diff --git a/README.md b/README.md index ceb6098..ecd7c59 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ JMeter ElasticSearch Backend Listener is a JMeter plugin enabling you to send te * Filters * Only send the samples you want by using Filters! Simply type them as follows in the field ``es.sample.filter`` : ``filter1;filter2;filter3`` or ``sampleLabel_must_contain_this``. * You can also choose to exclude certain samplers; `!!exclude_this;filter1;filter2` -* Specific fields ```field1;field2;field3` +* Specific fields ``field1;field2;field3`` * Specify fields that you want to send to ElasticSearch (possible fields below) * AllThreads * BodySize @@ -41,6 +41,9 @@ JMeter ElasticSearch Backend Listener is a JMeter plugin enabling you to send te * SampleEndTime * Timestamp * InjectorHostname +* Field rename + * Set a different name for the predefined fields by providing a mapping in the field ``es.fields.mapping`` : ``AllThreads:threadCount;ResponseTime:duration;Timestamp:@timestamp``. In this case ``threadCount,duration,@timestamp``, would be sent to ElasticSearch instead of ``AllThreads,ResponseTime,Timestamp``. + * Use the changed name of fields when ``es.fields`` is used. * Verbose, semi-verbose, error only, and quiet mode * __debug__ : Send request/response information of all samplers (headers, body, etc.) * __info__ : Sends all samplers to the ElasticSearch engine, but only sends the headers, body info for the failed samplers. diff --git a/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticSearchMetric.java b/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticSearchMetric.java index a996092..656730c 100644 --- a/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticSearchMetric.java +++ b/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticSearchMetric.java @@ -30,15 +30,17 @@ public class ElasticSearchMetric { private int ciBuildNumber; private HashMap json; private Set fields; + private Map esFieldNameMap; private boolean allReqHeaders; private boolean allResHeaders; public ElasticSearchMetric( SampleResult sr, String testMode, String timeStamp, int buildNumber, - boolean parseReqHeaders, boolean parseResHeaders, Set fields) { + boolean parseReqHeaders, boolean parseResHeaders, Set fields, Map fieldNameMap) { this.sampleResult = sr; this.esTestMode = testMode.trim(); this.esTimestamp = timeStamp.trim(); + this.esFieldNameMap = fieldNameMap; this.ciBuildNumber = buildNumber; this.json = new HashMap<>(); this.allReqHeaders = parseReqHeaders; @@ -56,28 +58,28 @@ public Map getMetric(BackendListenerContext context) throws Exce SimpleDateFormat sdf = new SimpleDateFormat(this.esTimestamp); //add all the default SampleResult parameters - addFilteredJSON("AllThreads", this.sampleResult.getAllThreads()); - addFilteredJSON("BodySize", this.sampleResult.getBodySizeAsLong()); - addFilteredJSON("Bytes", this.sampleResult.getBytesAsLong()); - addFilteredJSON("SentBytes", this.sampleResult.getSentBytes()); - addFilteredJSON("ConnectTime", this.sampleResult.getConnectTime()); - addFilteredJSON("ContentType", this.sampleResult.getContentType()); - addFilteredJSON("DataType", this.sampleResult.getDataType()); - addFilteredJSON("ErrorCount", this.sampleResult.getErrorCount()); - addFilteredJSON("GrpThreads", this.sampleResult.getGroupThreads()); - addFilteredJSON("IdleTime", this.sampleResult.getIdleTime()); - addFilteredJSON("Latency", this.sampleResult.getLatency()); - addFilteredJSON("ResponseTime", this.sampleResult.getTime()); - addFilteredJSON("SampleCount", this.sampleResult.getSampleCount()); - addFilteredJSON("SampleLabel", this.sampleResult.getSampleLabel()); - addFilteredJSON("ThreadName", this.sampleResult.getThreadName()); - addFilteredJSON("URL", this.sampleResult.getURL()); - addFilteredJSON("ResponseCode", this.sampleResult.getResponseCode()); - addFilteredJSON("TestStartTime", JMeterContextService.getTestStartTime()); - addFilteredJSON("SampleStartTime", sdf.format(new Date(this.sampleResult.getStartTime()))); - addFilteredJSON("SampleEndTime", sdf.format(new Date(this.sampleResult.getEndTime()))); - addFilteredJSON("Timestamp", this.sampleResult.getTimeStamp()); - addFilteredJSON("InjectorHostname", InetAddress.getLocalHost().getHostName()); + addFilteredJSON(this.esFieldNameMap.get("AllThreads"), this.sampleResult.getAllThreads()); + addFilteredJSON(this.esFieldNameMap.get("BodySize"), this.sampleResult.getBodySizeAsLong()); + addFilteredJSON(this.esFieldNameMap.get("Bytes"), this.sampleResult.getBytesAsLong()); + addFilteredJSON(this.esFieldNameMap.get("SentBytes"), this.sampleResult.getSentBytes()); + addFilteredJSON(this.esFieldNameMap.get("ConnectTime"), this.sampleResult.getConnectTime()); + addFilteredJSON(this.esFieldNameMap.get("ContentType"), this.sampleResult.getContentType()); + addFilteredJSON(this.esFieldNameMap.get("DataType"), this.sampleResult.getDataType()); + addFilteredJSON(this.esFieldNameMap.get("ErrorCount"), this.sampleResult.getErrorCount()); + addFilteredJSON(this.esFieldNameMap.get("GrpThreads"), this.sampleResult.getGroupThreads()); + addFilteredJSON(this.esFieldNameMap.get("IdleTime"), this.sampleResult.getIdleTime()); + addFilteredJSON(this.esFieldNameMap.get("Latency"), this.sampleResult.getLatency()); + addFilteredJSON(this.esFieldNameMap.get("ResponseTime"), this.sampleResult.getTime()); + addFilteredJSON(this.esFieldNameMap.get("SampleCount"), this.sampleResult.getSampleCount()); + addFilteredJSON(this.esFieldNameMap.get("SampleLabel"), this.sampleResult.getSampleLabel()); + addFilteredJSON(this.esFieldNameMap.get("ThreadName"), this.sampleResult.getThreadName()); + addFilteredJSON(this.esFieldNameMap.get("URL"), this.sampleResult.getURL()); + addFilteredJSON(this.esFieldNameMap.get("ResponseCode"), this.sampleResult.getResponseCode()); + addFilteredJSON(this.esFieldNameMap.get("TestStartTime"), JMeterContextService.getTestStartTime()); + addFilteredJSON(this.esFieldNameMap.get("SampleStartTime"), sdf.format(new Date(this.sampleResult.getStartTime()))); + addFilteredJSON(this.esFieldNameMap.get("SampleEndTime"), sdf.format(new Date(this.sampleResult.getEndTime()))); + addFilteredJSON(this.esFieldNameMap.get("Timestamp"), this.sampleResult.getTimeStamp()); + addFilteredJSON(this.esFieldNameMap.get("InjectorHostname"), InetAddress.getLocalHost().getHostName()); // Add the details according to the mode that is set switch (this.esTestMode) { diff --git a/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticsearchBackendClient.java b/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticsearchBackendClient.java index 2fe23ee..d1dd876 100644 --- a/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticsearchBackendClient.java +++ b/src/main/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/ElasticsearchBackendClient.java @@ -1,4 +1,4 @@ - package io.github.delirius325.jmeter.backendlistener.elasticsearch; +package io.github.delirius325.jmeter.backendlistener.elasticsearch; import java.util.*; import java.util.regex.Matcher; @@ -31,6 +31,7 @@ public class ElasticsearchBackendClient extends AbstractBackendListenerClient { private static final String ES_PORT = "es.port"; private static final String ES_INDEX = "es.index"; private static final String ES_FIELDS = "es.fields"; + private static final String ES_FIELDS_MAPPING = "es.fields.mapping"; private static final String ES_TIMESTAMP = "es.timestamp"; private static final String ES_BULK_SIZE = "es.bulk.size"; private static final String ES_TIMEOUT_MS = "es.timout.ms"; @@ -62,6 +63,7 @@ public class ElasticsearchBackendClient extends AbstractBackendListenerClient { DEFAULT_ARGS.put(ES_TIMEOUT_MS, Long.toString(DEFAULT_TIMEOUT_MS)); DEFAULT_ARGS.put(ES_SAMPLE_FILTER, null); DEFAULT_ARGS.put(ES_FIELDS, null); + DEFAULT_ARGS.put(ES_FIELDS_MAPPING, null); DEFAULT_ARGS.put(ES_TEST_MODE, "info"); DEFAULT_ARGS.put(ES_AUTH_USER, ""); DEFAULT_ARGS.put(ES_AUTH_PWD, ""); @@ -78,6 +80,7 @@ public class ElasticsearchBackendClient extends AbstractBackendListenerClient { private Set modes; private Set filters; private Set fields; + private Map fieldNameMap; private int buildNumber; private int bulkSize; private int esVersion; @@ -100,6 +103,7 @@ public void setupTest(BackendListenerContext context) throws Exception { this.filters = new HashSet<>(); this.fields = new HashSet<>(); this.modes = new HashSet<>(Arrays.asList("info", "debug", "error", "quiet")); + this.fieldNameMap = new HashMap(); this.bulkSize = Integer.parseInt(context.getParameter(ES_BULK_SIZE)); this.timeoutMs = Integer.parseInt((context.getParameter(ES_TIMEOUT_MS))); this.buildNumber = (JMeterUtils.getProperty(ElasticsearchBackendClient.BUILD_NUMBER) != null @@ -132,6 +136,7 @@ public void onFailure(Node node) { convertParameterToSet(context, ES_SAMPLE_FILTER, this.filters); convertParameterToSet(context, ES_FIELDS, this.fields); + convertParameterToMap(context, ES_FIELDS_MAPPING, this.fieldNameMap); this.sender = new ElasticSearchMetricSender(client, context.getParameter(ES_INDEX).toLowerCase(), context.getParameter(ES_AUTH_USER), context.getParameter(ES_AUTH_PWD), @@ -164,6 +169,50 @@ private void convertParameterToSet(BackendListenerContext context, String parame } } + /** + * Method that converts a semicolon plus colon separated list contained in a parameter into a Map + * @param context + * @param parameter + * @param map + */ + private void convertParameterToMap(BackendListenerContext context, String parameter, Map map) { + List originalFieldnames = Arrays.asList( + "AllThreads", + "BodySize", + "Bytes", + "SentBytes", + "ConnectTime", + "ContentType", + "DataType", + "ErrorCount", + "GrpThreads", + "IdleTime", + "Latency", + "ResponseTime", + "SampleCount", + "SampleLabel", + "ThreadName", + "URL", + "ResponseCode", + "TestStartTime", + "SampleStartTime", + "SampleEndTime", + "Timestamp", + "InjectorHostname" + ); + for (String field : originalFieldnames) { + map.put(field, field); + } + if (context.getParameter(parameter).contains(":")) { + for (String mapping : context.getParameter(parameter).split(";")) { + String[] m = mapping.split(":"); + map.put(m[0].trim(), m[1].trim()); + if(logger.isDebugEnabled()) + logger.debug("fieldname '" + m[0].trim() + "' replaced by '" + m[1].trim() + "'"); + } + } + } + /** * Method that sets the SSL configuration to be able to send requests to a secured endpoint * @param context @@ -213,7 +262,7 @@ public void handleSampleResults(List results, BackendListenerConte ElasticSearchMetric metric = new ElasticSearchMetric(sr, context.getParameter(ES_TEST_MODE), context.getParameter(ES_TIMESTAMP), this.buildNumber, context.getBooleanParameter(ES_PARSE_REQ_HEADERS, false), - context.getBooleanParameter(ES_PARSE_RES_HEADERS, false), fields); + context.getBooleanParameter(ES_PARSE_RES_HEADERS, false), fields, this.fieldNameMap); if (validateSample(context, sr)) { try { diff --git a/src/test/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/TestElasticSearchBackend.java b/src/test/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/TestElasticSearchBackend.java index 6968d42..655be21 100644 --- a/src/test/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/TestElasticSearchBackend.java +++ b/src/test/java/io/github/delirius325/jmeter/backendlistener/elasticsearch/TestElasticSearchBackend.java @@ -5,6 +5,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; +import java.util.HashMap; import org.apache.jmeter.samplers.SampleResult; import org.junit.Before; @@ -18,9 +19,9 @@ public class TestElasticSearchBackend { @Before public void setUp() throws Exception { metricCI = new ElasticSearchMetric(new SampleResult(), "info", "yyyy-MM-dd'T'HH:mm:ss.SSSZZ", 1, false, false, - new HashSet()); + new HashSet(), new HashMap()); metricNoCI = new ElasticSearchMetric(new SampleResult(), "info", "yyyy-MM-dd'T'HH:mm:ss.SSSZZ", 0, false, - false, new HashSet()); + false, new HashSet(), new HashMap()); } @Test