Skip to content

Commit e17d84e

Browse files
arustamovalopezz
andauthored
Add ability to exclude sample results to be sent as logs based on response code regex (#48)
* Add ability to send only errors as logs * isErrorResponse to handle non-HTTP response code * Reverted IDEA default formatting * Add ability to exclude sample results to be sent as logs based on response code regex * Added testExcludeLogsResponseCodeRegexMatching * Slightly updated README to highlight exclude strategy * Added testExcludeLogsResponseCodeRegexDefaultEmpty * Revert default import order * Update README.md Co-authored-by: Alex Lopez <alex.lopez.zorzano@gmail.com> --------- Co-authored-by: Alex Lopez <alex.lopez.zorzano@gmail.com>
1 parent 2e012e1 commit e17d84e

7 files changed

Lines changed: 108 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changes
22

3+
## 0.5.0
4+
* [Added] Add ability to exclude sample results to be sent as logs based on response code regex
5+
See [#47](https://github.com/DataDog/jmeter-datadog-backend-listener/issues/47)
6+
37
## 0.4.0
48
* [Changed] Set configured tags on plugin generated logs. (See [#45](https://github.com/DataDog/jmeter-datadog-backend-listener/pull/45)).
59

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ The plugin has the following configuration options:
4646
|logsBatchSize|false|500|Logs are submitted in batches of size `logsBatchSize` as soon as this size is reached.|
4747
|sendResultsAsLogs|false|false|By default only metrics are reported to Datadog. To report individual test results as log events, set this field to `true`.|
4848
|includeSubresults|false|false|A subresult is for instance when an individual HTTP request has to follow redirects. By default subresults are ignored.|
49+
|excludeLogsResponseCodeRegex|false|`""`| Setting `sendResultsAsLogs` will submit all results as logs to Datadog by default. This option lets you exclude results whose response code matches a given regex. For example, you may set this option to `[123][0-5][0-9]` to only submit errors.|
4950
|customTags|false|`""`|Comma-separated list of tags to add to every metric
5051

5152
## Troubleshooting

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<groupId>com.datadoghq</groupId>
88
<artifactId>jmeter-datadog-backend-listener</artifactId>
99

10-
<version>0.4.0</version>
10+
<version>0.5.0</version>
1111
<name>jmeter-datadog-backend-listener</name>
1212
<url>https://github.com/DataDog/jmeter-datadog-backend-listener</url>
1313
<description>Datadog JMeter plugin</description>

src/main/java/org/datadog/jmeter/plugins/DatadogBackendClient.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55

66
package org.datadog.jmeter.plugins;
77

8-
import java.util.Arrays;
98
import java.util.ArrayList;
9+
import java.util.Arrays;
1010
import java.util.List;
1111
import java.util.concurrent.Executors;
1212
import java.util.concurrent.ScheduledExecutorService;
1313
import java.util.concurrent.ScheduledFuture;
1414
import java.util.concurrent.TimeUnit;
1515
import java.util.concurrent.atomic.AtomicInteger;
1616
import java.util.regex.Matcher;
17-
import java.util.regex.Pattern;
1817
import java.util.stream.Collectors;
1918
import net.minidev.json.JSONObject;
2019
import org.apache.jmeter.config.Arguments;
@@ -175,10 +174,12 @@ private void extractData(SampleResult sampleResult) {
175174
userMetrics.add(sampleResult);
176175
this.extractMetrics(sampleResult);
177176
if(configuration.shouldSendResultsAsLogs()) {
178-
this.extractLogs(sampleResult);
179-
if(logsBuffer.size() >= configuration.getLogsBatchSize()) {
180-
datadogClient.submitLogs(logsBuffer, this.configuration.getCustomTags());
181-
logsBuffer.clear();
177+
if(!shouldExcludeSampleResultAsLogs(sampleResult)) {
178+
this.extractLogs(sampleResult);
179+
if (logsBuffer.size() >= configuration.getLogsBatchSize()) {
180+
datadogClient.submitLogs(logsBuffer, this.configuration.getCustomTags());
181+
logsBuffer.clear();
182+
}
182183
}
183184
}
184185
if(configuration.shouldIncludeSubResults()) {
@@ -188,6 +189,14 @@ private void extractData(SampleResult sampleResult) {
188189
}
189190
}
190191

192+
/**
193+
* Called for each individual result. It checks if logs for the sample result should be excluded
194+
* @param sampleResult the result
195+
*/
196+
private boolean shouldExcludeSampleResultAsLogs(SampleResult sampleResult) {
197+
return configuration.getExcludeLogsResponseCodeRegex().matcher(sampleResult.getResponseCode()).matches();
198+
}
199+
191200
/**
192201
* Called for each individual result. It extracts metrics and give them to the {@link ConcurrentAggregator} instance for aggregation.
193202
* @param sampleResult the result

src/main/java/org/datadog/jmeter/plugins/DatadogConfiguration.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public class DatadogConfiguration {
4949
*/
5050
private boolean sendResultsAsLogs;
5151

52+
/**
53+
* User configurable. This options configures which Datadog logs to exclude from submission using a regex
54+
* that matches on the response code.
55+
*/
56+
private Pattern excludeLogsResponseCodeRegex = null;
57+
5258
/**
5359
* This options configures whether or not to collect metrics and logs for jmeter subresults.
5460
*/
@@ -74,6 +80,7 @@ public class DatadogConfiguration {
7480
private static final String LOGS_BATCH_SIZE = "logsBatchSize";
7581
private static final String SEND_RESULTS_AS_LOGS = "sendResultsAsLogs";
7682
private static final String INCLUDE_SUB_RESULTS = "includeSubresults";
83+
private static final String EXCLUDE_LOGS_RESPONSE_CODE_REGEX = "excludeLogsResponseCodeRegex";
7784
private static final String SAMPLERS_REGEX = "samplersRegex";
7885
private static final String CUSTOM_TAGS ="customTags";
7986

@@ -84,6 +91,7 @@ public class DatadogConfiguration {
8491
private static final int DEFAULT_LOGS_BATCH_SIZE = 500;
8592
private static final boolean DEFAULT_SEND_RESULTS_AS_LOGS = true;
8693
private static final boolean DEFAULT_INCLUDE_SUB_RESULTS = false;
94+
private static final String DEFAULT_EXCLUDE_LOGS_RESPONSE_CODE_REGEX = "";
8795
private static final String DEFAULT_SAMPLERS_REGEX = "";
8896
private static final String DEFAULT_CUSTOM_TAGS = "";
8997

@@ -98,6 +106,7 @@ public static Arguments getPluginArguments() {
98106
arguments.addArgument(LOGS_BATCH_SIZE, String.valueOf(DEFAULT_LOGS_BATCH_SIZE));
99107
arguments.addArgument(SEND_RESULTS_AS_LOGS, String.valueOf(DEFAULT_SEND_RESULTS_AS_LOGS));
100108
arguments.addArgument(INCLUDE_SUB_RESULTS, String.valueOf(DEFAULT_INCLUDE_SUB_RESULTS));
109+
arguments.addArgument(EXCLUDE_LOGS_RESPONSE_CODE_REGEX, DEFAULT_EXCLUDE_LOGS_RESPONSE_CODE_REGEX);
101110
arguments.addArgument(SAMPLERS_REGEX, DEFAULT_SAMPLERS_REGEX);
102111
arguments.addArgument(CUSTOM_TAGS, DEFAULT_CUSTOM_TAGS);
103112
return arguments;
@@ -141,8 +150,11 @@ public static DatadogConfiguration parseConfiguration(BackendListenerContext con
141150
throw new DatadogConfigurationException("Invalid 'includeSubResults'. Value '" + includeSubResults + "' is not a boolean.");
142151
}
143152
configuration.includeSubResults = Boolean.parseBoolean(includeSubResults);
153+
144154
configuration.samplersRegex = Pattern.compile(context.getParameter(SAMPLERS_REGEX, DEFAULT_SAMPLERS_REGEX));
145155

156+
configuration.excludeLogsResponseCodeRegex = Pattern.compile(context.getParameter(EXCLUDE_LOGS_RESPONSE_CODE_REGEX, DEFAULT_EXCLUDE_LOGS_RESPONSE_CODE_REGEX));
157+
146158
String customTagsString = context.getParameter(CUSTOM_TAGS, String.valueOf(DEFAULT_CUSTOM_TAGS));
147159
List<String> customTags = new ArrayList<>();
148160
if(customTagsString.contains(",")){
@@ -186,6 +198,10 @@ public boolean shouldIncludeSubResults() {
186198
return includeSubResults;
187199
}
188200

201+
public Pattern getExcludeLogsResponseCodeRegex() {
202+
return excludeLogsResponseCodeRegex;
203+
}
204+
189205
public Pattern getSamplersRegex() {
190206
return samplersRegex;
191207
}

src/test/java/org/datadog/jmeter/plugins/DatadogBackendClientTest.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public class DatadogBackendClientTest
5151
put("logsBatchSize", "0");
5252
put("sendResultsAsLogs", "true");
5353
put("includeSubresults", "false");
54+
put("excludeLogsResponseCodeRegex", "");
5455
put("samplersRegex", "^foo\\d*$");
5556
put("customTags", "key:value");
5657
}
@@ -85,9 +86,13 @@ public void teardownMocks() throws Exception {
8586

8687

8788
private SampleResult createDummySampleResult(String sampleLabel) {
89+
return createDummySampleResult(sampleLabel, "123");
90+
}
91+
92+
private SampleResult createDummySampleResult(String sampleLabel, String responseCode) {
8893
SampleResult result = SampleResult.createTestSample(1, 126);
8994
result.setSuccessful(true);
90-
result.setResponseCode("123");
95+
result.setResponseCode(responseCode);
9196
result.setSampleLabel(sampleLabel);
9297
result.setSampleCount(10);
9398
result.setErrorCount(1);
@@ -268,7 +273,7 @@ private void assertMetricsWithTag(List<DatadogMetric> metrics, Map<String, Doubl
268273
}
269274

270275
@Test
271-
public void testRegexNotMatching() {
276+
public void testSamplersRegexNotMatching() {
272277
SampleResult result1 = createDummySampleResult("foo1");
273278
SampleResult resultA = createDummySampleResult("fooA");
274279

@@ -281,4 +286,38 @@ public void testRegexNotMatching() {
281286
Assert.assertEquals("foo1", this.logsBuffer.get(0).getAsString("sample_label"));
282287
}
283288

289+
@Test
290+
public void testExcludeLogsResponseCodeRegexDefaultEmpty() {
291+
SampleResult result1 = createDummySampleResult("foo1", "200");
292+
SampleResult result2 = createDummySampleResult("foo2", "301");
293+
SampleResult result3 = createDummySampleResult("foo3", "404");
294+
SampleResult result4 = createDummySampleResult("foo4", "Non HTTP response code: java.net.NoRouteToHostException");
295+
296+
this.client.handleSampleResults(Arrays.asList(result1, result2, result3, result4), context);
297+
Assert.assertEquals(4, this.logsBuffer.size());
298+
Assert.assertEquals("foo1", this.logsBuffer.get(0).getAsString("sample_label"));
299+
Assert.assertEquals("foo2", this.logsBuffer.get(1).getAsString("sample_label"));
300+
Assert.assertEquals("foo3", this.logsBuffer.get(2).getAsString("sample_label"));
301+
Assert.assertEquals("foo4", this.logsBuffer.get(3).getAsString("sample_label"));
302+
}
303+
304+
@Test
305+
public void testExcludeLogsResponseCodeRegexMatching() throws Exception {
306+
HashMap<String, String> config = new HashMap<>(DEFAULT_VALID_TEST_CONFIG);
307+
config.put("excludeLogsResponseCodeRegex", "^[23][0-5][0-9]$");
308+
DatadogBackendClient client = new DatadogBackendClient();
309+
BackendListenerContext context = new BackendListenerContext(config);
310+
client.setupTest(context);
311+
312+
SampleResult result1 = createDummySampleResult("foo1", "200");
313+
SampleResult result2 = createDummySampleResult("foo2", "301");
314+
SampleResult result3 = createDummySampleResult("foo3", "404");
315+
SampleResult result4 = createDummySampleResult("foo4", "Non HTTP response code: java.net.NoRouteToHostException");
316+
317+
client.handleSampleResults(Arrays.asList(result1, result2, result3, result4), context);
318+
Assert.assertEquals(2, this.logsBuffer.size());
319+
Assert.assertEquals("foo3", this.logsBuffer.get(0).getAsString("sample_label"));
320+
Assert.assertEquals("foo4", this.logsBuffer.get(1).getAsString("sample_label"));
321+
}
322+
284323
}

src/test/java/org/datadog/jmeter/plugins/DatadogConfigurationTest.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55

66
package org.datadog.jmeter.plugins;
77

8-
import java.util.Arrays;
98
import java.util.ArrayList;
9+
import java.util.Arrays;
1010
import java.util.HashMap;
1111
import java.util.Map;
1212
import java.util.regex.PatternSyntaxException;
1313
import org.apache.jmeter.config.Arguments;
1414
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
1515
import org.datadog.jmeter.plugins.exceptions.DatadogConfigurationException;
16-
import org.junit.Test;
1716
import org.junit.Assert;
17+
import org.junit.Test;
1818

1919
public class DatadogConfigurationTest {
2020
private static final String API_URL_PARAM = "datadogUrl";
@@ -24,13 +24,14 @@ public class DatadogConfigurationTest {
2424
private static final String LOGS_BATCH_SIZE = "logsBatchSize";
2525
private static final String SEND_RESULTS_AS_LOGS = "sendResultsAsLogs";
2626
private static final String INCLUDE_SUB_RESULTS = "includeSubresults";
27+
private static final String EXCLUDE_LOGS_RESPONSE_CODE_REGEX = "excludeLogsResponseCodeRegex";
2728
private static final String SAMPLERS_REGEX = "samplersRegex";
2829
private static final String CUSTOM_TAGS = "customTags";
2930

3031
@Test
3132
public void testArguments(){
3233
Arguments args = DatadogConfiguration.getPluginArguments();
33-
Assert.assertEquals(9, args.getArgumentCount());
34+
Assert.assertEquals(10, args.getArgumentCount());
3435

3536
Map<String, String> argumentsMap = args.getArgumentsAsMap();
3637
Assert.assertTrue(argumentsMap.containsKey(API_URL_PARAM));
@@ -40,6 +41,7 @@ public void testArguments(){
4041
Assert.assertTrue(argumentsMap.containsKey(LOGS_BATCH_SIZE));
4142
Assert.assertTrue(argumentsMap.containsKey(SEND_RESULTS_AS_LOGS));
4243
Assert.assertTrue(argumentsMap.containsKey(INCLUDE_SUB_RESULTS));
44+
Assert.assertTrue(argumentsMap.containsKey(EXCLUDE_LOGS_RESPONSE_CODE_REGEX));
4345
Assert.assertTrue(argumentsMap.containsKey(SAMPLERS_REGEX));
4446
Assert.assertTrue(argumentsMap.containsKey(CUSTOM_TAGS));
4547
}
@@ -55,6 +57,7 @@ public void testValidConfiguration() throws DatadogConfigurationException {
5557
put(LOGS_BATCH_SIZE, "11");
5658
put(SEND_RESULTS_AS_LOGS, "true");
5759
put(INCLUDE_SUB_RESULTS, "false");
60+
put(EXCLUDE_LOGS_RESPONSE_CODE_REGEX, "");
5861
put(SAMPLERS_REGEX, "false");
5962
put(CUSTOM_TAGS, "key:value");
6063
}
@@ -134,7 +137,29 @@ public void testIncludeSubresultsNotBoolean() throws DatadogConfigurationExcepti
134137
}
135138

136139
@Test(expected = PatternSyntaxException.class)
137-
public void testInvalidRegex() throws DatadogConfigurationException {
140+
public void testInvalidExcludeLogsResponseCodeRegex() throws DatadogConfigurationException {
141+
Map<String, String> config = new HashMap<String, String>() {
142+
{
143+
put("apiKey", "123456");
144+
put(EXCLUDE_LOGS_RESPONSE_CODE_REGEX, "[");
145+
}
146+
};
147+
DatadogConfiguration.parseConfiguration(new BackendListenerContext(config));
148+
}
149+
150+
@Test
151+
public void testValidExcludeLogsResponseCodeRegex() throws DatadogConfigurationException {
152+
Map<String, String> config = new HashMap<String, String>() {
153+
{
154+
put("apiKey", "123456");
155+
put(EXCLUDE_LOGS_RESPONSE_CODE_REGEX, "[123][0-5][0-9]");
156+
}
157+
};
158+
DatadogConfiguration.parseConfiguration(new BackendListenerContext(config));
159+
}
160+
161+
@Test(expected = PatternSyntaxException.class)
162+
public void testInvalidSamplersRegex() throws DatadogConfigurationException {
138163
Map<String, String> config = new HashMap<String, String>() {
139164
{
140165
put("apiKey", "123456");
@@ -145,7 +170,7 @@ public void testInvalidRegex() throws DatadogConfigurationException {
145170
}
146171

147172
@Test
148-
public void testValidRegex() throws DatadogConfigurationException {
173+
public void testValidSamplersRegex() throws DatadogConfigurationException {
149174
Map<String, String> config = new HashMap<String, String>() {
150175
{
151176
put("apiKey", "123456");

0 commit comments

Comments
 (0)