AnalyticsServiceElasticsearch extends AbstractAnalyticsService { @Override public Collection<NodeSummaryStatistics> getNodeSummaryStatistics(String tenantId, Criteria criteria) { String index = client.getIndex(tenantId); if (!refresh(index)) { return null; } List<NodeSummaryStatistics> stats = new ArrayList<>(); AvgBuilder actualBuilder = AggregationBuilders .avg("actual") .field(ElasticsearchUtil.ACTUAL_FIELD); AvgBuilder elapsedBuilder = AggregationBuilders .avg("elapsed") .field(ElasticsearchUtil.ELAPSED_FIELD); TermsBuilder operationsBuilder = AggregationBuilders .terms("operations") .field(ElasticsearchUtil.OPERATION_FIELD) .size(criteria.getMaxResponseSize()) .subAggregation(actualBuilder) .subAggregation(elapsedBuilder); MissingBuilder missingOperationBuilder = AggregationBuilders .missing("missingOperation") .field(ElasticsearchUtil.OPERATION_FIELD) .subAggregation(actualBuilder) .subAggregation(elapsedBuilder); TermsBuilder urisBuilder = AggregationBuilders .terms("uris") .field(ElasticsearchUtil.URI_FIELD) .size(criteria.getMaxResponseSize()) .subAggregation(operationsBuilder) .subAggregation(missingOperationBuilder); MissingBuilder missingUrisBuilder = AggregationBuilders .missing("missingUri") .field("uri") .subAggregation(operationsBuilder) .subAggregation(missingOperationBuilder); TermsBuilder componentsBuilder = AggregationBuilders .terms("components") .field("componentType") .size(criteria.getMaxResponseSize()) .subAggregation(urisBuilder) .subAggregation(missingUrisBuilder); TermsBuilder interactionUrisBuilder = AggregationBuilders .terms("uris") .field(ElasticsearchUtil.URI_FIELD) .size(criteria.getMaxResponseSize()) .subAggregation(actualBuilder) .subAggregation(elapsedBuilder); MissingBuilder missingComponentsBuilder = AggregationBuilders .missing("missingcomponent") .field("componentType") .subAggregation(interactionUrisBuilder); TermsBuilder nodesBuilder = AggregationBuilders .terms("types") .field(ElasticsearchUtil.TYPE_FIELD) .size(criteria.getMaxResponseSize()) .subAggregation(componentsBuilder) .subAggregation(missingComponentsBuilder); BoolQueryBuilder query = buildQuery(criteria, ElasticsearchUtil.TRANSACTION_FIELD, NodeDetails.class); SearchRequestBuilder request = getNodeDetailsRequest(index, criteria, query, 0) .addAggregation(nodesBuilder); SearchResponse response = getSearchResponse(request); Terms types = response.getAggregations().get("types"); for (Terms.Bucket typeBucket : types.getBuckets()) { Terms components = typeBucket.getAggregations().get("components"); for (Terms.Bucket componentBucket : components.getBuckets()) { Terms uris = componentBucket.getAggregations().get("uris"); for (Terms.Bucket uriBucket : uris.getBuckets()) { Terms operations = uriBucket.getAggregations().get("operations"); for (Terms.Bucket operationBucket : operations.getBuckets()) { Avg actual = operationBucket.getAggregations().get("actual"); Avg elapsed = operationBucket.getAggregations().get("elapsed"); NodeSummaryStatistics stat = new NodeSummaryStatistics(); stat.setComponentType(getComponentTypeForBucket(typeBucket, componentBucket)); stat.setUri(uriBucket.getKey()); stat.setOperation(operationBucket.getKey()); stat.setActual((long)actual.getValue()); stat.setElapsed((long)elapsed.getValue()); stat.setCount(operationBucket.getDocCount()); stats.add(stat); } Missing missingOp = uriBucket.getAggregations().get("missingOperation"); if (missingOp != null && missingOp.getDocCount() > 0) { Avg actual = missingOp.getAggregations().get("actual"); Avg elapsed = missingOp.getAggregations().get("elapsed"); if (!actual.getValueAsString().equals("NaN")) { NodeSummaryStatistics stat = new NodeSummaryStatistics(); stat.setComponentType(getComponentTypeForBucket(typeBucket, componentBucket)); stat.setUri(uriBucket.getKey()); stat.setActual((long)actual.getValue()); stat.setElapsed((long)elapsed.getValue()); stat.setCount(missingOp.getDocCount()); stats.add(stat); } } } Missing missingUri = componentBucket.getAggregations().get("missingUri"); if (missingUri.getDocCount() > 0) { Terms operations = missingUri.getAggregations().get("operations"); for (Terms.Bucket operationBucket : operations.getBuckets()) { Avg actual = operationBucket.getAggregations().get("actual"); Avg elapsed = operationBucket.getAggregations().get("elapsed"); NodeSummaryStatistics stat = new NodeSummaryStatistics(); stat.setComponentType(getComponentTypeForBucket(typeBucket, componentBucket)); stat.setOperation(operationBucket.getKey()); stat.setActual((long)actual.getValue()); stat.setElapsed((long)elapsed.getValue()); stat.setCount(operationBucket.getDocCount()); stats.add(stat); } } } Missing missingComponents = typeBucket.getAggregations().get("missingcomponent"); Terms uris = missingComponents.getAggregations().get("uris"); for (Terms.Bucket uriBucket : uris.getBuckets()) { Avg actual = uriBucket.getAggregations().get("actual"); Avg elapsed = uriBucket.getAggregations().get("elapsed"); NodeSummaryStatistics stat = new NodeSummaryStatistics(); stat.setComponentType(typeBucket.getKey()); stat.setUri(uriBucket.getKey()); stat.setActual((long)actual.getValue()); stat.setElapsed((long)elapsed.getValue()); stat.setCount(uriBucket.getDocCount()); stats.add(stat); } } return stats; }  @Override List<TransactionInfo> getTransactionInfo(String tenantId, Criteria criteria); @Override List<PropertyInfo> getPropertyInfo(String tenantId, Criteria criteria); @Override long getTraceCompletionCount(String tenantId, Criteria criteria); @Override long getTraceCompletionFaultCount(String tenantId, Criteria criteria); @Override List<CompletionTime> getTraceCompletions(String tenantId, Criteria criteria); @Override Percentiles getTraceCompletionPercentiles(String tenantId, Criteria criteria); @Override List<TimeseriesStatistics> getTraceCompletionTimeseriesStatistics(String tenantId, Criteria criteria, long interval); @Override List<Cardinality> getTraceCompletionFaultDetails(String tenantId, Criteria criteria); @Override List<Cardinality> getTraceCompletionPropertyDetails(String tenantId, Criteria criteria, String property); @Override List<NodeTimeseriesStatistics> getNodeTimeseriesStatistics(String tenantId, Criteria criteria, long interval); @Override Collection<NodeSummaryStatistics> getNodeSummaryStatistics(String tenantId, Criteria criteria); @Override List<TimeseriesStatistics> getEndpointResponseTimeseriesStatistics(String tenantId, Criteria criteria, long interval); @Override Set<String> getHostNames(String tenantId, Criteria criteria); @Override void storeCommunicationDetails(String tenantId, List<CommunicationDetails> communicationDetails); @Override void storeNodeDetails(String tenantId, List<NodeDetails> nodeDetails); @Override void storeTraceCompletions(String tenantId, List<CompletionTime> completionTimes); @Override void clear(String tenantId);  }
@Test public void testGetNodeSummaryStatistics() throws StoreException { NodeDetails ct1_0 = new NodeDetails(); ct1_0.setTransaction(TXN); ct1_0.setTimestamp(1500); ct1_0.setActual(100); ct1_0.setElapsed(200); ct1_0.setType(NodeType.Consumer); ct1_0.setUri("hello"); NodeDetails ct1_1 = new NodeDetails(); ct1_1.setTransaction(TXN); ct1_1.setTimestamp(1500); ct1_1.setActual(100); ct1_1.setElapsed(200); ct1_1.setType(NodeType.Component); ct1_1.setComponentType(Constants.COMPONENT_DATABASE); ct1_1.setUri("jdbc"); NodeDetails ct1_2 = new NodeDetails(); ct1_2.setTransaction(TXN); ct1_2.setTimestamp(1600); ct1_2.setActual(300); ct1_2.setElapsed(600); ct1_2.setType(NodeType.Component); ct1_2.setComponentType(Constants.COMPONENT_DATABASE); ct1_2.setUri("jdbc"); NodeDetails ct1_3 = new NodeDetails(); ct1_3.setTransaction(TXN); ct1_3.setTimestamp(1700); ct1_3.setActual(150); ct1_3.setElapsed(300); ct1_3.setType(NodeType.Component); ct1_3.setComponentType(Constants.COMPONENT_EJB); ct1_3.setUri("BookingService"); ct1_3.setOperation("createBooking"); NodeDetails ct1_4 = new NodeDetails(); ct1_4.setTransaction(TXN); ct1_4.setTimestamp(1800); ct1_4.setActual(170); ct1_4.setElapsed(200); ct1_4.setType(NodeType.Component); ct1_4.setComponentType("OtherComponent"); ct1_4.setOperation("onlyOp"); analytics.storeNodeDetails(null, Arrays.asList(ct1_0, ct1_1, ct1_2, ct1_3, ct1_4)); Criteria criteria = new Criteria(); criteria.setStartTime(1).setEndTime(10000); Wait.until(() -> analytics.getNodeSummaryStatistics(null, criteria).size() == 4); Collection<NodeSummaryStatistics> stats = analytics.getNodeSummaryStatistics(null, criteria); assertNotNull(stats); assertEquals(4, stats.size()); Map<String,NodeSummaryStatistics> results= stats.stream().collect(Collectors.toMap(x -> x.getComponentType(), x -> x)); assertEquals("jdbc", results.get(Constants.COMPONENT_DATABASE).getUri()); assertNull(results.get(Constants.COMPONENT_DATABASE).getOperation()); assertEquals(2, results.get(Constants.COMPONENT_DATABASE).getCount()); assertTrue(results.get(Constants.COMPONENT_DATABASE).getActual() == 200.0); assertTrue(results.get(Constants.COMPONENT_DATABASE).getElapsed() == 400.0); assertEquals("BookingService", results.get(Constants.COMPONENT_EJB).getUri()); assertEquals("createBooking", results.get(Constants.COMPONENT_EJB).getOperation()); assertEquals(1, results.get(Constants.COMPONENT_EJB).getCount()); assertTrue(results.get(Constants.COMPONENT_EJB).getActual() == 150.0); assertTrue(results.get(Constants.COMPONENT_EJB).getElapsed() == 300.0); assertEquals("hello", results.get("Consumer").getUri()); assertNull(results.get("Consumer").getOperation()); assertEquals(1, results.get("Consumer").getCount()); assertTrue(results.get("Consumer").getActual() == 100.0); assertTrue(results.get("Consumer").getElapsed() == 200.0); assertEquals("onlyOp", results.get("OtherComponent").getOperation()); assertEquals(1, results.get("OtherComponent").getCount()); assertTrue(results.get("OtherComponent").getActual() == 170.0); assertTrue(results.get("OtherComponent").getElapsed() == 200.0); }