Skip to content

Commit 3d043a5

Browse files
Allow to filter sample results when logging with jtlwriter
1 parent 312e846 commit 3d043a5

File tree

3 files changed

+149
-40
lines changed

3 files changed

+149
-40
lines changed

docs/guide/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,26 @@ public class PerformanceTest {
866866
}
867867
```
868868

869+
::: tip
869870
By default, `jtlWriter` will write the most used information to evaluate the performance of the tested service. If you want to trace all the information of each request you may use `jtlWriter` with `withAllFields()` option. Doing this will provide all the information at the cost of additional computation and resource usage (fewer resources for actual load testing). You can tune which fields to include or not with `jtlWriter` and only log what you need, check [JtlWriter](../../jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/listeners/JtlWriter.java) for more details.
871+
:::
872+
873+
::: tip
874+
By default, `jtlWriter` will log every sample result, but in some cases you might want to log additional info when a sample result fails. In such scenarios you can use two `jtlWriter` instances like in this example:
875+
876+
```java
877+
testPlan(
878+
threadGroup(2, 10,
879+
httpSampler("http://my.service")
880+
),
881+
jtlWriter("target/jtls/success")
882+
.logOnly(SampleStatus.SUCCESS),
883+
jtlWriter("target/jtls/error")
884+
.logOnly(SampleStatus.ERROR)
885+
.withAllFields(true)
886+
)
887+
```
888+
:::
870889

871890
::: tip
872891
`jtlWriter` will automatically generate `.jtl` files applying this format: `<yyyy-MM-dd HH-mm-ss> <UUID>.jtl`.

jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/listeners/JtlWriter.java

Lines changed: 106 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.Arrays;
99
import java.util.Collections;
1010
import java.util.List;
11+
import java.util.Set;
1112
import java.util.UUID;
1213
import org.apache.jmeter.reporters.ResultCollector;
1314
import org.apache.jmeter.samplers.SampleSaveConfiguration;
@@ -16,6 +17,7 @@
1617
import org.apache.jmeter.visualizers.SimpleDataWriter;
1718
import us.abstracta.jmeter.javadsl.codegeneration.MethodCall;
1819
import us.abstracta.jmeter.javadsl.codegeneration.MethodCallContext;
20+
import us.abstracta.jmeter.javadsl.codegeneration.MethodParam;
1921
import us.abstracta.jmeter.javadsl.codegeneration.SingleTestElementCallBuilder;
2022
import us.abstracta.jmeter.javadsl.codegeneration.TestElementParamBuilder;
2123
import us.abstracta.jmeter.javadsl.codegeneration.params.BoolParam;
@@ -42,6 +44,7 @@
4244
public class JtlWriter extends BaseListener {
4345

4446
protected String jtlFile;
47+
protected SampleStatus logOnly;
4548
protected boolean saveAsXml;
4649
protected boolean saveElapsedTime = true;
4750
protected boolean saveResponseMessage = true;
@@ -87,43 +90,24 @@ private static String buildFileName() {
8790
return timeFormatter.format(Instant.now()) + " " + UUID.randomUUID() + ".jtl";
8891
}
8992

90-
@Override
91-
public TestElement buildTestElement() {
92-
ResultCollector logger = new ResultCollector();
93-
logger.setFilename(jtlFile);
94-
SampleSaveConfiguration config = logger.getSaveConfig();
95-
config.setAsXml(saveAsXml);
96-
config.setTime(saveElapsedTime);
97-
config.setMessage(saveResponseMessage);
98-
config.setSuccess(saveSuccess);
99-
config.setSentBytes(saveSentByteCount);
100-
config.setFileName(saveResponseFilename);
101-
config.setEncoding(saveEncoding);
102-
config.setIdleTime(saveIdleTime);
103-
config.setResponseHeaders(saveResponseHeaders);
104-
config.setAssertions(saveAssertionResults);
105-
config.setFieldNames(saveFieldNames);
106-
config.setLabel(saveLabel);
107-
config.setThreadName(saveThreadName);
108-
config.setAssertionResultsFailureMessage(saveAssertionFailureMessage);
109-
config.setThreadCounts(saveActiveThreadCounts);
110-
config.setLatency(saveLatency);
111-
config.setSampleCount(saveSampleAndErrorCounts);
112-
config.setRequestHeaders(saveRequestHeaders);
113-
config.setResponseData(saveResponseData);
114-
config.setTimestamp(saveTimeStamp);
115-
config.setCode(saveResponseCode);
116-
config.setDataType(saveDataType);
117-
config.setBytes(saveReceivedByteCount);
118-
config.setUrl(saveUrl);
119-
config.setConnectTime(saveConnectTime);
120-
config.setHostname(saveHostname);
121-
config.setSamplerData(saveSamplerData);
122-
config.setSubresults(saveSubResults);
123-
if (!sampleVariables.isEmpty()) {
124-
JMeterUtils.setProperty("sample_variables", String.join(",", sampleVariables));
125-
}
126-
return logger;
93+
/**
94+
* Allows filtering which sample results to log according to their status.
95+
* <p>
96+
* This is useful, for example, when you want to have a jtl file with basic information for
97+
* success sample results, but a more detailed jtl file for the ones that fail.
98+
*
99+
* @param status specifies the status of the sample results to log. When set to null it will log
100+
* all sample results. By default, it is set to null.
101+
* @return the JtlWriter for further configuration or usage.
102+
* @since 1.4
103+
*/
104+
public JtlWriter logOnly(SampleStatus status) {
105+
this.logOnly = status;
106+
return this;
107+
}
108+
109+
public enum SampleStatus {
110+
SUCCESS, ERROR
127111
}
128112

129113
/**
@@ -665,6 +649,49 @@ public JtlWriter withVariables(String... variables) {
665649
return this;
666650
}
667651

652+
@Override
653+
public TestElement buildTestElement() {
654+
ResultCollector logger = new ResultCollector();
655+
logger.setFilename(jtlFile);
656+
if (logOnly != null) {
657+
logger.setSuccessOnlyLogging(logOnly == SampleStatus.SUCCESS);
658+
logger.setErrorLogging(logOnly == SampleStatus.ERROR);
659+
}
660+
SampleSaveConfiguration config = logger.getSaveConfig();
661+
config.setAsXml(saveAsXml);
662+
config.setTime(saveElapsedTime);
663+
config.setMessage(saveResponseMessage);
664+
config.setSuccess(saveSuccess);
665+
config.setSentBytes(saveSentByteCount);
666+
config.setFileName(saveResponseFilename);
667+
config.setEncoding(saveEncoding);
668+
config.setIdleTime(saveIdleTime);
669+
config.setResponseHeaders(saveResponseHeaders);
670+
config.setAssertions(saveAssertionResults);
671+
config.setFieldNames(saveFieldNames);
672+
config.setLabel(saveLabel);
673+
config.setThreadName(saveThreadName);
674+
config.setAssertionResultsFailureMessage(saveAssertionFailureMessage);
675+
config.setThreadCounts(saveActiveThreadCounts);
676+
config.setLatency(saveLatency);
677+
config.setSampleCount(saveSampleAndErrorCounts);
678+
config.setRequestHeaders(saveRequestHeaders);
679+
config.setResponseData(saveResponseData);
680+
config.setTimestamp(saveTimeStamp);
681+
config.setCode(saveResponseCode);
682+
config.setDataType(saveDataType);
683+
config.setBytes(saveReceivedByteCount);
684+
config.setUrl(saveUrl);
685+
config.setConnectTime(saveConnectTime);
686+
config.setHostname(saveHostname);
687+
config.setSamplerData(saveSamplerData);
688+
config.setSubresults(saveSubResults);
689+
if (!sampleVariables.isEmpty()) {
690+
JMeterUtils.setProperty("sample_variables", String.join(",", sampleVariables));
691+
}
692+
return logger;
693+
}
694+
668695
public static class CodeBuilder extends SingleTestElementCallBuilder<ResultCollector> {
669696

670697
public CodeBuilder(List<Method> builderMethods) {
@@ -695,6 +722,7 @@ protected MethodCall buildMethodCall(ResultCollector collector, MethodCallContex
695722
if (isAllSet(config)) {
696723
return ret.chain("withAllFields", new BoolParam(true, false));
697724
}
725+
ret.chain("logOnly", SampleStatusParam.fromParamBuilder(paramBuilder));
698726
return ret.chain("saveAsXml", new BoolParam(config.saveAsXml(), false))
699727
.chain("withElapsedTime", new BoolParam(config.saveTime(), true))
700728
.chain("withResponseMessage", new BoolParam(config.saveMessage(), true))
@@ -741,4 +769,45 @@ private boolean isAllSet(SampleSaveConfiguration config) {
741769

742770
}
743771

772+
private static class SampleStatusParam extends MethodParam {
773+
774+
private final SampleStatus sampleStatus;
775+
776+
private SampleStatusParam(SampleStatus sampleStatus) {
777+
super(SampleStatus.class, null);
778+
this.sampleStatus = sampleStatus;
779+
}
780+
781+
public static MethodParam fromParamBuilder(TestElementParamBuilder paramBuilder) {
782+
SampleStatus status = null;
783+
MethodParam successOnly = paramBuilder.boolParam(
784+
"ResultCollector.success_only_logging", false);
785+
if (!successOnly.isDefault()) {
786+
status = SampleStatus.SUCCESS;
787+
} else {
788+
MethodParam errorOnly = paramBuilder.boolParam("ResultCollector.error_logging", false);
789+
if (!errorOnly.isDefault()) {
790+
status = SampleStatus.ERROR;
791+
}
792+
}
793+
return new SampleStatusParam(status);
794+
}
795+
796+
@Override
797+
public boolean isDefault() {
798+
return sampleStatus == null;
799+
}
800+
801+
@Override
802+
public Set<String> getImports() {
803+
return Collections.singleton(SampleStatus.class.getName());
804+
}
805+
806+
@Override
807+
protected String buildCode(String indent) {
808+
return SampleStatus.class.getSimpleName() + "." + sampleStatus.name();
809+
}
810+
811+
}
812+
744813
}

jmeter-java-dsl/src/test/java/us/abstracta/jmeter/javadsl/core/listeners/JtlWriterTest.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import us.abstracta.jmeter.javadsl.codegeneration.MethodCallBuilderTest;
2020
import us.abstracta.jmeter.javadsl.core.DslTestPlan;
2121
import us.abstracta.jmeter.javadsl.core.StringTemplateAssert;
22+
import us.abstracta.jmeter.javadsl.core.listeners.JtlWriter.SampleStatus;
2223

2324
public class JtlWriterTest extends JmeterDslTest {
2425

@@ -162,7 +163,7 @@ public void shouldJtlIncludeCustomVariableWhenJtlWithCustomVariableDefined(@Temp
162163
@Nested
163164
public class CodeBuilderTest extends MethodCallBuilderTest {
164165

165-
public DslTestPlan simpleTestPlanWithJtlWriterAndDefaultSaves() {
166+
public DslTestPlan testPlanWithJtlWriterAndDefaultSaves() {
166167
return testPlan(
167168
threadGroup(1, 1,
168169
httpSampler("http://localhost")
@@ -171,7 +172,27 @@ public DslTestPlan simpleTestPlanWithJtlWriterAndDefaultSaves() {
171172
);
172173
}
173174

174-
public DslTestPlan simpleTestPlanWithJtlWriterSavingAllFields() {
175+
public DslTestPlan testPlanWithJtlWriterOnlyLoggingSuccessSampleResults() {
176+
return testPlan(
177+
threadGroup(1, 1,
178+
httpSampler("http://localhost")
179+
),
180+
jtlWriter("", "results.jtl")
181+
.logOnly(SampleStatus.SUCCESS)
182+
);
183+
}
184+
185+
public DslTestPlan testPlanWithJtlWriterOnlyLoggingErrorSampleResults() {
186+
return testPlan(
187+
threadGroup(1, 1,
188+
httpSampler("http://localhost")
189+
),
190+
jtlWriter("", "results.jtl")
191+
.logOnly(SampleStatus.ERROR)
192+
);
193+
}
194+
195+
public DslTestPlan testPlanWithJtlWriterSavingAllFields() {
175196
return testPlan(
176197
threadGroup(1, 1,
177198
httpSampler("http://localhost")
@@ -181,7 +202,7 @@ public DslTestPlan simpleTestPlanWithJtlWriterSavingAllFields() {
181202
);
182203
}
183204

184-
public DslTestPlan simpleTestPlanWithJtlWriterAndSavingNonDefaultFields() {
205+
public DslTestPlan testPlanWithJtlWriterAndSavingNonDefaultFields() {
185206
return testPlan(
186207
threadGroup(1, 1,
187208
httpSampler("http://localhost")

0 commit comments

Comments
 (0)