You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2019/10/03 18:52:25 UTC
[jmeter] branch master updated: Added simple tests
InfluxdbBackendListenerClientSpec (#509)
This is an automated email from the ASF dual-hosted git repository.
pmouawad pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git
The following commit(s) were added to refs/heads/master by this push:
new 9143129 Added simple tests InfluxdbBackendListenerClientSpec (#509)
9143129 is described below
commit 91431299da490891a338f4f40326c8645f570c39
Author: Graham Russell <gr...@ham1.co.uk>
AuthorDate: Thu Oct 3 19:52:21 2019 +0100
Added simple tests InfluxdbBackendListenerClientSpec (#509)
* Added simple tests InfluxdbBackendListenerClientSpec
* Formatting/whitespace/JavaDoc,simplified code, reduced visibility,
extracted methods and added guard clauses
---
.../visualizers/backend/BackendListener.java | 73 ++---
.../backend/BackendListenerContext.java | 120 +++-----
.../influxdb/InfluxdbBackendListenerClient.java | 336 +++++++++++----------
.../InfluxdbBackendListenerClientSpec.groovy | 50 +++
4 files changed, 297 insertions(+), 282 deletions(-)
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java
index ab703d3..1b4c29f 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListener.java
@@ -45,11 +45,12 @@ import org.slf4j.LoggerFactory;
/**
* Async Listener that delegates SampleResult handling to implementations of {@link BackendListenerClient}
+ *
* @since 2.13
*/
-public class BackendListener extends AbstractTestElement
- implements Backend, Serializable, SampleListener,
- TestStateListener, NoThreadClone, Remoteable {
+public class BackendListener
+ extends AbstractTestElement
+ implements Backend, Serializable, SampleListener, TestStateListener, NoThreadClone, Remoteable {
private static final class ListenerClientData {
private BackendListenerClient client;
@@ -70,9 +71,7 @@ public class BackendListener extends AbstractTestElement
*/
public static final String CLASSNAME = "classname";
- /**
- * Queue size
- */
+ /** Queue size */
public static final String QUEUE_SIZE = "QUEUE_SIZE";
/**
@@ -106,12 +105,9 @@ public class BackendListener extends AbstractTestElement
// Name of the test element. Set up by testStarted().
private transient String myName;
- // Holds listenerClientData for this test element
private transient ListenerClientData listenerClientData;
- /**
- * Create a BackendListener.
- */
+ /** Create a BackendListener. */
public BackendListener() {
setArguments(new Arguments());
}
@@ -146,10 +142,6 @@ public class BackendListener extends AbstractTestElement
return Thread.currentThread().getName() + "@" + Integer.toHexString(hashCode()) + "-" + getName();
}
-
- /* (non-Javadoc)
- * @see org.apache.jmeter.samplers.SampleListener#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
- */
@Override
public void sampleOccurred(SampleEvent event) {
Arguments args = getArguments();
@@ -163,12 +155,12 @@ public class BackendListener extends AbstractTestElement
return;
}
try {
- if (!listenerClientData.queue.offer(sr)){ // we failed to add the element first time
+ if (!listenerClientData.queue.offer(sr)) { // we failed to add the element first time
listenerClientData.queueWaits.add(1L);
long t1 = System.nanoTime();
listenerClientData.queue.put(sr);
long t2 = System.nanoTime();
- listenerClientData.queueWaitTime.add(t2-t1);
+ listenerClientData.queueWaitTime.add(t2 - t1);
}
} catch (Exception err) {
log.error("sampleOccurred, failed to queue the sample", err);
@@ -183,7 +175,8 @@ public class BackendListener extends AbstractTestElement
private final ListenerClientData listenerClientData;
private final BackendListenerContext context;
private final BackendListenerClient backendListenerClient;
- private Worker(BackendListenerClient backendListenerClient, Arguments arguments, ListenerClientData listenerClientData){
+
+ private Worker(BackendListenerClient backendListenerClient, Arguments arguments, ListenerClientData listenerClientData) {
this.listenerClientData = listenerClientData;
// Allow BackendListenerClient implementations to get access to test element name
arguments.addArgument(TestElement.NAME, getName());
@@ -213,7 +206,7 @@ public class BackendListener extends AbstractTestElement
}
// try to process as many as possible
// The == comparison is not a mistake
- while (!(endOfLoop = sampleResult == FINAL_SAMPLE_RESULT) && sampleResult != null ) {
+ while (!(endOfLoop = sampleResult == FINAL_SAMPLE_RESULT) && sampleResult != null) {
sampleResults.add(sampleResult);
if (isDebugEnabled) {
log.debug("Thread: {} polling from queue: {}", Thread.currentThread().getName(),
@@ -231,7 +224,7 @@ public class BackendListener extends AbstractTestElement
sampleResult == null);
}
sendToListener(backendListenerClient, context, sampleResults);
- if(!endOfLoop) {
+ if (!endOfLoop) {
LockSupport.parkNanos(100);
}
}
@@ -249,14 +242,15 @@ public class BackendListener extends AbstractTestElement
/**
* Send sampleResults to {@link BackendListenerClient}
+ *
* @param backendListenerClient {@link BackendListenerClient}
- * @param context {@link BackendListenerContext}
- * @param sampleResults List of {@link SampleResult}
+ * @param context {@link BackendListenerContext}
+ * @param sampleResults List of {@link SampleResult}
*/
- static void sendToListener(
- final BackendListenerClient backendListenerClient,
- final BackendListenerContext context,
- final List<SampleResult> sampleResults) {
+ private static void sendToListener(
+ BackendListenerClient backendListenerClient,
+ BackendListenerContext context,
+ List<SampleResult> sampleResults) {
if (!sampleResults.isEmpty()) {
backendListenerClient.handleSampleResults(sampleResults, context);
sampleResults.clear();
@@ -265,10 +259,11 @@ public class BackendListener extends AbstractTestElement
/**
* Returns reference to {@link BackendListener}
+ *
* @param clientClass {@link BackendListenerClient} client class
* @return BackendListenerClient reference.
*/
- static BackendListenerClient createBackendListenerClientImpl(Class<?> clientClass) {
+ private static BackendListenerClient createBackendListenerClientImpl(Class<?> clientClass) {
if (clientClass == null) { // failed to initialise the class
return new ErrorBackendListenerClient();
}
@@ -304,12 +299,12 @@ public class BackendListener extends AbstractTestElement
synchronized (LOCK) {
myName = getName();
listenerClientData = queuesByTestElementName.get(myName);
- if (listenerClientData == null){
+ if (listenerClientData == null) {
// We need to do this to ensure in Distributed testing
// that only 1 instance of BackendListenerClient is used
clientClass = initClass(); // may be null
BackendListenerClient backendListenerClient = createBackendListenerClientImpl(clientClass);
- BackendListenerContext context = new BackendListenerContext((Arguments)getArguments().clone());
+ BackendListenerContext context = new BackendListenerContext((Arguments) getArguments().clone());
listenerClientData = new ListenerClientData();
listenerClientData.queue = new ArrayBlockingQueue<>(queueSize);
@@ -330,7 +325,7 @@ public class BackendListener extends AbstractTestElement
try {
backendListenerClient.setupTest(context);
} catch (Exception e) {
- throw new java.lang.IllegalStateException("Failed calling setupTest", e);
+ throw new IllegalStateException("Failed calling setupTest", e);
}
queuesByTestElementName.put(myName, listenerClientData);
}
@@ -353,9 +348,9 @@ public class BackendListener extends AbstractTestElement
if (log.isDebugEnabled()) {
log.debug("testEnded called on instance {}#{}", myName, listenerClientDataForName.instanceCount);
}
- if(listenerClientDataForName != null) {
+ if (listenerClientDataForName != null) {
listenerClientDataForName.instanceCount--;
- if (listenerClientDataForName.instanceCount > 0){
+ if (listenerClientDataForName.instanceCount > 0) {
// Not the last instance of myName
return;
} else {
@@ -368,7 +363,7 @@ public class BackendListener extends AbstractTestElement
try {
listenerClientData.queue.put(FINAL_SAMPLE_RESULT);
} catch (Exception ex) {
- log.warn("testEnded() with exception: {}", ex, ex);
+ log.warn("testEnded() with exception: {}", ex.getMessage(), ex);
}
if (listenerClientData.queueWaits.longValue() > 0) {
log.warn(
@@ -380,7 +375,7 @@ public class BackendListener extends AbstractTestElement
BackendListenerContext context = new BackendListenerContext(getArguments());
listenerClientData.client.teardownTest(context);
} catch (Exception e) {
- throw new java.lang.IllegalStateException("Failed calling teardownTest", e);
+ throw new IllegalStateException("Failed calling teardownTest", e);
}
}
@@ -409,17 +404,11 @@ public class BackendListener extends AbstractTestElement
}
}
- /* (non-Javadoc)
- * @see org.apache.jmeter.samplers.SampleListener#sampleStarted(org.apache.jmeter.samplers.SampleEvent)
- */
@Override
public void sampleStarted(SampleEvent e) {
// NOOP
}
- /* (non-Javadoc)
- * @see org.apache.jmeter.samplers.SampleListener#sampleStopped(org.apache.jmeter.samplers.SampleEvent)
- */
@Override
public void sampleStopped(SampleEvent e) {
// NOOP
@@ -429,8 +418,7 @@ public class BackendListener extends AbstractTestElement
* Set the arguments (parameters) for the BackendListenerClient to be executed
* with.
*
- * @param args
- * the new arguments. These replace any existing arguments.
+ * @param args the new arguments. These replace any existing arguments.
*/
public void setArguments(Arguments args) {
// Bug 59173 - don't save new default argument
@@ -452,8 +440,7 @@ public class BackendListener extends AbstractTestElement
/**
* Sets the Classname of the BackendListenerClient object
*
- * @param classname
- * the new Classname value
+ * @param classname the new Classname value
*/
public void setClassname(String classname) {
setProperty(CLASSNAME, classname);
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
index aa3803d..ae1438c 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/BackendListenerContext.java
@@ -29,41 +29,37 @@ import org.slf4j.LoggerFactory;
* BackendListenerContext is used to provide context information to a
* BackendListenerClient implementation. This currently consists of the
* initialization parameters which were specified in the GUI.
+ * <p>
+ * All of the methods in this class are currently read-only. If update methods
+ * are included in the future, they should be defined so that a single instance
+ * of {@link BackendListenerContext} can be associated with each thread.
+ * Therefore, no synchronization should be needed. The same instance should
+ * be used for all calls to setupTest, runTest, and teardownTest.
+ *
* @since 2.13
*/
public class BackendListenerContext {
- /*
- * Implementation notes:
- *
- * All of the methods in this class are currently read-only. If update
- * methods are included in the future, they should be defined so that a
- * single instance of BackendListenerContext can be associated with each thread.
- * Therefore, no synchronization should be needed. The same instance should
- * be used for the call to setupTest, all calls to runTest, and the call to
- * teardownTest.
- */
private static final Logger log = LoggerFactory.getLogger(BackendListenerContext.class);
- /**
- * Map containing the initialization parameters for the BackendListenerClient.
- */
+ /** The initialization parameters. */
private final Map<String, String> params;
- /**
- * @param args
- * the initialization parameters.
- */
+ /** @param args the initialization parameters. */
public BackendListenerContext(Arguments args) {
this.params = args.getArgumentsAsMap();
}
+ /** @param params the initialization parameters. */
+ public BackendListenerContext(Map<String, String> params) {
+ this.params = params;
+ }
+
/**
* Determine whether or not a value has been specified for the parameter
* with this name.
*
- * @param name
- * the name of the parameter to test
+ * @param name the name of the parameter to test
* @return true if the parameter value has been specified, false otherwise.
*/
public boolean containsParameter(String name) {
@@ -71,11 +67,10 @@ public class BackendListenerContext {
}
/**
- * Get an iterator of the parameter names. Each entry in the Iterator is a
- * String.
+ * Get an iterator of the parameter names.
*
- * @return an Iterator of Strings listing the names of the parameters which
- * have been specified for this test.
+ * @return an Iterator of Strings of the names of the parameters which
+ * have been specified for this test.
*/
public Iterator<String> getParameterNamesIterator() {
return params.keySet().iterator();
@@ -85,10 +80,8 @@ public class BackendListenerContext {
* Get the value of a specific parameter as a String, or null if the value
* was not specified.
*
- * @param name
- * the name of the parameter whose value should be retrieved
- * @return the value of the parameter, or null if the value was not
- * specified
+ * @param name the name of the parameter whose value should be retrieved
+ * @return the value of the parameter, or null if the value was not specified
*/
public String getParameter(String name) {
return getParameter(name, null);
@@ -98,13 +91,11 @@ public class BackendListenerContext {
* Get the value of a specified parameter as a String, or return the
* specified default value if the value was not specified.
*
- * @param name
- * the name of the parameter whose value should be retrieved
- * @param defaultValue
- * the default value to return if the value of this parameter was
- * not specified
+ * @param name the name of the parameter whose value should be retrieved
+ * @param defaultValue the default value to return if the value of this parameter was
+ * not specified
* @return the value of the parameter, or the default value if the parameter
- * was not specified
+ * was not specified
*/
public String getParameter(String name, String defaultValue) {
if (params == null || !params.containsKey(name)) {
@@ -116,21 +107,14 @@ public class BackendListenerContext {
/**
* Get the value of a specified parameter as an integer. An exception will
* be thrown if the parameter is not specified or if it is not an integer.
- * The value may be specified in decimal, hexadecimal, or octal, as defined
- * by Integer.decode().
*
- * @param name
- * the name of the parameter whose value should be retrieved
+ * @param name the name of the parameter whose value should be retrieved
* @return the value of the parameter
- *
- * @throws IllegalArgumentException
- * if no value defined
- * @throws NumberFormatException
- * if the parameter is not specified or is not an integer
- *
- * @see java.lang.Integer#decode(java.lang.String)
+ * @throws IllegalArgumentException if no value defined
+ * @throws NumberFormatException if the parameter is not specified or is not an integer
+ * @see Integer#parseInt(String)
*/
- public int getIntParameter(String name) {
+ public int getIntParameter(String name) {
if (params == null || !params.containsKey(name)) {
throw new IllegalArgumentException("No value for parameter named '" + name + "'.");
}
@@ -141,19 +125,14 @@ public class BackendListenerContext {
/**
* Get the value of a specified parameter as an integer, or return the
* specified default value if the value was not specified or is not an
- * integer. A warning will be logged if the value is not an integer. The
- * value may be specified in decimal, hexadecimal, or octal, as defined by
- * Integer.decode().
+ * integer. A warning will be logged if the value is not an integer.
*
- * @param name
- * the name of the parameter whose value should be retrieved
- * @param defaultValue
- * the default value to return if the value of this parameter was
- * not specified
+ * @param name the name of the parameter whose value should be retrieved
+ * @param defaultValue the default value to return if the value of this parameter was
+ * not specified
* @return the value of the parameter, or the default value if the parameter
- * was not specified
- *
- * @see java.lang.Integer#decode(java.lang.String)
+ * was not specified
+ * @see Integer#parseInt(String)
*/
public int getIntParameter(String name, int defaultValue) {
if (params == null || !params.containsKey(name)) {
@@ -172,18 +151,12 @@ public class BackendListenerContext {
/**
* Get the value of a specified parameter as a long. An exception will be
- * thrown if the parameter is not specified or if it is not a long. The
- * value may be specified in decimal, hexadecimal, or octal, as defined by
- * Long.decode().
+ * thrown if the parameter is not specified or if it is not a long.
*
- * @param name
- * the name of the parameter whose value should be retrieved
+ * @param name the name of the parameter whose value should be retrieved
* @return the value of the parameter
- *
- * @throws NumberFormatException
- * if the parameter is not specified or is not a long
- *
- * @see Long#decode(String)
+ * @throws NumberFormatException if the parameter is not specified or is not a long
+ * @see Long#parseLong(String)
*/
public long getLongParameter(String name) {
if (params == null || !params.containsKey(name)) {
@@ -199,14 +172,11 @@ public class BackendListenerContext {
* will be logged if the value is not a long. The value may be specified in
* decimal, hexadecimal, or octal, as defined by Long.decode().
*
- * @param name
- * the name of the parameter whose value should be retrieved
- * @param defaultValue
- * the default value to return if the value of this parameter was
- * not specified
+ * @param name the name of the parameter whose value should be retrieved
+ * @param defaultValue the default value to return if the value of this parameter was
+ * not specified
* @return the value of the parameter, or the default value if the parameter
- * was not specified
- *
+ * was not specified
* @see Long#decode(String)
*/
public long getLongParameter(String name, long defaultValue) {
@@ -224,9 +194,9 @@ public class BackendListenerContext {
}
/**
- * @param name Parameter name
+ * @param name Parameter name
* @param defaultValue Default value used if name is not in params
- * @return boolean
+ * @return boolean the value of the parameter in the map, or the default value
*/
public boolean getBooleanParameter(String name, boolean defaultValue) {
if (params == null || !params.containsKey(name)) {
diff --git a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java
index 212fe1b..ace1a22 100644
--- a/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java
+++ b/src/components/src/main/java/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClient.java
@@ -38,6 +38,7 @@ import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
+import org.apache.jmeter.visualizers.backend.ErrorMetric;
import org.apache.jmeter.visualizers.backend.SamplerMetric;
import org.apache.jmeter.visualizers.backend.UserMetric;
import org.slf4j.Logger;
@@ -46,6 +47,7 @@ import org.slf4j.LoggerFactory;
/**
* Implementation of {@link AbstractBackendListenerClient} to write in an InfluxDB using
* custom schema
+ *
* @since 3.2
*/
public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient implements Runnable {
@@ -96,6 +98,7 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
private static final String SEPARATOR = ";"; //$NON-NLS-1$
private static final Object LOCK = new Object();
private static final Map<String, String> DEFAULT_ARGS = new LinkedHashMap<>();
+
static {
DEFAULT_ARGS.put("influxdbMetricsSender", HttpMetricsSender.class.getName());
DEFAULT_ARGS.put("influxdbUrl", "http://host_to_change:8086/write?db=jmeter");
@@ -117,8 +120,7 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
private Map<String, Float> allPercentiles;
private String testTitle;
private String testTags;
- // Name of the application tested
- private String application = "";
+ private String applicationName = "";
private String userTag = "";
private InfluxdbMetricsSender influxdbMetricsManager;
@@ -134,13 +136,10 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
sendMetrics();
}
- /**
- * Send metrics
- */
- protected void sendMetrics() {
+ private void sendMetrics() {
synchronized (LOCK) {
- for (Map.Entry<String, SamplerMetric> entry : getMetricsInfluxdbPerSampler().entrySet()) {
+ for (Map.Entry<String, SamplerMetric> entry : metricsPerSampler.entrySet()) {
SamplerMetric metric = entry.getValue();
if (entry.getKey().equals(CUMULATED_METRICS)) {
addCumulatedMetrics(metric);
@@ -155,7 +154,7 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
UserMetric userMetrics = getUserMetrics();
// For JMETER context
StringBuilder tag = new StringBuilder(80);
- tag.append(TAG_APPLICATION).append(application);
+ tag.append(TAG_APPLICATION).append(applicationName);
tag.append(TAG_TRANSACTION).append("internal");
tag.append(userTag);
StringBuilder field = new StringBuilder(80);
@@ -172,124 +171,120 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
@FunctionalInterface
private interface PercentileProvider {
- public double getPercentileValue(double percentile);
+ double getPercentileValue(double percentile);
}
- /**
- * Add request metrics to metrics manager.
- *
- * @param metric
- * {@link SamplerMetric}
- */
+
private void addMetrics(String transaction, SamplerMetric metric) {
- // FOR ALL STATUS
- addMetric(transaction, metric.getTotal(), metric.getSentBytes(), metric.getReceivedBytes(), TAG_ALL, metric.getAllMean(), metric.getAllMinTime(),
+ // ALL
+ addMetric(transaction, metric.getTotal(), metric.getSentBytes(), metric.getReceivedBytes(),
+ TAG_ALL, metric.getAllMean(), metric.getAllMinTime(),
metric.getAllMaxTime(), allPercentiles.values(), metric::getAllPercentile);
- // FOR OK STATUS
- addMetric(transaction, metric.getSuccesses(), null, null, TAG_OK, metric.getOkMean(), metric.getOkMinTime(),
+ // OK
+ addMetric(transaction, metric.getSuccesses(), null, null,
+ TAG_OK, metric.getOkMean(), metric.getOkMinTime(),
metric.getOkMaxTime(), okPercentiles.values(), metric::getOkPercentile);
- // FOR KO STATUS
- addMetric(transaction, metric.getFailures(), null, null, TAG_KO, metric.getKoMean(), metric.getKoMinTime(),
+ // KO
+ addMetric(transaction, metric.getFailures(), null, null,
+ TAG_KO, metric.getKoMean(), metric.getKoMinTime(),
metric.getKoMaxTime(), koPercentiles.values(), metric::getKoPercentile);
- metric.getErrors().forEach((error, count) -> addErrorMetric(transaction, error.getResponseCode(),
- error.getResponseMessage(), count));
+ metric.getErrors().forEach((err, count) -> addErrorMetric(transaction, err, count));
}
- private void addErrorMetric(String transaction, String responseCode, String responseMessage, long count) {
- if (count > 0) {
- StringBuilder tag = new StringBuilder(70);
- tag.append(TAG_APPLICATION).append(application);
- tag.append(TAG_TRANSACTION).append(transaction);
- tag.append(TAG_RESPONSE_CODE).append(AbstractInfluxdbMetricsSender.tagToStringValue(responseCode));
- tag.append(TAG_RESPONSE_MESSAGE).append(AbstractInfluxdbMetricsSender.tagToStringValue(responseMessage));
- tag.append(userTag);
-
- StringBuilder field = new StringBuilder(30);
- field.append(METRIC_COUNT).append(count);
- influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
+ private void addErrorMetric(String transaction, ErrorMetric err, long count) {
+ if (count <= 0) {
+ return;
}
+ StringBuilder tag = new StringBuilder(70);
+ tag.append(TAG_APPLICATION).append(applicationName);
+ tag.append(TAG_TRANSACTION).append(transaction);
+ tag.append(TAG_RESPONSE_CODE).append(AbstractInfluxdbMetricsSender.tagToStringValue(err.getResponseCode()));
+ tag.append(TAG_RESPONSE_MESSAGE).append(AbstractInfluxdbMetricsSender.tagToStringValue(err.getResponseMessage()));
+ tag.append(userTag);
+
+ StringBuilder field = new StringBuilder(30);
+ field.append(METRIC_COUNT).append(count);
+ influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
}
private void addMetric(String transaction, int count,
- Long sentBytes, Long receivedBytes,
- String statut, double mean, double minTime, double maxTime,
- Collection<Float> pcts, PercentileProvider percentileProvider) {
- if (count > 0) {
- StringBuilder tag = new StringBuilder(95);
- tag.append(TAG_APPLICATION).append(application);
- tag.append(TAG_STATUS).append(statut);
- tag.append(TAG_TRANSACTION).append(transaction);
- tag.append(userTag);
-
- StringBuilder field = new StringBuilder(80);
- field.append(METRIC_COUNT).append(count);
- if (!Double.isNaN(mean)) {
- field.append(',').append(METRIC_AVG).append(mean);
- }
- if (!Double.isNaN(minTime)) {
- field.append(',').append(METRIC_MIN).append(minTime);
- }
- if (!Double.isNaN(maxTime)) {
- field.append(',').append(METRIC_MAX).append(maxTime);
- }
- if(sentBytes != null) {
- field.append(',').append(METRIC_SENT_BYTES).append(sentBytes);
- }
- if(receivedBytes != null) {
- field.append(',').append(METRIC_RECEIVED_BYTES).append(receivedBytes);
- }
- for (Float pct : pcts) {
- field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(
- percentileProvider.getPercentileValue(pct));
- }
- influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
+ Long sentBytes, Long receivedBytes,
+ String statut, double mean, double minTime, double maxTime,
+ Collection<Float> pcts, PercentileProvider percentileProvider) {
+ if (count <= 0) {
+ return;
+ }
+ StringBuilder tag = new StringBuilder(95);
+ tag.append(TAG_APPLICATION).append(applicationName);
+ tag.append(TAG_STATUS).append(statut);
+ tag.append(TAG_TRANSACTION).append(transaction);
+ tag.append(userTag);
+
+ StringBuilder field = new StringBuilder(80);
+ field.append(METRIC_COUNT).append(count);
+ if (!Double.isNaN(mean)) {
+ field.append(',').append(METRIC_AVG).append(mean);
+ }
+ if (!Double.isNaN(minTime)) {
+ field.append(',').append(METRIC_MIN).append(minTime);
+ }
+ if (!Double.isNaN(maxTime)) {
+ field.append(',').append(METRIC_MAX).append(maxTime);
}
+ if (sentBytes != null) {
+ field.append(',').append(METRIC_SENT_BYTES).append(sentBytes);
+ }
+ if (receivedBytes != null) {
+ field.append(',').append(METRIC_RECEIVED_BYTES).append(receivedBytes);
+ }
+ for (Float pct : pcts) {
+ field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(
+ percentileProvider.getPercentileValue(pct));
+ }
+ influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
}
private void addCumulatedMetrics(SamplerMetric metric) {
int total = metric.getTotal();
- if (total > 0) {
- StringBuilder tag = new StringBuilder(70);
- StringBuilder field = new StringBuilder(100);
- Collection<Float> pcts = allPercentiles.values();
- tag.append(TAG_APPLICATION).append(application);
- tag.append(TAG_TRANSACTION).append(CUMULATED_METRICS);
- tag.append(TAG_STATUS).append(CUMULATED_METRICS);
- tag.append(userTag);
-
- field.append(METRIC_COUNT).append(total);
- field.append(',').append(METRIC_COUNT_ERROR).append(metric.getFailures());
-
- if (!Double.isNaN(metric.getOkMean())) {
- field.append(',').append(METRIC_AVG).append(Double.toString(metric.getOkMean()));
- }
- if (!Double.isNaN(metric.getOkMinTime())) {
- field.append(',').append(METRIC_MIN).append(Double.toString(metric.getOkMinTime()));
- }
- if (!Double.isNaN(metric.getOkMaxTime())) {
- field.append(',').append(METRIC_MAX).append(Double.toString(metric.getOkMaxTime()));
- }
+ if (total <= 0) {
+ return;
+ }
+ StringBuilder tag = new StringBuilder(70);
+ StringBuilder field = new StringBuilder(100);
+ Collection<Float> pcts = allPercentiles.values();
+ tag.append(TAG_APPLICATION).append(applicationName);
+ tag.append(TAG_TRANSACTION).append(CUMULATED_METRICS);
+ tag.append(TAG_STATUS).append(CUMULATED_METRICS);
+ tag.append(userTag);
- field.append(',').append(METRIC_HIT).append(metric.getHits());
- field.append(',').append(METRIC_SENT_BYTES).append(metric.getSentBytes());
- field.append(',').append(METRIC_RECEIVED_BYTES).append(metric.getReceivedBytes());
- for (Float pct : pcts) {
- field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(Double.toString(metric.getAllPercentile(pct)));
- }
- influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
+ field.append(METRIC_COUNT).append(total);
+ field.append(',').append(METRIC_COUNT_ERROR).append(metric.getFailures());
+
+ if (!Double.isNaN(metric.getOkMean())) {
+ field.append(',').append(METRIC_AVG).append(Double.toString(metric.getOkMean()));
}
+ if (!Double.isNaN(metric.getOkMinTime())) {
+ field.append(',').append(METRIC_MIN).append(Double.toString(metric.getOkMinTime()));
+ }
+ if (!Double.isNaN(metric.getOkMaxTime())) {
+ field.append(',').append(METRIC_MAX).append(Double.toString(metric.getOkMaxTime()));
+ }
+
+ field.append(',').append(METRIC_HIT).append(metric.getHits());
+ field.append(',').append(METRIC_SENT_BYTES).append(metric.getSentBytes());
+ field.append(',').append(METRIC_RECEIVED_BYTES).append(metric.getReceivedBytes());
+ for (Float pct : pcts) {
+ field.append(',').append(METRIC_PCT_PREFIX).append(pct).append('=').append(Double.toString(metric.getAllPercentile(pct)));
+ }
+ influxdbMetricsManager.addMetric(measurement, tag.toString(), field.toString());
}
- /**
- * @return the samplersList
- */
public String getSamplersRegex() {
return samplersRegex;
}
/**
- * @param samplersList
- * the samplersList to set
+ * @param samplersList the samplersList to set
*/
public void setSamplersList(String samplersList) {
this.samplersRegex = samplersList;
@@ -314,83 +309,93 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
@Override
public void setupTest(BackendListenerContext context) throws Exception {
- String influxdbMetricsSender = context.getParameter("influxdbMetricsSender");
- String influxdbUrl = context.getParameter("influxdbUrl");
- String influxdbToken = context.getParameter("influxdbToken");
summaryOnly = context.getBooleanParameter("summaryOnly", false);
samplersRegex = context.getParameter("samplersRegex", "");
- application = AbstractInfluxdbMetricsSender.tagToStringValue(context.getParameter("application", ""));
- measurement = AbstractInfluxdbMetricsSender
- .tagToStringValue(context.getParameter("measurement", DEFAULT_MEASUREMENT));
+ applicationName = AbstractInfluxdbMetricsSender.tagToStringValue(
+ context.getParameter("application", ""));
+ measurement = AbstractInfluxdbMetricsSender.tagToStringValue(
+ context.getParameter("measurement", DEFAULT_MEASUREMENT));
testTitle = context.getParameter("testTitle", "Test");
- testTags = AbstractInfluxdbMetricsSender.tagToStringValue(context.getParameter("eventTags", ""));
- String percentilesAsString = context.getParameter("percentiles", "");
- String[] percentilesStringArray = percentilesAsString.split(SEPARATOR);
- okPercentiles = new HashMap<>(percentilesStringArray.length);
- koPercentiles = new HashMap<>(percentilesStringArray.length);
- allPercentiles = new HashMap<>(percentilesStringArray.length);
- DecimalFormat format = new DecimalFormat("0.##");
- for (int i = 0; i < percentilesStringArray.length; i++) {
- if (!StringUtils.isEmpty(percentilesStringArray[i].trim())) {
- try {
- Float percentileValue = Float.valueOf(percentilesStringArray[i].trim());
- okPercentiles.put(AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue)),
- percentileValue);
- koPercentiles.put(AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue)),
- percentileValue);
- allPercentiles.put(AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue)),
- percentileValue);
-
- } catch (Exception e) {
- log.error("Error parsing percentile: '{}'", percentilesStringArray[i], e);
- }
- }
- }
- // Check if more row which started with 'TAG_' are filled ( corresponding to user tag )
+ testTags = AbstractInfluxdbMetricsSender.tagToStringValue(
+ context.getParameter("eventTags", ""));
+
+ initPercentiles(context);
+ initUserTags(context);
+ initInfluxdbMetricsManager(context);
+
+ samplersToFilter = Pattern.compile(samplersRegex);
+ addAnnotation(true);
+
+ scheduler = Executors.newScheduledThreadPool(MAX_POOL_SIZE);
+ // Start immediately the scheduler and put the pooling ( 5 seconds by default )
+ this.timerHandle = scheduler.scheduleAtFixedRate(this, 0, SEND_INTERVAL, TimeUnit.SECONDS);
+ }
+
+ private void initInfluxdbMetricsManager(BackendListenerContext context) throws Exception {
+ Class<?> clazz = Class.forName(context.getParameter("influxdbMetricsSender"));
+ influxdbMetricsManager = (InfluxdbMetricsSender) clazz.getDeclaredConstructor().newInstance();
+
+ String influxdbUrl = context.getParameter("influxdbUrl");
+ String influxdbToken = context.getParameter("influxdbToken");
+ influxdbMetricsManager.setup(influxdbUrl, influxdbToken);
+ }
+
+ private void initUserTags(BackendListenerContext context) {
+ // Check if more rows which started with 'TAG_' are filled ( corresponding to user tag )
StringBuilder userTagBuilder = new StringBuilder();
context.getParameterNamesIterator().forEachRemaining(name -> {
- if (StringUtils.isNotBlank(name) && !DEFAULT_ARGS.containsKey(name.trim())
+ if (StringUtils.isNotBlank(name)
+ && !DEFAULT_ARGS.containsKey(name.trim())
&& name.startsWith("TAG_")
&& StringUtils.isNotBlank(context.getParameter(name))) {
final String tagName = name.trim().substring(4);
final String tagValue = context.getParameter(name).trim();
userTagBuilder.append(',')
- .append(AbstractInfluxdbMetricsSender
- .tagToStringValue(tagName))
+ .append(AbstractInfluxdbMetricsSender.tagToStringValue(tagName))
.append('=')
- .append(AbstractInfluxdbMetricsSender.tagToStringValue(
- tagValue));
+ .append(AbstractInfluxdbMetricsSender.tagToStringValue(tagValue));
log.debug("Adding '{}' tag with '{}' value ", tagName, tagValue);
}
});
userTag = userTagBuilder.toString();
-
- Class<?> clazz = Class.forName(influxdbMetricsSender);
- this.influxdbMetricsManager = (InfluxdbMetricsSender) clazz.getDeclaredConstructor().newInstance();
- influxdbMetricsManager.setup(influxdbUrl, influxdbToken);
- samplersToFilter = Pattern.compile(samplersRegex);
- addAnnotation(true);
-
- scheduler = Executors.newScheduledThreadPool(MAX_POOL_SIZE);
- // Start immediately the scheduler and put the pooling ( 5 seconds by default )
- this.timerHandle = scheduler.scheduleAtFixedRate(this, 0, SEND_INTERVAL, TimeUnit.SECONDS);
-
}
- protected SamplerMetric getSamplerMetricInfluxdb(String sampleLabel) {
- SamplerMetric samplerMetric = metricsPerSampler.get(sampleLabel);
- if (samplerMetric == null) {
- samplerMetric = new SamplerMetric();
- SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel, samplerMetric);
- if (oldValue != null) {
- samplerMetric = oldValue;
+ private void initPercentiles(BackendListenerContext context) {
+ String percentilesAsString = context.getParameter("percentiles", "");
+ String[] percentilesStringArray = percentilesAsString.split(SEPARATOR);
+ okPercentiles = new HashMap<>(percentilesStringArray.length);
+ koPercentiles = new HashMap<>(percentilesStringArray.length);
+ allPercentiles = new HashMap<>(percentilesStringArray.length);
+ DecimalFormat format = new DecimalFormat("0.##");
+ for (String percentile : percentilesStringArray) {
+ String trimmedPercentile = percentile.trim();
+ if (StringUtils.isEmpty(trimmedPercentile)) {
+ continue;
+ }
+ try {
+ Float percentileValue = Float.valueOf(trimmedPercentile);
+ String key = AbstractInfluxdbMetricsSender.tagToStringValue(format.format(percentileValue));
+ okPercentiles.put(key, percentileValue);
+ koPercentiles.put(key, percentileValue);
+ allPercentiles.put(key, percentileValue);
+ } catch (Exception e) {
+ log.error("Error parsing percentile: '{}'", percentile, e);
}
}
- return samplerMetric;
}
- private Map<String, SamplerMetric> getMetricsInfluxdbPerSampler() {
- return metricsPerSampler;
+ private SamplerMetric getSamplerMetricInfluxdb(String sampleLabel) {
+ SamplerMetric samplerMetric = metricsPerSampler.get(sampleLabel);
+ if (samplerMetric != null) {
+ return samplerMetric;
+ }
+
+ SamplerMetric newSamplerMetric = new SamplerMetric();
+ SamplerMetric oldValue = metricsPerSampler.putIfAbsent(sampleLabel, newSamplerMetric);
+ if (oldValue != null) {
+ newSamplerMetric = oldValue;
+ }
+ return newSamplerMetric;
}
@Override
@@ -422,15 +427,18 @@ public class InfluxdbBackendListenerClient extends AbstractBackendListenerClient
* Tags is put as InfluxdbTag for better query performance on it
* Never double or single quotes in influxdb except for string field
* see : https://docs.influxdata.com/influxdb/v1.1/write_protocols/line_protocol_reference/#quoting-special-characters-and-additional-naming-guidelines
- * * @param startOrEnd boolean true for start, false for end
+ *
+ * @param isStartOfTest boolean true for start, false for end
*/
- private void addAnnotation(boolean startOrEnd) {
- influxdbMetricsManager.addMetric(EVENTS_FOR_ANNOTATION,
- TAG_APPLICATION + application + ",title=ApacheJMeter"+ userTag +
- (StringUtils.isNotEmpty(testTags) ? TAGS+ testTags : ""),
- TEXT +
- AbstractInfluxdbMetricsSender.fieldToStringValue(testTitle +
- (startOrEnd ? " started" : " ended")) + "\"" );
+ private void addAnnotation(boolean isStartOfTest) {
+ String tags = TAG_APPLICATION + applicationName +
+ ",title=ApacheJMeter" + userTag +
+ (StringUtils.isNotEmpty(testTags) ? TAGS + testTags : "");
+ String field = TEXT +
+ AbstractInfluxdbMetricsSender.fieldToStringValue(
+ testTitle + (isStartOfTest ? " started" : " ended")) + "\"";
+
+ influxdbMetricsManager.addMetric(EVENTS_FOR_ANNOTATION, tags, field);
}
@Override
diff --git a/src/components/src/test/groovy/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientSpec.groovy b/src/components/src/test/groovy/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientSpec.groovy
new file mode 100644
index 0000000..f303d57
--- /dev/null
+++ b/src/components/src/test/groovy/org/apache/jmeter/visualizers/backend/influxdb/InfluxdbBackendListenerClientSpec.groovy
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.visualizers.backend.influxdb
+
+import org.apache.jmeter.visualizers.backend.BackendListenerContext
+
+import spock.lang.Specification
+
+class InfluxdbBackendListenerClientSpec extends Specification {
+
+ def sut = new InfluxdbBackendListenerClient()
+ def defaultContext = new BackendListenerContext(InfluxdbBackendListenerClient.DEFAULT_ARGS)
+
+ def "setupTest with default config does not raise an exception"() {
+ when:
+ sut.setupTest(defaultContext)
+ then:
+ noExceptionThrown()
+ }
+
+ def "Sending metrics when empty does not raise an exception"() {
+ given:
+ sut.setupTest(defaultContext)
+ when:
+ sut.run()
+ then:
+ noExceptionThrown()
+ }
+
+ def "Default parameters are equal to default args"() {
+ expect:
+ sut.getDefaultParameters().getArgumentsAsMap() == InfluxdbBackendListenerClient.DEFAULT_ARGS
+ }
+}