Hello,
This commit breaks report generation with below stacktrace. I opened
https://bz.apache.org/bugzilla/show_bug.cgi?id=62540
To reproduce , put in user.properties:
jmeter.save.saveservice.print_field_names=true
jmeter.save.saveservice.data_type=false
jmeter.save.saveservice.timestamp_format=dd/MM HH:mm:ss
Make a test, and then try generating
jmeter -p <jmeter_home>/bin/jmeter.properties -q user.properties -g
results.csv -o reportFolder
This is due to early computing of Sample while normalization has not yet
happened.
2018-07-15 22:41:52,208 ERROR o.a.j.JMeter: An error occurred:
org.apache.jmeter.report.core.SampleException: Error in sample at line:1
converting field:timeStamp at column:0 to:long, fieldValue:'28/06 15:23:47'
at org.apache.jmeter.report.core.Sample.getData(Sample.java:138)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Sample.getData(Sample.java:156)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Sample.getPossibleValue(Sample.java:83)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Sample.<init>(Sample.java:72)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at
org.apache.jmeter.report.core.CsvSampleReader.nextSample(CsvSampleReader.java:192)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at
org.apache.jmeter.report.core.CsvSampleReader.<init>(CsvSampleReader.java:135)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at
org.apache.jmeter.report.core.CsvSampleReader.<init>(CsvSampleReader.java:87)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.processor.CsvFileSampleSource.
<init>(CsvFileSampleSource.java:113) ~[ApacheJMeter_core.jar:4.1-
SNAPSHOT.20180715]
at org.apache.jmeter.report.dashboard.ReportGenerator.
generate(ReportGenerator.java:211) ~[ApacheJMeter_core.jar:4.1-
SNAPSHOT.20180715]
at org.apache.jmeter.JMeter.start(JMeter.java:522)
[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
~[?:1.8.0_161]
at sun.reflect.NativeMethodAccessorImpl.invoke(
NativeMethodAccessorImpl.java:62) ~[?:1.8.0_161]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(
DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_161]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_161]
at org.apache.jmeter.NewDriver.main(NewDriver.java:245)
[ApacheJMeter.jar:4.1-SNAPSHOT.20180715]
Caused by: org.apache.jmeter.report.core.ConvertException: Unable to
convert "28/06 15:23:47" to "java.lang.Long"
at org.apache.jmeter.report.core.Converters$5.convert(Converters.java:102)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Converters$5.convert(Converters.java:95)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Converters.convert(Converters.java:172)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Sample.getData(Sample.java:134)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
... 14 more
Caused by: java.lang.NumberFormatException: For input string: "28/06
15:23:47"
at
java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
~[?:1.8.0_161]
at java.lang.Long.parseLong(Long.java:589) ~[?:1.8.0_161]
at java.lang.Long.valueOf(Long.java:803) ~[?:1.8.0_161]
at org.apache.jmeter.report.core.Converters$5.convert(Converters.java:100)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Converters$5.convert(Converters.java:95)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Converters.convert(Converters.java:172)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
at org.apache.jmeter.report.core.Sample.getData(Sample.java:134)
~[ApacheJMeter_core.jar:4.1-SNAPSHOT.20180715]
... 14 more
On Sun, Jul 8, 2018 at 7:45 AM, <[email protected]> wrote:
> Author: fschumacher
> Date: Sun Jul 8 11:45:32 2018
> New Revision: 1835351
>
> URL: http://svn.apache.org/viewvc?rev=1835351&view=rev
> Log:
> Optimize performance of report generation.
>
> Compute things that don't change, but get used often eagerly.
> Don't use String#format for simple concatenation, as it is really slow.
> Based on feedback by Allen (444104595 at qq.com)
>
> Bugzilla Id: 62426
>
> Modified:
> jmeter/trunk/src/core/org/apache/jmeter/report/core/Sample.java
> jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/SyntheticResponseTimeDistributionGraphConsumer.java
> jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/TransactionsPerSecondGraphConsumer.java
> jmeter/trunk/xdocs/changes.xml
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/report/core/Sample.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apach
> e/jmeter/report/core/Sample.java?rev=1835351&r1=1835350&
> r2=1835351&view=diff
> ============================================================
> ==================
> --- jmeter/trunk/src/core/org/apache/jmeter/report/core/Sample.java
> (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/report/core/Sample.java Sun
> Jul 8 11:45:32 2018
> @@ -35,13 +35,21 @@ public class Sample {
> private static final String ERROR_ON_SAMPLE = "Error in sample at
> line:";
>
> private static final String CONTROLLER_PATTERN = "Number of samples
> in transaction";
> -
> +
> private static final String EMPTY_CONTROLLER_PATTERN = "Number of
> samples in transaction : 0";
>
> private final boolean storesStartTimeStamp;
> private final SampleMetadata metadata;
> private final String[] data;
> private final long row;
> + private final long elapsedTime;
> + private final long timestamp;
> + private final long latency;
> + private final long connectTime;
> + private final long receivedBytes;
> + private final long sentBytes;
> + private final int groupThreads;
> + private final boolean success;
>
> /**
> * Build a sample from a string array
> @@ -59,6 +67,14 @@ public class Sample {
> this.metadata = metadata;
> this.data = data;
> this.storesStartTimeStamp =
> JMeterUtils.getPropDefault("sampleresult.timestamp.start",
> false);
> + this.elapsedTime = getData(long.class,
> CSVSaveService.CSV_ELAPSED).longValue();
> + this.timestamp = getData(long.class,
> CSVSaveService.TIME_STAMP).longValue();
> + this.latency = getData(long.class, CSVSaveService.CSV_LATENCY).lo
> ngValue();
> + this.connectTime = metadata.indexOf(CSVSaveService.CSV_CONNECT_TIME)
> >= 0 ? getData(long.class, CSVSaveService.CSV_CONNECT_TIME).longValue() :
> 0L;
> + this.success = getData(boolean.class,
> CSVSaveService.SUCCESSFUL).booleanValue();
> + this.receivedBytes = getData(long.class,
> CSVSaveService.CSV_BYTES).longValue();
> + this.sentBytes = metadata.indexOf(CSVSaveService.CSV_SENT_BYTES)
> >= 0 ? getData(long.class, CSVSaveService.CSV_SENT_BYTES).longValue() :
> 0L;
> + this.groupThreads = getData(int.class,
> CSVSaveService.CSV_THREAD_COUNT1).intValue();
> }
>
> /**
> @@ -148,7 +164,7 @@ public class Sample {
> * @return the time stamp
> */
> public long getTimestamp() {
> - return getData(long.class, CSVSaveService.TIME_STAMP).lon
> gValue();
> + return this.timestamp;
> }
>
> /**
> @@ -157,7 +173,7 @@ public class Sample {
> * @return the elapsed time stored in the sample
> */
> public long getElapsedTime() {
> - return getData(long.class, CSVSaveService.CSV_ELAPSED).lo
> ngValue();
> + return this.elapsedTime;
> }
>
> /**
> @@ -242,20 +258,16 @@ public class Sample {
> * @return the latency stored in the sample
> */
> public long getLatency() {
> - return getData(long.class, CSVSaveService.CSV_LATENCY).lo
> ngValue();
> + return this.latency;
> }
> -
> +
> /**
> * Gets the connect time stored in the sample.
> *
> * @return the connect time stored in the sample or 0 is column is
> not in results
> */
> public long getConnectTime() {
> - if(metadata.indexOf(CSVSaveService.CSV_CONNECT_TIME) >= 0) {
> - return getData(long.class, CSVSaveService.CSV_CONNECT_TIM
> E).longValue();
> - } else {
> - return 0L;
> - }
> + return this.connectTime;
> }
>
> /**
> @@ -264,7 +276,7 @@ public class Sample {
> * @return the success status stored in the sample
> */
> public boolean getSuccess() {
> - return getData(boolean.class, CSVSaveService.SUCCESSFUL).boo
> leanValue();
> + return this.success;
> }
>
> /**
> @@ -273,7 +285,7 @@ public class Sample {
> * @return the number of received bytes stored in the sample
> */
> public long getReceivedBytes() {
> - return getData(long.class, CSVSaveService.CSV_BYTES).longValue();
> + return this.receivedBytes;
> }
>
> /**
> @@ -282,11 +294,7 @@ public class Sample {
> * @return the number of sent bytes stored in the sample
> */
> public long getSentBytes() {
> - if(metadata.indexOf(CSVSaveService.CSV_SENT_BYTES) >= 0) {
> - return getData(long.class, CSVSaveService.CSV_SENT_BYTES)
> .longValue();
> - } else {
> - return 0L;
> - }
> + return this.sentBytes;
> }
>
> /**
> @@ -295,7 +303,7 @@ public class Sample {
> * @return the number of threads in the group of this sample
> */
> public int getGroupThreads() {
> - return getData(int.class, CSVSaveService.CSV_THREAD_COUN
> T1).intValue();
> + return this.groupThreads;
> }
>
> /**
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/SyntheticResponseTimeDistributionGraphConsumer.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apach
> e/jmeter/report/processor/graph/impl/SyntheticResponseTi
> meDistributionGraphConsumer.java?rev=1835351&r1=1835350&
> r2=1835351&view=diff
> ============================================================
> ==================
> --- jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/SyntheticResponseTimeDistributionGraphConsumer.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/SyntheticResponseTimeDistributionGraphConsumer.java Sun Jul 8
> 11:45:32 2018
> @@ -19,7 +19,9 @@ package org.apache.jmeter.report.process
>
> import java.text.MessageFormat;
> import java.util.Arrays;
> +import java.util.Collections;
> import java.util.HashMap;
> +import java.util.List;
> import java.util.Map;
>
> import org.apache.jmeter.report.core.Sample;
> @@ -44,9 +46,12 @@ import org.apache.jmeter.util.JMeterUtil
> public class SyntheticResponseTimeDistributionGraphConsumer extends
> AbstractGraphConsumer {
> private static final String FAILED_LABEL =
> JMeterUtils.getResString("response_time_distribution_failed_label");
> - private static final MessageFormat SATISFIED_LABEL = new
> MessageFormat(JMeterUtils.getResString("response_time_distri
> bution_satisfied_label"));
> - private static final MessageFormat TOLERATED_LABEL = new
> MessageFormat(JMeterUtils.getResString("response_time_distri
> bution_tolerated_label"));
> - private static final MessageFormat UNTOLERATED_LABEL = new
> MessageFormat(JMeterUtils.getResString("response_time_distri
> bution_untolerated_label"));
> + private static final MessageFormat SATISFIED_LABEL = new
> MessageFormat(
> + JMeterUtils.getResString("response_time_distribution_satisfi
> ed_label"));
> + private static final MessageFormat TOLERATED_LABEL = new
> MessageFormat(
> + JMeterUtils.getResString("response_time_distribution_tolerat
> ed_label"));
> + private static final MessageFormat UNTOLERATED_LABEL = new
> MessageFormat(
> + JMeterUtils.getResString("response_time_distribution_untoler
> ated_label"));
> private static final String SERIE_COLOR_PROPERTY = "color";
> private static final String SATISFIED_COLOR = "#9ACD32";
> private static final String TOLERATED_COLOR = "yellow";
> @@ -55,6 +60,9 @@ public class SyntheticResponseTimeDistri
>
> private long satisfiedThreshold;
> private long toleratedThreshold;
> + List<String> satisfiedLabels = Collections.emptyList();
> + List<String> toleratedLabels = Collections.emptyList();
> + List<String> untoleratedLabels = Collections.emptyList();
>
> private class SyntheticSeriesSelector extends AbstractSeriesSelector {
> @Override
> @@ -64,11 +72,11 @@ public class SyntheticResponseTimeDistri
> } else {
> long elapsedTime = sample.getElapsedTime();
> if(elapsedTime<=getSatisfiedThreshold()) {
> - return Arrays.asList(SATISFIED_LABEL.format(new
> Object[] {Long.valueOf(getSatisfiedThreshold())}));
> + return satisfiedLabels;
> } else if(elapsedTime <= getToleratedThreshold()) {
> - return Arrays.asList(TOLERATED_LABEL.format(new
> Object[] {Long.valueOf(getSatisfiedThreshold()),
> Long.valueOf(getToleratedThreshold())}));
> + return toleratedLabels;
> } else {
> - return Arrays.asList(UNTOLERATED_LABEL.format(new
> Object[] {Long.valueOf(getToleratedThreshold())}));
> + return untoleratedLabels;
> }
> }
> }
> @@ -170,6 +178,7 @@ public class SyntheticResponseTimeDistri
> */
> public void setSatisfiedThreshold(long satisfiedThreshold) {
> this.satisfiedThreshold = satisfiedThreshold;
> + formatLabels();
> }
>
> /**
> @@ -184,5 +193,15 @@ public class SyntheticResponseTimeDistri
> */
> public void setToleratedThreshold(long toleratedThreshold) {
> this.toleratedThreshold = toleratedThreshold;
> + formatLabels();
> + }
> +
> + private void formatLabels() {
> + this.satisfiedLabels = Collections
> + .singletonList(SATISFIED_LABEL.format(new Object[] {
> Long.valueOf(this.satisfiedThreshold) }));
> + this.toleratedLabels = Collections.singletonList(TOLERATED_LABEL
> + .format(new Object[] { Long.valueOf(this.satisfiedThreshold),
> Long.valueOf(this.toleratedThreshold) }));
> + this.untoleratedLabels = Collections
> + .singletonList(UNTOLERATED_LABEL.format(new Object[] {
> Long.valueOf(this.toleratedThreshold) }));
> }
> }
>
> Modified: jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/TransactionsPerSecondGraphConsumer.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apach
> e/jmeter/report/processor/graph/impl/TransactionsPerSeco
> ndGraphConsumer.java?rev=1835351&r1=1835350&r2=1835351&view=diff
> ============================================================
> ==================
> --- jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/TransactionsPerSecondGraphConsumer.java (original)
> +++ jmeter/trunk/src/core/org/apache/jmeter/report/processor/
> graph/impl/TransactionsPerSecondGraphConsumer.java Sun Jul 8 11:45:32
> 2018
> @@ -18,7 +18,7 @@
> package org.apache.jmeter.report.processor.graph.impl;
>
> import java.util.Arrays;
> -import java.util.HashMap;
> +import java.util.Collections;
> import java.util.Map;
>
> import org.apache.jmeter.report.core.Sample;
> @@ -39,7 +39,6 @@ import org.apache.jmeter.report.processo
> public class TransactionsPerSecondGraphConsumer extends
> AbstractOverTimeGraphConsumer {
>
> - private static final String STATUS_SERIES_FORMAT = "%s-%s";
> private static final String SUCCESS_SERIES_SUFFIX = "success";
> private static final String FAILURE_SERIES_SUFFIX = "failure";
>
> @@ -65,23 +64,20 @@ public class TransactionsPerSecondGraphC
> */
> @Override
> protected Map<String, GroupInfo> createGroupInfos() {
> - HashMap<String, GroupInfo> groupInfos = new HashMap<>(1);
> - groupInfos.put(AbstractGraphConsumer.DEFAULT_GROUP, new
> GroupInfo(
> - new TimeRateAggregatorFactory(), new
> AbstractSeriesSelector(
> - true) {
> + GroupInfo value = new GroupInfo(
> + new TimeRateAggregatorFactory(),
> + new AbstractSeriesSelector(true) {
>
> @Override
> public Iterable<String> select(Sample sample) {
> - String label = String.format(STATUS_SERIES_FO
> RMAT,
> - sample.getName(),
> - sample.getSuccess() ?
> SUCCESS_SERIES_SUFFIX
> - : FAILURE_SERIES_SUFFIX);
> + String success = sample.getSuccess() ?
> SUCCESS_SERIES_SUFFIX : FAILURE_SERIES_SUFFIX;
> + String label = sample.getName() + "-" + success;
> return Arrays.asList(label);
> }
> },
> // We include Transaction Controller results
> - new CountValueSelector(false), false, false));
> - return groupInfos;
> + new CountValueSelector(false), false, false);
> + return Collections.singletonMap(Abstr
> actGraphConsumer.DEFAULT_GROUP, value);
> }
>
> @Override
>
> Modified: jmeter/trunk/xdocs/changes.xml
> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?
> rev=1835351&r1=1835350&r2=1835351&view=diff
> ============================================================
> ==================
> --- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
> +++ jmeter/trunk/xdocs/changes.xml [utf-8] Sun Jul 8 11:45:32 2018
> @@ -133,6 +133,7 @@ this behaviour, set <code>httpclient.res
> <li><bug>62243</bug>Dashboard : make option
> "<code>--forceDeleteResultFile</code>"/"<code>-f</code>" option delete
> folder referenced by "<code>-o</code>" option</li>
> <li><bug>62367</bug>HTML Report Generator: Add Graph Total
> Transactions per Second. Contributed mainly by Martha Laks (laks.martha at
> gmail.com)</li>
> <li><bug>62166</bug>Report/Dashboard: Provide ability to register
> custom graphs and metrics in the JMeter Dashboard. Contributed by Ubik Load
> Pack (support at ubikloadpack.com)</li>
> + <li><bug>62426</bug>Optimize performance of report generation. Based
> on feedback by Allen (444104595 at qq.com)</li>
> </ul>
>
> <h3>General</h3>
> @@ -269,6 +270,7 @@ this behaviour, set <code>httpclient.res
> <li>helppass (onegaicimasu at hotmail.com)</li>
> <li>blue414 (blue414 at 163.com)</li>
> <li>Aaron Levin</li>
> + <li>Allen (444104595 at qq.com)</li>
> </ul>
> <p>We also thank bug reporters who helped us improve JMeter.</p>
> <p>
>
>
>
--
Cordialement.
Philippe Mouawad.