View | Details | Raw Unified | Return to bug 57516
Collapse All | Expand All

(-)build.properties (+5 lines)
Lines 171-176 Link Here
171
excalibur-pool-instrumented.loc     = ${maven2.repo}/excalibur-pool/excalibur-pool-instrumented/${excalibur-pool-instrumented.version}
171
excalibur-pool-instrumented.loc     = ${maven2.repo}/excalibur-pool/excalibur-pool-instrumented/${excalibur-pool-instrumented.version}
172
excalibur-pool-instrumented.md5     = 1b5425fe0fe63dc67da6fe995db6be31
172
excalibur-pool-instrumented.md5     = 1b5425fe0fe63dc67da6fe995db6be31
173
173
174
freemarker.version          = 2.3.21
175
freemarker.loc               = ${maven2.repo}/org/freemarker/freemarker/${freemarker.version}
176
freemarker.jar               = freemarker-${freemarker.version}.jar
177
freemarker.md5               = bdc6a9d3a41bc13e5965fc06e74c16c2
178
174
# Common file containing both htmlparser and htmllexer jars
179
# Common file containing both htmlparser and htmllexer jars
175
htmlparser.version          = 2.1
180
htmlparser.version          = 2.1
176
htmllexer.loc               = ${maven2.repo}/org/htmlparser/htmllexer/${htmlparser.version}
181
htmllexer.loc               = ${maven2.repo}/org/htmlparser/htmllexer/${htmlparser.version}
(-)build.xml (+3 lines)
Lines 371-376 Link Here
371
    <include name="${lib.dir}/${excalibur-pool-api.jar}"/>
371
    <include name="${lib.dir}/${excalibur-pool-api.jar}"/>
372
    <include name="${lib.dir}/${excalibur-pool-impl.jar}"/>
372
    <include name="${lib.dir}/${excalibur-pool-impl.jar}"/>
373
    <include name="${lib.dir}/${excalibur-pool-instrumented.jar}"/>
373
    <include name="${lib.dir}/${excalibur-pool-instrumented.jar}"/>
374
    <include name="${lib.dir}/${freemarker.jar}"/>
374
    <include name="${lib.dir}/${htmllexer.jar}"/>
375
    <include name="${lib.dir}/${htmllexer.jar}"/>
375
    <include name="${lib.dir}/${htmlparser.jar}"/>
376
    <include name="${lib.dir}/${htmlparser.jar}"/>
376
    <include name="${lib.dir}/${httpclient.jar}"/>
377
    <include name="${lib.dir}/${httpclient.jar}"/>
Lines 446-451 Link Here
446
    <pathelement location="${lib.dir}/${excalibur-pool-api.jar}"/>
447
    <pathelement location="${lib.dir}/${excalibur-pool-api.jar}"/>
447
    <pathelement location="${lib.dir}/${excalibur-pool-impl.jar}"/>
448
    <pathelement location="${lib.dir}/${excalibur-pool-impl.jar}"/>
448
    <pathelement location="${lib.dir}/${excalibur-pool-instrumented.jar}"/>
449
    <pathelement location="${lib.dir}/${excalibur-pool-instrumented.jar}"/>
450
  	<pathelement location="${lib.dir}/${freemarker.jar}"/>
449
    <pathelement location="${lib.dir}/${htmllexer.jar}"/>
451
    <pathelement location="${lib.dir}/${htmllexer.jar}"/>
450
    <pathelement location="${lib.dir}/${htmlparser.jar}"/>
452
    <pathelement location="${lib.dir}/${htmlparser.jar}"/>
451
    <pathelement location="${lib.dir}/${httpclient.jar}"/>
453
    <pathelement location="${lib.dir}/${httpclient.jar}"/>
Lines 2871-2876 Link Here
2871
        <process_jarfile jarname="excalibur-pool-api"/>
2873
        <process_jarfile jarname="excalibur-pool-api"/>
2872
        <process_jarfile jarname="excalibur-pool-impl"/>
2874
        <process_jarfile jarname="excalibur-pool-impl"/>
2873
        <process_jarfile jarname="excalibur-pool-instrumented"/>
2875
        <process_jarfile jarname="excalibur-pool-instrumented"/>
2876
    	<process_jarfile jarname="freemarker"/>
2874
        <process_jarfile jarname="htmllexer"/>
2877
        <process_jarfile jarname="htmllexer"/>
2875
        <process_jarfile jarname="htmlparser"/>
2878
        <process_jarfile jarname="htmlparser"/>
2876
        <process_jarfile jarname="httpclient"/>
2879
        <process_jarfile jarname="httpclient"/>
(-)report_templates/HTML_REPORT.ftl (+240 lines)
Line 0 Link Here
1
<!DOCTYPE html>
2
<#setting number_format="##0">
3
<html lang="en">
4
  <head>
5
    <meta charset="utf-8">
6
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
7
    <meta name="viewport" content="width=device-width, initial-scale=1">
8
    <meta name="description" content="">
9
    <meta name="author" content="">
10
    <script src="./Chart.js"></script>
11
    <link rel="icon" href="../../favicon.ico">
12
13
    <title>Dashboard</title>
14
15
    <!-- Bootstrap core CSS -->
16
		<!-- Latest compiled and minified CSS -->
17
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
18
19
		<!-- Optional theme -->
20
		<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
21
22
    <!-- Custom styles for this template -->
23
    <link href="dashboard.css" rel="stylesheet">
24
25
    <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
26
    <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
27
    <script src="../../assets/js/ie-emulation-modes-warning.js"></script>
28
29
    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
30
    <!--[if lt IE 9]>
31
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
32
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
33
    <![endif]-->
34
  </head>
35
36
  <body>
37
38
    <nav class="navbar navbar-inverse navbar-fixed-top">
39
      <div class="container-fluid">
40
        <div class="navbar-header">
41
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
42
            <span class="sr-only">Toggle navigation</span>
43
            <span class="icon-bar"></span>
44
            <span class="icon-bar"></span>
45
            <span class="icon-bar"></span>
46
          </button>
47
          <a class="navbar-brand" href="#">JMeter Dashboard</a>
48
        </div>
49
50
      </div>
51
    </nav>
52
53
    <div class="container-fluid">
54
      <div class="row">
55
        <div class="col-sm-3 col-md-2 sidebar">
56
          <ul class="nav nav-sidebar">
57
            <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
58
            <li><a href="#">Reports</a></li>
59
            <li><a href="#">Analytics</a></li>
60
            <li><a href="#">Export</a></li>
61
          </ul>
62
        </div>
63
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
64
          <h1 class="page-header">Dashboard</h1>
65
66
          <div class="row placeholders">
67
			<div class="col-md-6">
68
    			<div class="panel panel-default">
69
                	<div class="panel-heading">
70
                  		<h3 class="panel-title">APDEX</h3>
71
                	</div>
72
            	   <div class="panel-body">
73
              		    ${APDEX}
74
                	</div>
75
              	</div>
76
            </div>
77
            <div class="col-md-6">
78
                <div class="panel panel-default">
79
                    <div class="panel-heading">
80
                        <h3 class="panel-title">Requests Summary</h3>
81
                    </div>
82
                    <div class="panel-body">
83
                        <div id="pieChart" style="height:200px"></div>
84
    	               <!--<canvas id="pieChart" height="150" width="300"></canvas>-->
85
            	       <div id="legend"></div>
86
                    </div>
87
        		</div>
88
            </div>
89
90
          <h2 class="sub-header">Statistics</h2>
91
          <div class="table-responsive">
92
            <table class="table table-striped">
93
              <thead>
94
                <tr>
95
                  <th>Label</th>
96
                  <th>#Samples</th>
97
                  <th>KO</th>
98
                  <th>Error%</th>
99
                  <th>90% Line</th>
100
                  <th>95% Line</th>
101
                  <th>99% Line</th>
102
                  <th>Throughput</th>
103
                  <th>KB/sec</th>
104
                  <th>Min</th>
105
                  <th>Max</th>
106
                </tr>
107
              </thead>
108
              <tfoot>
109
                <tr>
110
                  <td>${TOTAL.label}</td>
111
                  <td>${TOTAL.count}</td>
112
                  <td>${TOTAL.errorCount}</td>
113
                  <td>${TOTAL.errorPercentage?string.percent}</td>
114
                  <td>${TOTAL.getPercentPoint(0.9)}</td>
115
                  <td>${TOTAL.getPercentPoint(0.95)}</td>
116
                  <td>${TOTAL.getPercentPoint(0.99)}</td>
117
                  <td>${TOTAL.rate}</td>
118
                  <td>${TOTAL.getKBPerSecond()}</td>
119
                  <td>${TOTAL.min}</td>
120
                  <td>${TOTAL.max}</td>
121
                </tr>
122
              </tfoot>
123
              <tbody>
124
<#list resultsPerSample?keys as key>
125
<#assign prop = resultsPerSample[key]>
126
                <tr>
127
                  <td>${prop.label}</td>
128
                  <td>${prop.count}</td>
129
                  <td>${prop.errorCount}</td>
130
                  <td>${prop.errorPercentage?string.percent}</td>
131
                  <td>${prop.getPercentPoint(0.9)}</td>
132
                  <td>${prop.getPercentPoint(0.95)}</td>
133
                  <td>${prop.getPercentPoint(0.99)}</td>
134
                  <td>${prop.rate}</td>
135
                  <td>${prop.getKBPerSecond()}</td>
136
                  <td>${prop.min}</td>
137
                  <td>${prop.max}</td>
138
                </tr>
139
</#list>
140
              </tbody>
141
            </table>
142
          </div>
143
        </div>
144
      </div>
145
    </div>
146
147
    <!-- Bootstrap core JavaScript
148
    ================================================== -->
149
    <!-- Placed at the end of the document so the pages load faster -->
150
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
151
    <script src="./assets/js/docs.min.js"></script>
152
    <script language="javascript" type="text/javascript" src="./flot/jquery.flot.js"></script>
153
    <script language="javascript" type="text/javascript" src="./flot/jquery.flot.pie.js"></script>
154
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
155
    <script src="./assets/js/ie10-viewport-bug-workaround.js"></script>
156
        <script>
157
158
159
        var pieData = [
160
                {
161
                    data:${TOTAL.errorCount},
162
                    color:"#F7464A",
163
                    highlight: "#FF5A5E",
164
                    label: "KO",
165
                    labelColor : 'white',
166
                    labelFontSize : '16'
167
                },
168
                {
169
                    data:${TOTAL.count - TOTAL.errorCount},
170
                    color: "#46BFBD",
171
                    highlight: "#5AD3D1",
172
                    label: "OK",
173
                    labelColor : 'white',
174
                    labelFontSize : '16'
175
                }
176
            ];
177
            
178
        $.plot('#pieChart', pieData, {
179
    series: {
180
        pie: {
181
            show: true,
182
            radius: 1,
183
            label: {
184
                show: true,
185
                radius: 3/4,
186
                formatter: labelFormatter,
187
                background: {
188
                    opacity: 0.5
189
                }
190
            }
191
        }
192
    },
193
    legend: {
194
        show: true
195
    }
196
});
197
198
    function labelFormatter(label, series) {
199
        return "<div style='font-size:8pt; text-align:center; padding:2px; color:white;'>" + label + "<br/>" + Math.round(series.percent) + "%</div>";
200
    }
201
    </script>
202
    <!--
203
    <script>
204
        var pieData = [
205
                {
206
                    value: ${TOTAL.errorCount},
207
                    color:"#F7464A",
208
                    highlight: "#FF5A5E",
209
                    label: "KO",
210
                    labelColor : 'white',
211
                    labelFontSize : '16'
212
                },
213
                {
214
                    value: ${TOTAL.count - TOTAL.errorCount},
215
                    color: "#46BFBD",
216
                    highlight: "#5AD3D1",
217
                    label: "OK",
218
                    labelColor : 'white',
219
                    labelFontSize : '16'
220
                }
221
            ];
222
223
            window.onload = function(){
224
                var ctx = document.getElementById("pieChart").getContext("2d");
225
                window.myPie = new Chart(ctx).Pie(pieData, 
226
					{
227
    					segmentShowStroke : true,
228
						animateScale: false,
229
						animateRotate : false,
230
						legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
231
232
					});
233
			     $("#legend").html(window.myPie.generateLegend());
234
            };
235
236
    </script>
237
    -->
238
  </body>
239
  
240
</html>
(-)src/components/org/apache/jmeter/visualizers/backend/BackendListener.java (+3 lines)
Lines 169-174 Link Here
169
        BackendListenerContext context = new BackendListenerContext(args);
169
        BackendListenerContext context = new BackendListenerContext(args);
170
170
171
        SampleResult sr = listenerClientData.client.createSampleResult(context, event.getResult());
171
        SampleResult sr = listenerClientData.client.createSampleResult(context, event.getResult());
172
        if(sr == null) {
173
            return;
174
        }
172
        try {
175
        try {
173
            if (!listenerClientData.queue.offer(sr)){ // we failed to add the element first time
176
            if (!listenerClientData.queue.offer(sr)){ // we failed to add the element first time
174
                listenerClientData.queueWaits.incrementAndGet();
177
                listenerClientData.queueWaits.incrementAndGet();
(-)src/components/org/apache/jmeter/visualizers/backend/apdex/ApdexBackendListenerClient.java (+221 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.visualizers.backend.apdex;
20
21
import java.io.BufferedWriter;
22
import java.io.File;
23
import java.io.FileOutputStream;
24
import java.io.OutputStreamWriter;
25
import java.io.Writer;
26
import java.util.HashMap;
27
import java.util.HashSet;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.Set;
31
import java.util.concurrent.atomic.AtomicLong;
32
33
import org.apache.commons.lang3.StringUtils;
34
import org.apache.jmeter.config.Arguments;
35
import org.apache.jmeter.samplers.SampleResult;
36
import org.apache.jmeter.util.JMeterUtils;
37
import org.apache.jmeter.visualizers.SamplingStatCalculator;
38
import org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient;
39
import org.apache.jmeter.visualizers.backend.BackendListenerContext;
40
import org.apache.jorphan.logging.LoggingManager;
41
import org.apache.jorphan.util.JOrphanUtils;
42
import org.apache.log.Logger;
43
44
import freemarker.template.Configuration;
45
import freemarker.template.Template;
46
import freemarker.template.TemplateExceptionHandler;
47
48
/**
49
 * APDEX Computer
50
 * @since 2.13
51
 */
52
public class ApdexBackendListenerClient extends AbstractBackendListenerClient {
53
    private static final Logger LOGGER = LoggingManager.getLoggerForClass();
54
    private static final String SEPARATOR = ";"; //$NON-NLS-1$
55
56
    /**
57
     * T : Threshold for satistied users. 
58
     * Response times <= satisfiedResponseTimeMS count towards satisfying 
59
     */
60
    private long satisfiedResponseTimeMS;
61
    /**
62
     * F : Threshold for tolerated users. 
63
     * Response times > satisfiedResponseTimeMS and <= toleratedResponseTimeMS count towards tolerated response times 
64
     * If user does not provide it, it is equal to 4xT
65
     */
66
    private long toleratedResponseTimeMS;
67
    /**
68
     * Semicolon separated samplers to include in results
69
     */
70
    private String samplersList = ""; //$NON-NLS-1$
71
    /**
72
     * Set of samplers to filter, computed from samplersList
73
     */
74
    private Set<String> samplersToFilter;
75
       
76
    /**
77
     * Number of Successful Responses for samplers in samplersToFilter  with Response Time <= T
78
     */
79
    private AtomicLong numberOfSatistiedResponses = new AtomicLong(0);
80
    /**
81
     * Number of Successful Responses for samplers in samplersToFilter with Response Time > T and <= F
82
     */
83
    private AtomicLong numberOfToleratedResponses = new AtomicLong(0);
84
    /**
85
     * Number of Responses for samplers in samplersToFilter  (OK + KO)
86
     */
87
    private AtomicLong totalResponses = new AtomicLong(0);
88
    private String resultsFile;
89
    private String reportFile;
90
    public ApdexBackendListenerClient() {
91
        super();
92
    } 
93
94
95
    /**
96
     * @return the samplersList
97
     */
98
    public String getSamplersList() {
99
        return samplersList;
100
    }
101
102
    /**
103
     * @param samplersList the samplersList to set
104
     */
105
    public void setSamplersList(String samplersList) {
106
        this.samplersList = samplersList;
107
    }
108
109
    @Override
110
    public void handleSampleResults(List<SampleResult> sampleResults,
111
            BackendListenerContext context) {
112
        // NOOP
113
    }
114
115
    @Override
116
    public void setupTest(BackendListenerContext context) throws Exception {
117
        String satisfiedResponseTimeAsString = context.getParameter("satisfiedResponseTimeMS", "");
118
        if(!StringUtils.isEmpty(satisfiedResponseTimeAsString)) {
119
            try {
120
                satisfiedResponseTimeMS = Long.parseLong(satisfiedResponseTimeAsString);
121
            } catch (Exception e) {
122
                throw new IllegalArgumentException("Error parsing satisfiedResponseTimeMS '"
123
                        +satisfiedResponseTimeAsString+"', message:"+e.getMessage());
124
            }
125
        } else {
126
            throw new IllegalArgumentException("satisfiedResponseTimeMS is null or empty");
127
        }
128
129
        String toleratedResponseTimeAsString = context.getParameter("toleratedResponseTimeMS", "");
130
        if(!StringUtils.isEmpty(toleratedResponseTimeAsString)) {
131
            try {
132
                toleratedResponseTimeMS = Long.parseLong(toleratedResponseTimeAsString);
133
            } catch (Exception e) {
134
                throw new IllegalArgumentException("Error parsing toleratedResponseTimeMS '"
135
                        +satisfiedResponseTimeAsString+"', message:"+e.getMessage());
136
            }
137
        } else {
138
            toleratedResponseTimeMS = 4*satisfiedResponseTimeMS;
139
        }
140
        
141
        samplersList = context.getParameter("samplersList", "");
142
        String[] samplers = samplersList.split(SEPARATOR);
143
        samplersToFilter = new HashSet<String>();
144
        for (String samplerName : samplers) {
145
            samplersToFilter.add(samplerName.trim());
146
        }
147
        
148
        resultsFile = context.getParameter("resultsFile");
149
        reportFile = context.getParameter("reportFile");
150
        
151
        numberOfSatistiedResponses.set(0);
152
        numberOfToleratedResponses.set(0);
153
        totalResponses.set(0);
154
    }
155
156
    @Override
157
    public void teardownTest(BackendListenerContext context) throws Exception {
158
        ReportVisualizer reportVisualizer = new ReportVisualizer(samplersToFilter, satisfiedResponseTimeMS, toleratedResponseTimeMS);
159
        ReportResultCollector collector = new ReportResultCollector();
160
        collector.setFilename(resultsFile);
161
        collector.setListener(reportVisualizer);
162
        collector.loadExistingFile();
163
        Map<String, SamplingStatCalculator> results = reportVisualizer.getResultsPerSampleLabel();
164
        for (Map.Entry<String, SamplingStatCalculator> entry : results.entrySet()) {
165
            System.out.println(entry.getKey()+":"+entry.getValue());
166
        }
167
        generateReport(reportFile, reportVisualizer);
168
        samplersToFilter.clear();
169
        super.teardownTest(context);
170
    }
171
    
172
    private void generateReport(String reportFile, ReportVisualizer reportVisualizer) 
173
        throws Exception {
174
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_21);
175
        cfg.setDirectoryForTemplateLoading(new File(JMeterUtils.getJMeterHome(),"report_templates"));
176
        cfg.setDefaultEncoding("UTF-8");
177
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
178
        Writer writer = null;
179
        try {
180
            //Load template from source folder
181
            Template template = cfg.getTemplate("HTML_REPORT.ftl");
182
             
183
            // Build the data-model
184
            Map<String, Object> data = new HashMap<String, Object>();
185
            data.put("APDEX", "APDEX:"+Float.toString(reportVisualizer.computeApdex()) + " for thresholds T:"+satisfiedResponseTimeMS+"ms, F:"+toleratedResponseTimeMS
186
                    + "ms on samplers:"+samplersToFilter);
187
            Map<String, SamplingStatCalculator> map = reportVisualizer.getResultsPerSampleLabel();
188
            SamplingStatCalculator total = map.get(ReportVisualizer.TOTAL_ROW_LABEL);
189
            data.put("TOTAL", total);
190
            map.remove(ReportVisualizer.TOTAL_ROW_LABEL);
191
            data.put("resultsPerSample", map);
192
            writer = new BufferedWriter(new OutputStreamWriter(
193
                    new FileOutputStream(reportFile), "UTF-8"));
194
            // File output
195
            template.process(data, writer);             
196
        } finally {
197
            JOrphanUtils.closeQuietly(writer);
198
        }
199
    }
200
201
    @Override
202
    public Arguments getDefaultParameters() {
203
        Arguments arguments = new Arguments();
204
        arguments.addArgument("satisfiedResponseTimeMS", "");
205
        arguments.addArgument("toleratedResponseTimeMS", "");
206
        arguments.addArgument("samplersList", "");
207
        arguments.addArgument("resultsFile", "");
208
        arguments.addArgument("reportFile", "");
209
        return arguments;
210
    }
211
212
213
    /* (non-Javadoc)
214
     * @see org.apache.jmeter.visualizers.backend.AbstractBackendListenerClient#createSampleResult(org.apache.jmeter.visualizers.backend.BackendListenerContext, org.apache.jmeter.samplers.SampleResult)
215
     */
216
    @Override
217
    public SampleResult createSampleResult(BackendListenerContext context,
218
            SampleResult result) {
219
        return result;
220
    }
221
}
(-)src/components/org/apache/jmeter/visualizers/backend/apdex/ReportResultCollector.java (+57 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.visualizers.backend.apdex;
20
21
import org.apache.jmeter.reporters.ResultCollector;
22
import org.apache.jmeter.reporters.Summariser;
23
import org.apache.jmeter.samplers.SampleEvent;
24
25
/**
26
 * 
27
 */
28
public class ReportResultCollector extends ResultCollector {
29
30
    /**
31
     * 
32
     */
33
    private static final long serialVersionUID = 4360593252987031579L;
34
35
    /**
36
     * 
37
     */
38
    public ReportResultCollector() {
39
        super();
40
    }
41
42
    /**
43
     * @param summer
44
     */
45
    public ReportResultCollector(Summariser summer) {
46
        super(summer);
47
    }
48
49
    /* (non-Javadoc)
50
     * @see org.apache.jmeter.reporters.ResultCollector#sampleOccurred(org.apache.jmeter.samplers.SampleEvent)
51
     */
52
    @Override
53
    public void sampleOccurred(SampleEvent event) {
54
        super.sampleOccurred(event);
55
    }
56
57
}
(-)src/components/org/apache/jmeter/visualizers/backend/apdex/ReportVisualizer.java (+139 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.visualizers.backend.apdex;
20
21
import java.util.Map;
22
import java.util.Set;
23
import java.util.concurrent.ConcurrentHashMap;
24
import java.util.concurrent.atomic.AtomicLong;
25
26
import org.apache.jmeter.samplers.SampleResult;
27
import org.apache.jmeter.util.JMeterUtils;
28
import org.apache.jmeter.visualizers.SamplingStatCalculator;
29
import org.apache.jmeter.visualizers.gui.AbstractVisualizer;
30
31
/**
32
 * @since 2.13
33
 */
34
public class ReportVisualizer extends AbstractVisualizer {
35
    /**
36
     * 
37
     */
38
    private static final long serialVersionUID = -783284260364641662L;
39
    private final Map<String, SamplingStatCalculator> tableRows =
40
            new ConcurrentHashMap<String, SamplingStatCalculator>();
41
    public final static String TOTAL_ROW_LABEL = JMeterUtils
42
            .getResString("aggregate_report_total_label"); //$NON-NLS-1$
43
    /**
44
     * T : Threshold for satistied users. 
45
     * Response times <= satisfiedResponseTimeMS count towards satisfying 
46
     */
47
    private long satisfiedResponseTimeMS;
48
    /**
49
     * F : Threshold for tolerated users. 
50
     * Response times > satisfiedResponseTimeMS and <= toleratedResponseTimeMS count towards tolerated response times 
51
     * If user does not provide it, it is equal to 4xT
52
     */
53
    private long toleratedResponseTimeMS;
54
55
    /**
56
     * Set of samplers to filter, computed from samplersList
57
     */
58
    private Set<String> samplersToFilter;
59
       
60
    /**
61
     * Number of Successful Responses for samplers in samplersToFilter  with Response Time <= T
62
     */
63
    private AtomicLong numberOfSatistiedResponses = new AtomicLong(0);
64
    /**
65
     * Number of Successful Responses for samplers in samplersToFilter with Response Time > T and <= F
66
     */
67
    private AtomicLong numberOfToleratedResponses = new AtomicLong(0);
68
    /**
69
     * Number of Responses for samplers in samplersToFilter  (OK + KO)
70
     */
71
    private AtomicLong totalResponses = new AtomicLong(0);
72
73
    public ReportVisualizer(Set<String> samplersToFilter,
74
            long satisfiedResponseTimeMS,
75
            long toleratedResponseTimeMS) {
76
        this.samplersToFilter = samplersToFilter;
77
        this.satisfiedResponseTimeMS = satisfiedResponseTimeMS;
78
        this.toleratedResponseTimeMS = toleratedResponseTimeMS;
79
    }
80
81
    @Override
82
    public void add(SampleResult res) {
83
        final String sampleLabel = res.getSampleLabel();
84
        if(!samplersToFilter.contains(sampleLabel)) {
85
            return;
86
        }
87
        SamplingStatCalculator row = null;
88
        row = tableRows.get(sampleLabel);
89
        if (row == null) {
90
            row = new SamplingStatCalculator(sampleLabel);
91
            tableRows.put(row.getLabel(), row);
92
        }
93
        row.addSample(res);
94
        
95
        SamplingStatCalculator tot = tableRows.get(TOTAL_ROW_LABEL);
96
        if (tot == null) {
97
            tot = new SamplingStatCalculator(TOTAL_ROW_LABEL);
98
            tableRows.put(tot.getLabel(), tot);
99
        }
100
        tot.addSample(res);
101
        
102
        totalResponses.incrementAndGet();
103
104
        if(res.isSuccessful()) {
105
            if(res.getTime()<=satisfiedResponseTimeMS) {
106
                numberOfSatistiedResponses.incrementAndGet();
107
            } else if (res.getTime()<=toleratedResponseTimeMS) {
108
                numberOfToleratedResponses.incrementAndGet();
109
            }
110
        }
111
    }
112
113
    public Map<String, SamplingStatCalculator> getResultsPerSampleLabel() {
114
        return tableRows;
115
    }
116
    
117
    @Override
118
    public void clearData() {
119
        tableRows.clear();
120
        tableRows.put(TOTAL_ROW_LABEL, new SamplingStatCalculator(TOTAL_ROW_LABEL));
121
        numberOfSatistiedResponses.set(0);
122
        numberOfToleratedResponses.set(0);
123
        totalResponses.set(0);
124
    }
125
126
    @Override
127
    public String getLabelResource() {
128
        return "TEST";
129
    }
130
131
    /**
132
     * @return float APDEX
133
     * See http://www.apdex.org/overview.html
134
     */
135
    public float computeApdex() {
136
        double apdex = ((double)(numberOfSatistiedResponses.get()+numberOfToleratedResponses.get()/2))/totalResponses.get();
137
        return (float)apdex;
138
    }
139
}

Return to bug 57516