mirror of https://github.com/apache/jmeter.git
				
				
				
			Bug 62367 - HTML Report Generator: Add Graph Total Transactions per Second
Mainly contributed by  laks.martha 
Bugzilla Id: 62367
git-svn-id: https://svn.apache.org/repos/asf/jmeter/trunk@1831444 13f79535-47bb-0310-9956-ffa450edef68
Former-commit-id: 341fecb621
			
			
This commit is contained in:
		
							parent
							
								
									31cd47cac1
								
							
						
					
					
						commit
						5063b3863e
					
				|  | @ -1331,6 +1331,84 @@ function refreshTransactionsPerSecond(fixTimestamps) { | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | var totalTPSInfos = { | ||||||
|  |         data: ${totalTPS!"{}"}, | ||||||
|  |         getOptions: function(){ | ||||||
|  |             return { | ||||||
|  |                 series: { | ||||||
|  |                     lines: { | ||||||
|  |                         show: true | ||||||
|  |                     }, | ||||||
|  |                     points: { | ||||||
|  |                         show: true | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 xaxis: { | ||||||
|  |                     mode: "time", | ||||||
|  |                     timeformat: "%H:%M:%S", | ||||||
|  |                     axisLabel: getElapsedTimeLabel(this.data.result.granularity), | ||||||
|  |                     axisLabelUseCanvas: true, | ||||||
|  |                     axisLabelFontSizePixels: 12, | ||||||
|  |                     axisLabelFontFamily: 'Verdana, Arial', | ||||||
|  |                     axisLabelPadding: 20, | ||||||
|  |                 }, | ||||||
|  |                 yaxis: { | ||||||
|  |                     axisLabel: "Number of transactions / sec", | ||||||
|  |                     axisLabelUseCanvas: true, | ||||||
|  |                     axisLabelFontSizePixels: 12, | ||||||
|  |                     axisLabelFontFamily: 'Verdana, Arial', | ||||||
|  |                     axisLabelPadding: 20 | ||||||
|  |                 }, | ||||||
|  |                 legend: { | ||||||
|  |                     noColumns: 2, | ||||||
|  |                     show: true, | ||||||
|  |                     container: "#legendTotalTPS" | ||||||
|  |                 }, | ||||||
|  |                 selection: { | ||||||
|  |                     mode: 'xy' | ||||||
|  |                 }, | ||||||
|  |                 grid: { | ||||||
|  |                     hoverable: true // IMPORTANT! this is needed for tooltip to | ||||||
|  |                                     // work | ||||||
|  |                 }, | ||||||
|  |                 tooltip: true, | ||||||
|  |                 tooltipOpts: { | ||||||
|  |                     content: "%s at %x was %y transactions / sec" | ||||||
|  |                 }, | ||||||
|  |                 colors: ["#9ACD32", "#FF6347"] | ||||||
|  |             }; | ||||||
|  |         }, | ||||||
|  |     createGraph: function () { | ||||||
|  |         var data = this.data; | ||||||
|  |         var dataset = prepareData(data.result.series, $("#choicesTotalTPS")); | ||||||
|  |         var options = this.getOptions(); | ||||||
|  |         prepareOptions(options, data); | ||||||
|  |         $.plot($("#flotTotalTPS"), dataset, options); | ||||||
|  |         // setup overview | ||||||
|  |         $.plot($("#overviewTotalTPS"), dataset, prepareOverviewOptions(options)); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Total Transactions per second | ||||||
|  | function refreshTotalTPS(fixTimestamps) { | ||||||
|  |     var infos = totalTPSInfos; | ||||||
|  |     prepareSeries(infos.data); | ||||||
|  |     if(fixTimestamps) { | ||||||
|  |         fixTimeStamps(infos.data.result.series, ${(timeZoneOffset?c)!0}); | ||||||
|  |     } | ||||||
|  |     if(isGraph($("#flotTotalTPS"))){ | ||||||
|  |         infos.createGraph(); | ||||||
|  |     }else{ | ||||||
|  |         var choiceContainer = $("#choicesTotalTPS"); | ||||||
|  |         createLegend(choiceContainer, infos); | ||||||
|  |         infos.createGraph(); | ||||||
|  |         setGraphZoomable("#flotTotalTPS", "#overviewTotalTPS"); | ||||||
|  |         $('#footerTotalTPS .legendColorBox > div').each(function(i){ | ||||||
|  |             $(this).clone().prependTo(choiceContainer.find("li").eq(i)); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // Collapse the graph matching the specified DOM element depending the collapsed | // Collapse the graph matching the specified DOM element depending the collapsed | ||||||
| // status | // status | ||||||
| function collapse(elem, collapsed){ | function collapse(elem, collapsed){ | ||||||
|  | @ -1388,6 +1466,11 @@ function collapse(elem, collapsed){ | ||||||
|                 refreshTransactionsPerSecond(true); |                 refreshTransactionsPerSecond(true); | ||||||
|             } |             } | ||||||
|             document.location.href="#transactionsPerSecond"; |             document.location.href="#transactionsPerSecond"; | ||||||
|  |         } else if (elem.id == "bodyTotalTPS") { | ||||||
|  |             if (isGraph($(elem).find('.flot-chart-content')) == false) { | ||||||
|  |                 refreshTotalTPS(true); | ||||||
|  |             } | ||||||
|  |             document.location.href="#totalTPS"; | ||||||
|         } else if (elem.id == "bodyResponseTimeVsRequest") { |         } else if (elem.id == "bodyResponseTimeVsRequest") { | ||||||
|             if (isGraph($(elem).find('.flot-chart-content')) == false) { |             if (isGraph($(elem).find('.flot-chart-content')) == false) { | ||||||
|                 refreshResponseTimeVsRequest(); |                 refreshResponseTimeVsRequest(); | ||||||
|  | @ -1471,6 +1554,9 @@ function toggleAll(id, checked){ | ||||||
|     } else if ( id == "choicesTransactionsPerSecond"){ |     } else if ( id == "choicesTransactionsPerSecond"){ | ||||||
|         choiceContainer = $("#choicesTransactionsPerSecond"); |         choiceContainer = $("#choicesTransactionsPerSecond"); | ||||||
|         refreshTransactionsPerSecond(false); |         refreshTransactionsPerSecond(false); | ||||||
|  |     } else if ( id == "choicesTotalTPS"){ | ||||||
|  |         choiceContainer = $("#choicesTotalTPS"); | ||||||
|  |         refreshTotalTPS(false); | ||||||
|     } else if ( id == "choicesResponseTimeVsRequest"){ |     } else if ( id == "choicesResponseTimeVsRequest"){ | ||||||
|         choiceContainer = $("#choicesResponseTimeVsRequest"); |         choiceContainer = $("#choicesResponseTimeVsRequest"); | ||||||
|         refreshResponseTimeVsRequest(); |         refreshResponseTimeVsRequest(); | ||||||
|  |  | ||||||
|  | @ -80,6 +80,9 @@ | ||||||
|                                         <li> |                                         <li> | ||||||
|                                             <a href="Throughput.html#transactionsPerSecond" onclick="$('#bodyTransactionsPerSecond').collapse('show');">Transactions Per Second</a> |                                             <a href="Throughput.html#transactionsPerSecond" onclick="$('#bodyTransactionsPerSecond').collapse('show');">Transactions Per Second</a> | ||||||
|                                         </li> |                                         </li> | ||||||
|  |                                         <li> | ||||||
|  |                                             <a href="Throughput.html#totalTPS" onclick="$('#bodyTotalTPS').collapse('show');">Total Transactions Per Second</a> | ||||||
|  |                                         </li> | ||||||
|                                         <li> |                                         <li> | ||||||
|                                             <a href="Throughput.html#responseTimeVsRequest" onclick="$('#bodyResponseTimeVsRequest').collapse('show');">Response Time Vs Request</a> |                                             <a href="Throughput.html#responseTimeVsRequest" onclick="$('#bodyResponseTimeVsRequest').collapse('show');">Response Time Vs Request</a> | ||||||
|                                         </li> |                                         </li> | ||||||
|  | @ -281,6 +284,52 @@ | ||||||
|                     <!-- /.panel --> |                     <!-- /.panel --> | ||||||
|                 </div> |                 </div> | ||||||
| 
 | 
 | ||||||
|  |                 <div class="col-lg-12 portlet" id="totalTPS"> | ||||||
|  |                     <div class="panel panel-default"> | ||||||
|  |                         <div class="panel-heading portlet-header"> | ||||||
|  |                           <i class="fa fa-bar-chart-o fa-fw"> </i> <span type="button" class="dropdown-toggle click-title span-title" data-toggle="collapse" href="#bodyTotalTPS" aria-expanded="true" aria-controls="bodyTotalTPS">Total Transactions Per Second</span> | ||||||
|  |                           <div class="pull-right"> | ||||||
|  |                                 <div class="btn-group"> | ||||||
|  |                                     <a class="btn btn-link btn-xs"> | ||||||
|  |                                         <i class="glyphicon glyphicon-resize-vertical"></i> | ||||||
|  |                                     </a> | ||||||
|  |                                     <button type="button" class="btn btn-link btn-xs dropdown-toggle" data-toggle="dropdown"> | ||||||
|  |                                         <i class="fa fa-wrench"></i> | ||||||
|  |                                     </button> | ||||||
|  |                                     <ul class="dropdown-menu dropdown-user"> | ||||||
|  |                                         <li><a href="#totalTPS" onClick="checkAll('choicesTotalTPS');">Display all samples</a> | ||||||
|  |                                         </li> | ||||||
|  |                                         <li><a href="#totalTPS" onClick="uncheckAll('choicesTotalTPS');">Hide all samples</a> | ||||||
|  |                                         </li> | ||||||
|  |                                         <li><a href="#totalTPS" onclick="exportToPNG('flotTotalTPS', this);">Save as PNG</a></li> | ||||||
|  |                                     </ul> | ||||||
|  |                                     <button type="button" class="btn btn-link btn-xs dropdown-toggle" data-toggle="collapse" href="#bodyTotalTPS" aria-expanded="true" aria-controls="bodyTotalTPS"> | ||||||
|  |                                         <i class="fa fa-chevron-down"></i> | ||||||
|  |                                     </button> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <!-- /.panel-heading --> | ||||||
|  |                         <div class="collapse out portlet-content" id="bodyTotalTPS"> | ||||||
|  |                             <div class="panel-body" id="collapseTotalTPS"> | ||||||
|  |                                 <div class="flot-chart"> | ||||||
|  |                                     <div class="flot-chart-content" id="flotTotalTPS" style="float: left; width:80%;"></div> | ||||||
|  |                                     <div style="float:left;margin-left:5px"> | ||||||
|  |                                         <p>Zoom :</p> | ||||||
|  |                                         <div id="overviewTotalTPS" style="width:190px;height:100px;"></div> | ||||||
|  |                                     </div> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                             <div class="panel-footer" id="footerTotalTPS"> | ||||||
|  |                                 <p id="legendTotalTPS" hidden></p> | ||||||
|  |                                 <ul id="choicesTotalTPS" class="legend"></ul> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                         <!-- /.panel-body --> | ||||||
|  |                     </div> | ||||||
|  |                     <!-- /.panel --> | ||||||
|  |                 </div> | ||||||
|  | 
 | ||||||
|                 <div class="col-lg-12 portlet" id="responseTimeVsRequest"> |                 <div class="col-lg-12 portlet" id="responseTimeVsRequest"> | ||||||
|                     <div class="panel panel-default"> |                     <div class="panel panel-default"> | ||||||
|                         <div class="panel-heading portlet-header"> |                         <div class="panel-heading portlet-header"> | ||||||
|  |  | ||||||
|  | @ -161,6 +161,11 @@ jmeter.reportgenerator.graph.codesPerSecond.title=Codes Per Second | ||||||
| jmeter.reportgenerator.graph.codesPerSecond.exclude_controllers=true | jmeter.reportgenerator.graph.codesPerSecond.exclude_controllers=true | ||||||
| jmeter.reportgenerator.graph.codesPerSecond.property.set_granularity=${jmeter.reportgenerator.overall_granularity} | jmeter.reportgenerator.graph.codesPerSecond.property.set_granularity=${jmeter.reportgenerator.overall_granularity} | ||||||
| 
 | 
 | ||||||
|  | # Total TPS Per Second graph definition | ||||||
|  | jmeter.reportgenerator.graph.totalTPS.classname=org.apache.jmeter.report.processor.graph.impl.TotalTPSGraphConsumer | ||||||
|  | jmeter.reportgenerator.graph.totalTPS.title=Total Transactions Per Second | ||||||
|  | jmeter.reportgenerator.graph.totalTPS.property.set_granularity=${jmeter.reportgenerator.overall_granularity} | ||||||
|  | 
 | ||||||
| # Transactions Per Second graph definition | # Transactions Per Second graph definition | ||||||
| jmeter.reportgenerator.graph.transactionsPerSecond.classname=org.apache.jmeter.report.processor.graph.impl.TransactionsPerSecondGraphConsumer | jmeter.reportgenerator.graph.transactionsPerSecond.classname=org.apache.jmeter.report.processor.graph.impl.TransactionsPerSecondGraphConsumer | ||||||
| jmeter.reportgenerator.graph.transactionsPerSecond.title=Transactions Per Second | jmeter.reportgenerator.graph.transactionsPerSecond.title=Transactions Per Second | ||||||
|  |  | ||||||
|  | @ -0,0 +1,123 @@ | ||||||
|  | /* | ||||||
|  |  * 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.report.processor.graph.impl; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | import org.apache.jmeter.report.core.Sample; | ||||||
|  | import org.apache.jmeter.report.processor.ListResultData; | ||||||
|  | import org.apache.jmeter.report.processor.MapResultData; | ||||||
|  | import org.apache.jmeter.report.processor.TimeRateAggregatorFactory; | ||||||
|  | import org.apache.jmeter.report.processor.graph.AbstractGraphConsumer; | ||||||
|  | import org.apache.jmeter.report.processor.graph.AbstractOverTimeGraphConsumer; | ||||||
|  | import org.apache.jmeter.report.processor.graph.AbstractSeriesSelector; | ||||||
|  | import org.apache.jmeter.report.processor.graph.CountValueSelector; | ||||||
|  | import org.apache.jmeter.report.processor.graph.GroupInfo; | ||||||
|  | import org.apache.jmeter.report.processor.graph.SeriesData; | ||||||
|  | import org.apache.jmeter.report.processor.graph.TimeStampKeysSelector; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * The class TotalTPSGraphConsumer provides a graph to visualize transactions | ||||||
|  |  * rate per second. | ||||||
|  |  * | ||||||
|  |  * @since 4.1 | ||||||
|  |  */ | ||||||
|  | public class TotalTPSGraphConsumer 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"; | ||||||
|  |     private static final String TRANSACTION_SUCCESS_LABEL = String.format(STATUS_SERIES_FORMAT, "Transaction", SUCCESS_SERIES_SUFFIX); | ||||||
|  |     private static final String TRANSACTION_FAILURE_LABEL = String.format(STATUS_SERIES_FORMAT, "Transaction", FAILURE_SERIES_SUFFIX); | ||||||
|  |     /* | ||||||
|  |      * (non-Javadoc) | ||||||
|  |      * | ||||||
|  |      * @see | ||||||
|  |      * org.apache.jmeter.report.csv.processor.impl.AbstractOverTimeGraphConsumer | ||||||
|  |      * #createTimeStampKeysSelector() | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     protected TimeStampKeysSelector createTimeStampKeysSelector() { | ||||||
|  |         TimeStampKeysSelector keysSelector = new TimeStampKeysSelector(); | ||||||
|  |         keysSelector.setSelectBeginTime(false); | ||||||
|  |         return keysSelector; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* | ||||||
|  |      * (non-Javadoc) | ||||||
|  |      * | ||||||
|  |      * @see org.apache.jmeter.report.csv.processor.impl.AbstractGraphConsumer# | ||||||
|  |      * createGroupInfos() | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     protected Map<String, GroupInfo> createGroupInfos() { | ||||||
|  |         Map<String, GroupInfo> groupInfos = new HashMap<>(1); | ||||||
|  |         groupInfos.put(AbstractGraphConsumer.DEFAULT_GROUP, | ||||||
|  |                 new GroupInfo(new TimeRateAggregatorFactory(), new AbstractSeriesSelector(true) { | ||||||
|  |                     @Override | ||||||
|  |                     public Iterable<String> select(Sample sample) { | ||||||
|  |                         return Arrays.asList(sample.getSuccess() ? TRANSACTION_SUCCESS_LABEL : TRANSACTION_FAILURE_LABEL); | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                         // We include Transaction Controller results | ||||||
|  |                         new CountValueSelector(false), false, false)); | ||||||
|  |         return groupInfos; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /* | ||||||
|  |      * (non-Javadoc) | ||||||
|  |      * | ||||||
|  |      * @see | ||||||
|  |      * org.apache.jmeter.report.csv.processor.impl.AbstractOverTimeGraphConsumer | ||||||
|  |      * #setGranularity(long) | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     public void setGranularity(long granularity) { | ||||||
|  |         super.setGranularity(granularity); | ||||||
|  |         // Override the granularity of the aggregators factory | ||||||
|  |         ((TimeRateAggregatorFactory) getGroupInfos().get(AbstractGraphConsumer.DEFAULT_GROUP).getAggregatorFactory()) | ||||||
|  |                 .setGranularity(granularity); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     @Override | ||||||
|  |     protected void initializeExtraResults(MapResultData parentResult) { | ||||||
|  |         super.initializeExtraResults(parentResult); | ||||||
|  |         String[] seriesLabels = new String[]{ | ||||||
|  |                 TRANSACTION_SUCCESS_LABEL, TRANSACTION_FAILURE_LABEL | ||||||
|  |         }; | ||||||
|  |         initializeSeries(parentResult, seriesLabels); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  |     private void initializeSeries(MapResultData parentResult, String[] series) { | ||||||
|  |         ListResultData listResultData = (ListResultData) parentResult.getResult("series"); | ||||||
|  |         for (int i = 0; i < series.length; i++) { | ||||||
|  |             listResultData.addResult(create(series[i])); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     private MapResultData create(String serie) { | ||||||
|  |         GroupInfo groupInfo = getGroupInfos().get(AbstractGraphConsumer.DEFAULT_GROUP); | ||||||
|  |         SeriesData seriesData = new SeriesData(groupInfo.getAggregatorFactory(),  | ||||||
|  |                 groupInfo.enablesAggregatedKeysSeries(), false, | ||||||
|  |                 groupInfo.enablesOverallSeries());  | ||||||
|  |         return createSerieResult(serie, seriesData); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -130,6 +130,7 @@ this behaviour, set <code>httpclient.reset_state_on_thread_group_iteration=false | ||||||
| <h3>Report / Dashboard</h3> | <h3>Report / Dashboard</h3> | ||||||
| <ul> | <ul> | ||||||
|     <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>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> | ||||||
| </ul> | </ul> | ||||||
| 
 | 
 | ||||||
| <h3>General</h3> | <h3>General</h3> | ||||||
|  | @ -245,6 +246,7 @@ this behaviour, set <code>httpclient.reset_state_on_thread_group_iteration=false | ||||||
|     <li>Imane Ankhila (iankhila at ahlane.net)</li> |     <li>Imane Ankhila (iankhila at ahlane.net)</li> | ||||||
|     <li>jffagot05 (jffagot05 at gmail.com)</li> |     <li>jffagot05 (jffagot05 at gmail.com)</li> | ||||||
|     <li>Perze Ababa (perze.ababa at gmail.com)</li> |     <li>Perze Ababa (perze.ababa at gmail.com)</li> | ||||||
|  |     <li>Martha Laks (laks.martha at gmail.com)</li> | ||||||
| </ul> | </ul> | ||||||
| <p>We also thank bug reporters who helped us improve JMeter.</p> | <p>We also thank bug reporters who helped us improve JMeter.</p> | ||||||
| <p> | <p> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue