Include details in ElasticsearchRestHealthIndicator
This commit adds more information to the ElasticSearch REST health indicator. When the ES instance responds with an error HTTP status, the health details now include the actual status code and reason phrase. When the ES instance returns a HTTP 200 response, the entire response map is used as health details. See gh-15366
This commit is contained in:
committed by
Brian Clozel
parent
31284cd3df
commit
1ec2bbf54f
@@ -18,8 +18,10 @@ package org.springframework.boot.actuate.elasticsearch;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
@@ -36,6 +38,7 @@ import org.springframework.util.StreamUtils;
|
||||
*
|
||||
* @author Artsiom Yudovin
|
||||
* @author Brian Clozel
|
||||
* @author Filip Hrisafov
|
||||
* @since 2.1.1
|
||||
*/
|
||||
public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
|
||||
@@ -56,8 +59,11 @@ public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
Response response = this.client
|
||||
.performRequest(new Request("GET", "/_cluster/health/"));
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||
StatusLine statusLine = response.getStatusLine();
|
||||
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
|
||||
builder.down();
|
||||
builder.withDetail("statusCode", statusLine.getStatusCode());
|
||||
builder.withDetail("reasonPhrase", statusLine.getReasonPhrase());
|
||||
return;
|
||||
}
|
||||
try (InputStream inputStream = response.getEntity().getContent()) {
|
||||
@@ -67,12 +73,16 @@ public class ElasticsearchRestHealthIndicator extends AbstractHealthIndicator {
|
||||
}
|
||||
|
||||
private void doHealthCheck(Health.Builder builder, String json) {
|
||||
String status = (String) this.jsonParser.parseMap(json).get("status");
|
||||
Map<String, Object> response = this.jsonParser.parseMap(json);
|
||||
String status = (String) response.get("status");
|
||||
if (RED_STATUS.equals(status)) {
|
||||
builder.outOfService();
|
||||
return;
|
||||
}
|
||||
builder.up();
|
||||
else {
|
||||
builder.up();
|
||||
}
|
||||
|
||||
builder.withDetails(response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,9 +26,11 @@ import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
@@ -37,6 +39,7 @@ import static org.mockito.BDDMockito.when;
|
||||
* Tests for {@link ElasticsearchRestHealthIndicator}.
|
||||
*
|
||||
* @author Artsiom Yudovin
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class ElasticsearchRestHealthIndicatorTest {
|
||||
|
||||
@@ -59,8 +62,48 @@ public class ElasticsearchRestHealthIndicatorTest {
|
||||
when(response.getEntity()).thenReturn(httpEntity);
|
||||
when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
|
||||
|
||||
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus())
|
||||
.isEqualTo(Status.UP);
|
||||
Health health = this.elasticsearchRestHealthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
assertThat(health.getDetails()).contains(entry("cluster_name", "elasticsearch"),
|
||||
entry("status", "green"), entry("timed_out", false),
|
||||
entry("number_of_nodes", 1), entry("number_of_data_nodes", 1),
|
||||
entry("active_primary_shards", 0), entry("active_shards", 0),
|
||||
entry("relocating_shards", 0), entry("initializing_shards", 0),
|
||||
entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
|
||||
entry("number_of_pending_tasks", 0),
|
||||
entry("number_of_in_flight_fetch", 0),
|
||||
entry("task_max_waiting_in_queue_millis", 0),
|
||||
entry("active_shards_percent_as_number", 100.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void elasticsearchWithYellowStatusIsUp() throws IOException {
|
||||
BasicHttpEntity httpEntity = new BasicHttpEntity();
|
||||
httpEntity.setContent(
|
||||
new ByteArrayInputStream(createJsonResult(200, "yellow").getBytes()));
|
||||
|
||||
Response response = mock(Response.class);
|
||||
StatusLine statusLine = mock(StatusLine.class);
|
||||
|
||||
when(statusLine.getStatusCode()).thenReturn(200);
|
||||
when(response.getStatusLine()).thenReturn(statusLine);
|
||||
when(response.getEntity()).thenReturn(httpEntity);
|
||||
when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
|
||||
|
||||
Health health = this.elasticsearchRestHealthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
|
||||
assertThat(health.getDetails()).contains(entry("cluster_name", "elasticsearch"),
|
||||
entry("status", "yellow"), entry("timed_out", false),
|
||||
entry("number_of_nodes", 1), entry("number_of_data_nodes", 1),
|
||||
entry("active_primary_shards", 0), entry("active_shards", 0),
|
||||
entry("relocating_shards", 0), entry("initializing_shards", 0),
|
||||
entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
|
||||
entry("number_of_pending_tasks", 0),
|
||||
entry("number_of_in_flight_fetch", 0),
|
||||
entry("task_max_waiting_in_queue_millis", 0),
|
||||
entry("active_shards_percent_as_number", 100.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -68,8 +111,10 @@ public class ElasticsearchRestHealthIndicatorTest {
|
||||
when(this.restClient.performRequest(any(Request.class)))
|
||||
.thenThrow(new IOException("Couldn't connect"));
|
||||
|
||||
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus())
|
||||
.isEqualTo(Status.DOWN);
|
||||
Health health = this.elasticsearchRestHealthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(health.getDetails())
|
||||
.contains(entry("error", "java.io.IOException: Couldn't connect"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,11 +124,14 @@ public class ElasticsearchRestHealthIndicatorTest {
|
||||
StatusLine statusLine = mock(StatusLine.class);
|
||||
|
||||
when(statusLine.getStatusCode()).thenReturn(500);
|
||||
when(statusLine.getReasonPhrase()).thenReturn("Internal server error");
|
||||
when(response.getStatusLine()).thenReturn(statusLine);
|
||||
when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
|
||||
|
||||
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus())
|
||||
.isEqualTo(Status.DOWN);
|
||||
Health health = this.elasticsearchRestHealthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(health.getDetails()).contains(entry("statusCode", 500),
|
||||
entry("reasonPhrase", "Internal server error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,8 +148,18 @@ public class ElasticsearchRestHealthIndicatorTest {
|
||||
when(response.getEntity()).thenReturn(httpEntity);
|
||||
when(this.restClient.performRequest(any(Request.class))).thenReturn(response);
|
||||
|
||||
assertThat(this.elasticsearchRestHealthIndicator.health().getStatus())
|
||||
.isEqualTo(Status.OUT_OF_SERVICE);
|
||||
Health health = this.elasticsearchRestHealthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);
|
||||
assertThat(health.getDetails()).contains(entry("cluster_name", "elasticsearch"),
|
||||
entry("status", "red"), entry("timed_out", false),
|
||||
entry("number_of_nodes", 1), entry("number_of_data_nodes", 1),
|
||||
entry("active_primary_shards", 0), entry("active_shards", 0),
|
||||
entry("relocating_shards", 0), entry("initializing_shards", 0),
|
||||
entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
|
||||
entry("number_of_pending_tasks", 0),
|
||||
entry("number_of_in_flight_fetch", 0),
|
||||
entry("task_max_waiting_in_queue_millis", 0),
|
||||
entry("active_shards_percent_as_number", 100.0));
|
||||
}
|
||||
|
||||
private String createJsonResult(int responseCode, String status) {
|
||||
|
||||
Reference in New Issue
Block a user