package com.griddynamics.jagger.invoker.scenario; import com.griddynamics.jagger.engine.e1.Provider; import com.griddynamics.jagger.engine.e1.collector.MetricAggregatorProvider; import com.griddynamics.jagger.engine.e1.collector.MetricDescription; import com.griddynamics.jagger.engine.e1.collector.invocation.InvocationInfo; import com.griddynamics.jagger.engine.e1.collector.invocation.InvocationListener; import com.griddynamics.jagger.engine.e1.services.ServicesAware; import com.griddynamics.jagger.invoker.InvocationException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentSkipListSet; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.AVG_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.FAILS_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.MAX_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.MIN_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.PERCENTILE_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.STD_DEV_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.SUCCESS_AGGREGATOR; import static com.griddynamics.jagger.invoker.scenario.DefaultAggregatorsProvider.SUM_AGGREGATOR; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.ITERATIONS_SAMPLES; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.ITERATION_SAMPLES_ID; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.LATENCY_ID; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.LATENCY_SEC; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.SUCCESS_RATE; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.SUCCESS_RATE_ID; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.generateMetricDisplayName; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.generateMetricId; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.generateScenarioId; import static com.griddynamics.jagger.util.StandardMetricsNamesUtil.generateScenarioStepId; /** * Collects metrics during invocations of {@link JHttpUserScenarioInvoker} such as * Success rate, Iteration samples and Latency. * * @ingroup Main_Http_User_Scenario_group */ public class JHttpUserScenarioInvocationListener extends ServicesAware implements Provider<InvocationListener> { private final Set<String> createdMetrics = new ConcurrentSkipListSet<>(); private List<MetricAggregatorProvider> latencyAggregatorProviders = new ArrayList<>(); public JHttpUserScenarioInvocationListener() {} private JHttpUserScenarioInvocationListener(Builder builder) { this.latencyAggregatorProviders = newArrayList(builder.latencyAggregatorProviders); } public static Builder builder() {return new Builder();} public static class Builder { Set<MetricAggregatorProvider> latencyAggregatorProviders = new HashSet<>(); public Builder withLatencyAvgStddevAggregators() { this.latencyAggregatorProviders.addAll(newArrayList(STD_DEV_AGGREGATOR, AVG_AGGREGATOR)); return this; } public Builder withLatencyMinMaxAggregators() { this.latencyAggregatorProviders.addAll(newArrayList(MAX_AGGREGATOR, MIN_AGGREGATOR)); return this; } public Builder withLatencyPercentileAggregators(Double percentile, Double... percentiles) { this.latencyAggregatorProviders.add(PERCENTILE_AGGREGATOR(percentile)); Arrays.stream(percentiles).forEach(p -> this.latencyAggregatorProviders.add(PERCENTILE_AGGREGATOR(p))); return this; } public JHttpUserScenarioInvocationListener build() { return new JHttpUserScenarioInvocationListener(this); } } @Override protected void init() {} @Override public InvocationListener provide() { return new InvocationListener() { @Override public void onStart(InvocationInfo invocationInfo) { } @Override public void onSuccess(InvocationInfo invocationInfo) { if (invocationInfo.getResult() != null) { JHttpUserScenarioInvocationResult invocationResult = ((JHttpUserScenarioInvocationResult) invocationInfo.getResult()); List<JHttpUserScenarioStepInvocationResult> stepInvocationResults = invocationResult.getStepInvocationResults(); String scenarioId = generateScenarioId(invocationResult.getScenarioId()); // Create & save scenario metrics if (!createdMetrics.contains(scenarioId)) { createdMetrics.add(scenarioId); createScenarioMetricDescriptions(scenarioId, invocationResult.getScenarioDisplayName()); } getMetricService().saveValue(generateMetricId(scenarioId, ITERATION_SAMPLES_ID), 1); getMetricService().saveValue(generateMetricId(scenarioId, LATENCY_ID), invocationInfo.getDuration() / 1000.0); // ms -> s getMetricService().saveValue(generateMetricId(scenarioId, SUCCESS_RATE_ID), invocationResult.getSucceeded() ? 1 : 0); // Create & save step metrics Integer stepIndex = 1; // index 0 for scenario (not steps) metrics for (JHttpUserScenarioStepInvocationResult stepResult : stepInvocationResults) { String scenarioStepId = generateScenarioStepId(invocationResult.getScenarioId(), stepResult.getStepId(), stepIndex); if (!createdMetrics.contains(scenarioStepId)) { createdMetrics.add(scenarioStepId); createScenarioStepMetricDescriptions(scenarioStepId,String.format("%02d. %s ", stepIndex, stepResult.getStepDisplayName())); } getMetricService().saveValue(generateMetricId(scenarioStepId, LATENCY_ID), stepResult.getLatency().doubleValue() / 1000); // ms -> s getMetricService().saveValue(generateMetricId(scenarioStepId, SUCCESS_RATE_ID), stepResult.getSucceeded() ? 1 : 0); getMetricService().saveValue(generateMetricId(scenarioStepId, ITERATION_SAMPLES_ID), 1); stepIndex++; } } } private void createScenarioMetricDescriptions(String scenarioId, String scenarioDisplayName) { getMetricService().createMetric( new MetricDescription(generateMetricId(scenarioId, ITERATION_SAMPLES_ID)). displayName(generateMetricDisplayName(scenarioDisplayName, ITERATIONS_SAMPLES)). addAggregator(SUM_AGGREGATOR)); getMetricService().createMetric( new MetricDescription(generateMetricId(scenarioId, LATENCY_ID)). displayName(generateMetricDisplayName(scenarioDisplayName, LATENCY_SEC)). addAggregator(AVG_AGGREGATOR)); getMetricService().createMetric( new MetricDescription(generateMetricId(scenarioId, SUCCESS_RATE_ID)). displayName(generateMetricDisplayName(scenarioDisplayName, SUCCESS_RATE)). plotData(true). addAggregator(SUCCESS_AGGREGATOR). addAggregator(FAILS_AGGREGATOR)); } private void createScenarioStepMetricDescriptions(String scenarioStepId, String scenarioStepDisplayName) { MetricDescription metricDescription = new MetricDescription(generateMetricId(scenarioStepId,LATENCY_ID)). displayName(generateMetricDisplayName(scenarioStepDisplayName,LATENCY_SEC)) .plotData(true); if (latencyAggregatorProviders.isEmpty()) latencyAggregatorProviders.addAll(newHashSet(MAX_AGGREGATOR, MIN_AGGREGATOR, STD_DEV_AGGREGATOR, AVG_AGGREGATOR)); latencyAggregatorProviders.forEach(metricDescription::addAggregator); getMetricService().createMetric(metricDescription); getMetricService().createMetric( new MetricDescription(generateMetricId(scenarioStepId, ITERATION_SAMPLES_ID)). displayName(generateMetricDisplayName(scenarioStepDisplayName, ITERATIONS_SAMPLES)). addAggregator(SUM_AGGREGATOR)); getMetricService().createMetric( new MetricDescription(generateMetricId(scenarioStepId, SUCCESS_RATE_ID)). displayName(generateMetricDisplayName(scenarioStepDisplayName, SUCCESS_RATE)). plotData(true). addAggregator(SUCCESS_AGGREGATOR). addAggregator(FAILS_AGGREGATOR)); } @Override public void onFail(InvocationInfo invocationInfo, InvocationException e) { //TODO: JFG-1122 } @Override public void onError(InvocationInfo invocationInfo, Throwable error) { //TODO: JFG-1122 } }; } }