Skip to content

Commit

Permalink
add merge and info stats support
Browse files Browse the repository at this point in the history
  • Loading branch information
ywangd committed Sep 26, 2023
1 parent e669041 commit 2873701
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,15 @@
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.notNullValue;

@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 1, numClientNodes = 0)
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE, supportsDedicatedMasters = false, numDataNodes = 0, numClientNodes = 0)
public class HttpStatsIT extends HttpSmokeTestCase {

@SuppressWarnings("unchecked")
public void testHttpStats() throws IOException {
// basic request
final RestClient restClient = getRestClient();
assertOK(restClient.performRequest(new Request("GET", "/")));
// request with body and URL placeholder
final Request searchRequest = new Request("GET", "*/_search");
searchRequest.setJsonEntity("""
{"query":{"match_all":{}}}""");
assertOK(restClient.performRequest(searchRequest));
// chunked response
assertOK(restClient.performRequest(new Request("GET", "/_cluster/state")));
// chunked text response
assertOK(restClient.performRequest(new Request("GET", "/_cat/nodes")));
public void testNodeHttpStats() throws IOException {
internalCluster().startNode();
performHttpRequests();

final Response response = restClient.performRequest(new Request("GET", "/_nodes/stats/http"));
final Response response = getRestClient().performRequest(new Request("GET", "/_nodes/stats/http"));
assertOK(response);

final Map<String, Object> responseMap = XContentHelper.convertToMap(
Expand All @@ -57,30 +47,64 @@ public void testHttpStats() throws IOException {

assertThat(nodesMap, aMapWithSize(1));
final String nodeId = nodesMap.keySet().iterator().next();
final XContentTestUtils.JsonMapView nodeView = new XContentTestUtils.JsonMapView((Map<String, Object>) nodesMap.get(nodeId));

assertHttpStats(new XContentTestUtils.JsonMapView((Map<String, Object>) nodesMap.get(nodeId)));
}

@SuppressWarnings("unchecked")
public void testClusterInfoHttpStats() throws IOException {
internalCluster().ensureAtLeastNumDataNodes(3);
performHttpRequests();

final Response response = getRestClient().performRequest(new Request("GET", "/_info/http"));
assertOK(response);

final Map<String, Object> responseMap = XContentHelper.convertToMap(
JsonXContent.jsonXContent,
response.getEntity().getContent(),
false
);
assertHttpStats(new XContentTestUtils.JsonMapView(responseMap));
}

private void performHttpRequests() throws IOException {
// basic request
final RestClient restClient = getRestClient();
assertOK(restClient.performRequest(new Request("GET", "/")));
// request with body and URL placeholder
final Request searchRequest = new Request("GET", "*/_search");
searchRequest.setJsonEntity("""
{"query":{"match_all":{}}}""");
assertOK(restClient.performRequest(searchRequest));
// chunked response
assertOK(restClient.performRequest(new Request("GET", "/_cluster/state")));
// chunked text response
assertOK(restClient.performRequest(new Request("GET", "/_cat/nodes")));
}

private void assertHttpStats(XContentTestUtils.JsonMapView jsonMapView) {
final List<String> routes = List.of("/", "/_cat/nodes", "/{index}/_search", "/_cluster/state");

for (var route : routes) {
assertThat(nodeView.get("http.routes." + route), notNullValue());
assertThat(nodeView.get("http.routes." + route + ".requests.count"), equalTo(1));
assertThat(nodeView.get("http.routes." + route + ".requests.total_size_in_bytes"), greaterThanOrEqualTo(0));
assertThat(nodeView.get("http.routes." + route + ".responses.count"), equalTo(1));
assertThat(nodeView.get("http.routes." + route + ".responses.total_size_in_bytes"), greaterThan(1));
assertThat(nodeView.get("http.routes." + route + ".requests.size_histogram"), hasSize(1));
assertThat(nodeView.get("http.routes." + route + ".requests.size_histogram.0.count"), equalTo(1));
assertThat(nodeView.get("http.routes." + route + ".requests.size_histogram.0.lt_bytes"), notNullValue());
assertThat(jsonMapView.get("http.routes." + route), notNullValue());
assertThat(jsonMapView.get("http.routes." + route + ".requests.count"), equalTo(1));
assertThat(jsonMapView.get("http.routes." + route + ".requests.total_size_in_bytes"), greaterThanOrEqualTo(0));
assertThat(jsonMapView.get("http.routes." + route + ".responses.count"), equalTo(1));
assertThat(jsonMapView.get("http.routes." + route + ".responses.total_size_in_bytes"), greaterThan(1));
assertThat(jsonMapView.get("http.routes." + route + ".requests.size_histogram"), hasSize(1));
assertThat(jsonMapView.get("http.routes." + route + ".requests.size_histogram.0.count"), equalTo(1));
assertThat(jsonMapView.get("http.routes." + route + ".requests.size_histogram.0.lt_bytes"), notNullValue());
if (route.equals("/{index}/_search")) {
assertThat(nodeView.get("http.routes." + route + ".requests.size_histogram.0.ge_bytes"), notNullValue());
assertThat(jsonMapView.get("http.routes." + route + ".requests.size_histogram.0.ge_bytes"), notNullValue());
}
assertThat(nodeView.get("http.routes." + route + ".responses.size_histogram"), hasSize(1));
assertThat(nodeView.get("http.routes." + route + ".responses.size_histogram.0.count"), equalTo(1));
assertThat(nodeView.get("http.routes." + route + ".responses.size_histogram.0.lt_bytes"), notNullValue());
assertThat(nodeView.get("http.routes." + route + ".responses.size_histogram.0.ge_bytes"), notNullValue());
assertThat(nodeView.get("http.routes." + route + ".responses.handling_time_histogram"), hasSize(1));
assertThat(nodeView.get("http.routes." + route + ".responses.handling_time_histogram.0.count"), equalTo(1));
assertThat(nodeView.get("http.routes." + route + ".responses.handling_time_histogram.0.lt_millis"), notNullValue());
assertThat(nodeView.get("http.routes." + route + ".responses.handling_time_histogram.0.ge_millis"), notNullValue());
assertThat(jsonMapView.get("http.routes." + route + ".responses.size_histogram"), hasSize(1));
assertThat(jsonMapView.get("http.routes." + route + ".responses.size_histogram.0.count"), equalTo(1));
assertThat(jsonMapView.get("http.routes." + route + ".responses.size_histogram.0.lt_bytes"), notNullValue());
assertThat(jsonMapView.get("http.routes." + route + ".responses.size_histogram.0.ge_bytes"), notNullValue());
assertThat(jsonMapView.get("http.routes." + route + ".responses.handling_time_histogram"), hasSize(1));
assertThat(jsonMapView.get("http.routes." + route + ".responses.handling_time_histogram.0.count"), equalTo(1));
assertThat(jsonMapView.get("http.routes." + route + ".responses.handling_time_histogram.0.lt_millis"), notNullValue());
assertThat(jsonMapView.get("http.routes." + route + ".responses.handling_time_histogram.0.ge_millis"), notNullValue());
}
}
}
23 changes: 23 additions & 0 deletions server/src/main/java/org/elasticsearch/http/HttpRouteStats.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.stream.IntStream;

public record HttpRouteStats(
long requestCount,
Expand Down Expand Up @@ -87,6 +88,28 @@ static void histogramToXContent(XContentBuilder builder, String fieldName, Strin
builder.endArray();
}

public static HttpRouteStats merge(HttpRouteStats first, HttpRouteStats second) {
assert first.requestSizeHistogram.length == second.requestSizeHistogram.length
&& first.responseSizeHistogram.length == second.responseSizeHistogram.length
&& first.responseTimeHistogram.length == second.responseTimeHistogram.length;

return new HttpRouteStats(
first.requestCount + second.requestCount,
first.totalRequestSize + second.totalRequestSize,
IntStream.range(0, first.requestSizeHistogram.length)
.mapToLong(i -> first.requestSizeHistogram[i] + second.requestSizeHistogram[i])
.toArray(),
first.responseCount + second.responseCount,
first.totalResponseSize + second.totalResponseSize,
IntStream.range(0, first.responseSizeHistogram.length)
.mapToLong(i -> first.responseSizeHistogram[i] + second.responseSizeHistogram[i])
.toArray(),
IntStream.range(0, first.responseTimeHistogram.length)
.mapToLong(i -> first.responseTimeHistogram[i] + second.responseTimeHistogram[i])
.toArray()
);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVLong(requestCount);
Expand Down
4 changes: 3 additions & 1 deletion server/src/main/java/org/elasticsearch/http/HttpStats.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.elasticsearch.TransportVersions.NODE_STATS_HTTP_ROUTE_STATS_ADDED;
Expand Down Expand Up @@ -72,7 +73,8 @@ public static HttpStats merge(HttpStats first, HttpStats second) {
first.serverOpen + second.serverOpen,
first.totalOpen + second.totalOpen,
Stream.concat(first.clientStats.stream(), second.clientStats.stream()).toList(),
Map.of() // TODO: merge
Stream.concat(first.httpRouteStats.entrySet().stream(), second.httpRouteStats.entrySet().stream())
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue, HttpRouteStats::merge))
);
}

Expand Down

0 comments on commit 2873701

Please sign in to comment.