You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jmeter.apache.org by Felix Schumacher <fe...@internetallee.de> on 2014/11/30 22:09:33 UTC

Re: svn commit: r1642603 - in /jmeter/trunk: src/components/org/apache/jmeter/visualizers/backend/ src/components/org/apache/jmeter/visualizers/backend/graphite/ xdocs/usermanual/

Hi Philippe,

a few comments inline.

Am 30.11.2014 um 21:29 schrieb pmouawad@apache.org:
> Author: pmouawad
> Date: Sun Nov 30 20:29:49 2014
> New Revision: 1642603
>
> URL: http://svn.apache.org/r1642603
> Log:
> Bug 57246 - BackendListener : Create a Graphite implementation
> Make reported percentiles configurable
> Compute min and max within sliding window
> Move threads (Users) computing to UserMetric
> Bugzilla Id: 57246
>
> Added:
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java   (with props)
> Modified:
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/graphite/GraphiteBackendListenerClient.java
>      jmeter/trunk/xdocs/usermanual/component_reference.xml
>
> Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java?rev=1642603&r1=1642602&r2=1642603&view=diff
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java (original)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.java Sun Nov 30 20:29:49 2014
> @@ -53,6 +53,7 @@ import org.apache.log.Logger;
>   public abstract class AbstractBackendListenerClient implements BackendListenerClient {
>   
>       private static final Logger LOGGER = LoggingManager.getLoggerForClass();
> +    private UserMetric userMetrics = new UserMetric();
>       
>       private ConcurrentHashMap<String, SamplerMetric> metricsPerSampler = new ConcurrentHashMap<String, SamplerMetric>();
>   
> @@ -117,4 +118,10 @@ public abstract class AbstractBackendLis
>           return metricsPerSampler;
>       }
>   
> +    /**
> +     * @return UserMetric
> +     */
> +    protected UserMetric getUserMetrics() {
> +        return userMetrics;
> +    }
>   }
>
> Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java?rev=1642603&r1=1642602&r2=1642603&view=diff
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java (original)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java Sun Nov 30 20:29:49 2014
> @@ -20,20 +20,19 @@ package org.apache.jmeter.visualizers.ba
>   
>   import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
>   import org.apache.jmeter.samplers.SampleResult;
> +import org.apache.jmeter.util.JMeterUtils;
>   
>   /**
>    * Sampler metric
>    * @since 2.13
>    */
>   public class SamplerMetric {
> -    // Limit to sliding window of 100 values
> -    private DescriptiveStatistics stats = new DescriptiveStatistics(100);
> -    private int success;
> -    private int failure;
> -    private long maxTime=0L;
> -    private long minTime=Long.MAX_VALUE;
> -    private int maxActiveThreads = 0;
> -    private int minActiveThreads = Integer.MAX_VALUE;
> +    private static final int SLIDING_WINDOW_SIZE = JMeterUtils.getPropDefault("backend_metrics_window", 100); //$NON-NLS-1$
> +
> +    // Limit to sliding window of SLIDING_WINDOW_SIZE values
> +    private DescriptiveStatistics responsesStats = new DescriptiveStatistics(SLIDING_WINDOW_SIZE);
> +    private int successes;
I would have named it successCount and failureCount and shouldn't they 
also be windowed, if all other values are?
> +    private int failures;
>       /**
>        *
>        */
> @@ -46,20 +45,15 @@ public class SamplerMetric {
>        */
>       public synchronized void add(SampleResult result) {
>           if(result.isSuccessful()) {
> -            success++;
> +            successes++;
>           } else {
> -            failure++;
> +            failures++;
>           }
>           long time = result.getTime();
> -        int activeThreads = result.getAllThreads();
> -        maxTime = Math.max(time, maxTime);
> -        minTime = Math.min(time, minTime);
> -        maxActiveThreads = Math.max(maxActiveThreads, activeThreads);
> -        minActiveThreads = Math.min(minActiveThreads, activeThreads);
>           if(result.isSuccessful()) {
>               // Should we also compute KO , all response time ?
>               // only take successful requests for time computing
> -            stats.addValue(time);
> +            responsesStats.addValue(time);
>           }
>       }
>       
> @@ -67,14 +61,10 @@ public class SamplerMetric {
>        * Reset metric except for percentile related data
>        */
>       public synchronized void resetForTimeInterval() {
> -        // We don't clear stats as it will slide as per my understanding of
> +        // We don't clear responsesStats nor usersStats as it will slide as per my understanding of
>           // http://commons.apache.org/proper/commons-math/userguide/stat.html
> -        success = 0;
> -        failure = 0;
> -        maxTime=0L;
> -        minTime=Long.MAX_VALUE;
> -        maxActiveThreads = 0;
> -        minActiveThreads = Integer.MAX_VALUE;
> +        successes = 0;
> +        failures = 0;
>       }
>   
>       /**
> @@ -83,7 +73,7 @@ public class SamplerMetric {
>        * @return The arithmetic mean of the stored values
>        */
>       public double getMean() {
> -        return stats.getMean();
> +        return responsesStats.getMean();
>       }
>       
>       /**
> @@ -95,7 +85,7 @@ public class SamplerMetric {
>        *         values.
>        */
>       public double getPercentile(double percentile) {
> -        return stats.getPercentile(percentile);
> +        return responsesStats.getPercentile(percentile);
>       }
>   
>       /**
> @@ -104,7 +94,7 @@ public class SamplerMetric {
>        * @return number of total requests
>        */
>       public int getTotal() {
> -        return success+failure;
> +        return successes+failures;
>       }
>       
>       /**
> @@ -112,8 +102,8 @@ public class SamplerMetric {
>        *
>        * @return number of successful requests
>        */
> -    public int getSuccess() {
> -        return success;
> +    public int getSuccesses() {
> +        return successes;
>       }
>   
>       /**
> @@ -121,43 +111,27 @@ public class SamplerMetric {
>        *
>        * @return number of failed requests
>        */
> -    public int getFailure() {
> -        return failure;
> +    public int getFailures() {
> +        return failures;
>       }
>   
>       /**
> -     * Get the maximal elapsed time for all requests
> +     * Get the maximal elapsed time for requests within sliding window
>        *
>        * @return the maximal elapsed time, or <code>0</code> if no requests have
>        *         been added yet
>        */
> -    public long getMaxTime() {
> -        return maxTime;
> +    public double getMaxTime() {
> +        return responsesStats.getMax();
>       }
>   
>       /**
> -     * Get the minimal elapsed time for all requests
> +     * Get the minimal elapsed time for requests within sliding window
>        *
>        * @return the minTime, or {@link Long#MAX_VALUE} if no requests have been
>        *         added yet
>        */
> -    public long getMinTime() {
> -        return minTime;
> -    }
> -
> -    /**
> -     * @return the max number of active threads for this test run, or
> -     *         <code>0</code> if no samples have been added yet
> -     */
> -    public int getMaxActiveThreads() {
> -        return maxActiveThreads;
> -    }
> -
> -    /**
> -     * @return the min number of active threads for this test run, or
> -     *         {@link Integer#MAX_VALUE} if no samples have been added yet
> -     */
> -    public int getMinActiveThreads() {
> -        return minActiveThreads;
> +    public double getMinTime() {
> +        return responsesStats.getMin();
>       }
>   }
>
> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java?rev=1642603&view=auto
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java (added)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java Sun Nov 30 20:29:49 2014
> @@ -0,0 +1,78 @@
> +/*
> + * 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.visualizers.backend;
> +
> +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
> +import org.apache.jmeter.samplers.SampleResult;
> +import org.apache.jmeter.util.JMeterUtils;
> +
> +/**
> + * User metric
> + * @since 2.13
> + */
> +public class UserMetric {
> +    private static final int SLIDING_WINDOW_SIZE = JMeterUtils.getPropDefault("backend_metrics_window", 100); //$NON-NLS-1$
> +
> +    // Limit to sliding window of SLIDING_WINDOW_SIZE values
> +    private DescriptiveStatistics usersStats = new DescriptiveStatistics(SLIDING_WINDOW_SIZE);
> +    /**
> +     *
> +     */
> +    public UserMetric() {
> +    }
> +
> +    /**
> +     * Add a {@link SampleResult} to be used in the statistics
> +     * @param result {@link SampleResult} to be used
> +     */
> +    public synchronized void add(SampleResult result) {
> +        usersStats.addValue(result.getAllThreads());
> +    }
> +
> +    /**
> +     * Reset metric except for percentile related data
> +     */
> +    public synchronized void resetForTimeInterval() {
> +        // NOOP
> +    }
> +
> +    /**
> +     * @return the max number of active threads for this test run
> +     *          using a sliding window of SLIDING_WINDOW_SIZE
> +     */
> +    public int getMaxActiveThreads() {
> +        return (int) usersStats.getMin();
> +    }
> +
> +    /**
> +     * @return the mean number of active threads for this test run
> +     *          using a sliding window of SLIDING_WINDOW_SIZE
> +     */
> +    public int getMeanActiveThreads() {
> +        return (int) usersStats.getMean();
> +    }
> +
> +    /**
> +     * @return the min number of active threads for this test run
> +     *          using a sliding window of SLIDING_WINDOW_SIZE
> +     */
> +    public int getMinActiveThreads() {
> +        return (int) usersStats.getMax();
> +    }
> +}
>
> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java
> ------------------------------------------------------------------------------
>      svn:mime-type = text/plain
>
> Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/graphite/GraphiteBackendListenerClient.java
> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/graphite/GraphiteBackendListenerClient.java?rev=1642603&r1=1642602&r2=1642603&view=diff
> ==============================================================================
> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/graphite/GraphiteBackendListenerClient.java (original)
> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/graphite/GraphiteBackendListenerClient.java Sun Nov 30 20:29:49 2014
> @@ -18,6 +18,8 @@
>   
>   package org.apache.jmeter.visualizers.backend.graphite;
>   
> +import java.text.DecimalFormat;
> +import java.util.HashMap;
>   import java.util.HashSet;
>   import java.util.List;
>   import java.util.Map;
> @@ -26,6 +28,7 @@ import java.util.concurrent.Executors;
>   import java.util.concurrent.ScheduledExecutorService;
>   import java.util.concurrent.TimeUnit;
>   
> +import org.apache.commons.lang3.StringUtils;
>   import org.apache.jmeter.config.Arguments;
>   import org.apache.jmeter.samplers.SampleResult;
>   import org.apache.jmeter.threads.JMeterContextService;
> @@ -48,7 +51,9 @@ public class GraphiteBackendListenerClie
>       private static final Logger LOGGER = LoggingManager.getLoggerForClass();
>       private static final String DEFAULT_METRICS_PREFIX = "jmeter."; //$NON-NLS-1$
>       private static final String CUMULATED_METRICS = "__cumulated__"; //$NON-NLS-1$
> -    private static final String METRIC_ACTIVE_THREADS = "activeThreads"; //$NON-NLS-1$
> +    private static final String METRIC_MAX_ACTIVE_THREADS = "maxActiveThreads"; //$NON-NLS-1$
> +    private static final String METRIC_MIN_ACTIVE_THREADS = "minActiveThreads"; //$NON-NLS-1$
> +    private static final String METRIC_MEAN_ACTIVE_THREADS = "meanActiveThreads"; //$NON-NLS-1$
>       private static final String METRIC_STARTED_THREADS = "startedThreads"; //$NON-NLS-1$
>       private static final String METRIC_STOPPED_THREADS = "stoppedThreads"; //$NON-NLS-1$
>       private static final String METRIC_FAILED_REQUESTS = "failure"; //$NON-NLS-1$
> @@ -56,10 +61,10 @@ public class GraphiteBackendListenerClie
>       private static final String METRIC_TOTAL_REQUESTS = "total"; //$NON-NLS-1$
>       private static final String METRIC_MIN_RESPONSE_TIME = "min"; //$NON-NLS-1$
>       private static final String METRIC_MAX_RESPONSE_TIME = "max"; //$NON-NLS-1$
> -    private static final String METRIC_PERCENTILE90_RESPONSE_TIME = "percentile90"; //$NON-NLS-1$
> -    private static final String METRIC_PERCENTILE95_RESPONSE_TIME = "percentile95"; //$NON-NLS-1$
> +    private static final String METRIC_PERCENTILE_PREFIX = "percentile"; //$NON-NLS-1$
>       private static final long ONE_SECOND = 1L;
>       private static final int MAX_POOL_SIZE = 1;
> +    private static final String DEFAULT_PERCENTILES = "90;95;99";
In the documentation below you state, that this property will be split 
upon comma. I think the semicolon here is a better choice.
>   
>       private String graphiteHost;
>       private int graphitePort;
> @@ -67,6 +72,7 @@ public class GraphiteBackendListenerClie
>       private String rootMetricsPrefix;
>       private String samplersList = ""; //$NON-NLS-1$
>       private Set<String> samplersToFilter;
> +    private HashMap<String, Float> percentiles;
I would just declare Map<String, Float> instead of the specific HashMap.
>       
>   
>       private GraphiteMetricsSender pickleMetricsManager;
> @@ -93,7 +99,9 @@ public class GraphiteBackendListenerClie
>           }
>           
>           ThreadCounts tc = JMeterContextService.getThreadCounts();
> -        pickleMetricsManager.addMetric(timestamp, CUMULATED_CONTEXT_NAME, METRIC_ACTIVE_THREADS, Integer.toString(tc.activeThreads));
> +        pickleMetricsManager.addMetric(timestamp, CUMULATED_CONTEXT_NAME, METRIC_MIN_ACTIVE_THREADS, Integer.toString(getUserMetrics().getMaxActiveThreads()));
> +        pickleMetricsManager.addMetric(timestamp, CUMULATED_CONTEXT_NAME, METRIC_MAX_ACTIVE_THREADS, Integer.toString(getUserMetrics().getMinActiveThreads()));
> +        pickleMetricsManager.addMetric(timestamp, CUMULATED_CONTEXT_NAME, METRIC_MEAN_ACTIVE_THREADS, Integer.toString(getUserMetrics().getMeanActiveThreads()));
>           pickleMetricsManager.addMetric(timestamp, CUMULATED_CONTEXT_NAME, METRIC_STARTED_THREADS, Integer.toString(tc.startedThreads));
>           pickleMetricsManager.addMetric(timestamp, CUMULATED_CONTEXT_NAME, METRIC_STOPPED_THREADS, Integer.toString(tc.finishedThreads));
>   
> @@ -107,14 +115,16 @@ public class GraphiteBackendListenerClie
>        * @param metric
>        */
>       private void addMetrics(long timestamp, String contextName, SamplerMetric metric) {
> -        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_FAILED_REQUESTS, Integer.toString(metric.getFailure()));
> -        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_SUCCESSFUL_REQUESTS, Integer.toString(metric.getSuccess()));
> +        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_FAILED_REQUESTS, Integer.toString(metric.getFailures()));
> +        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_SUCCESSFUL_REQUESTS, Integer.toString(metric.getSuccesses()));
>           pickleMetricsManager.addMetric(timestamp, contextName, METRIC_TOTAL_REQUESTS, Integer.toString(metric.getTotal()));
> -        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_MIN_RESPONSE_TIME, Long.toString(metric.getMinTime()));
> -        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_MAX_RESPONSE_TIME, Long.toString(metric.getMaxTime()));
> -        // TODO Make this customizable
> -        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_PERCENTILE90_RESPONSE_TIME, Double.toString(metric.getPercentile(90)));
> -        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_PERCENTILE95_RESPONSE_TIME, Double.toString(metric.getPercentile(95)));
> +        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_MIN_RESPONSE_TIME, Double.toString(metric.getMinTime()));
> +        pickleMetricsManager.addMetric(timestamp, contextName, METRIC_MAX_RESPONSE_TIME, Double.toString(metric.getMaxTime()));
> +        for (Map.Entry<String, Float> entry : percentiles.entrySet()) {
> +            pickleMetricsManager.addMetric(timestamp, contextName,
> +                    entry.getKey(),
> +                    Double.toString(metric.getPercentile(entry.getValue().floatValue())));
> +        }
>       }
>   
>       /**
> @@ -135,6 +145,7 @@ public class GraphiteBackendListenerClie
>       public void handleSampleResults(List<SampleResult> sampleResults,
>               BackendListenerContext context) {
>           for (SampleResult sampleResult : sampleResults) {
> +            getUserMetrics().add(sampleResult);
>               if(!summaryOnly && samplersToFilter.contains(sampleResult.getSampleLabel())) {
>                   SamplerMetric samplerMetric = getSamplerMetric(sampleResult.getSampleLabel());
>                   samplerMetric.add(sampleResult);
> @@ -153,6 +164,22 @@ public class GraphiteBackendListenerClie
>           summaryOnly = context.getBooleanParameter("summaryOnly", true);
>           samplersList = context.getParameter("samplersList", "");
>           rootMetricsPrefix = context.getParameter("rootMetricsPrefix", DEFAULT_METRICS_PREFIX);
> +        String percentilesAsString = context.getParameter("percentiles", DEFAULT_METRICS_PREFIX);
> +        String[]  percentilesStringArray = percentilesAsString.split(";");
> +        percentiles = new HashMap<String, Float>(percentilesStringArray.length);
> +        DecimalFormat format = new DecimalFormat("0.##");
> +        for (int i = 0; i < percentilesStringArray.length; i++) {
Any reason for not using for(String percentile: 
percentilesAsString.split(";")) { instead?
Below in the documentation you state, that the property will be split 
upon a comma (",").
> +            if(!StringUtils.isEmpty(percentilesStringArray[i].trim())) {
> +                try {
> +                    Float percentileValue = Float.parseFloat(percentilesStringArray[i].trim());
> +                    percentiles.put(
> +                            METRIC_PERCENTILE_PREFIX+AbstractGraphiteMetricsSender.sanitizeString(format.format(percentileValue)),
> +                            percentileValue);
> +                } catch(Exception e) {
> +                    LOGGER.error("Error parsing percentile:'"+percentilesStringArray[i]+"'");
You could include the exception in the log message.
Do we want to catch any exception here, or just those that get thrown by 
parseFloat?
> +                }
> +            }
> +        }
>           Class<?> clazz = Class.forName(graphiteMetricsSenderClass);
>           this.pickleMetricsManager = (GraphiteMetricsSender) clazz.newInstance();
>           pickleMetricsManager.setup(graphiteHost, graphitePort, rootMetricsPrefix);
> @@ -189,6 +216,7 @@ public class GraphiteBackendListenerClie
>           arguments.addArgument("rootMetricsPrefix", DEFAULT_METRICS_PREFIX);
>           arguments.addArgument("summaryOnly", "true");
>           arguments.addArgument("samplersList", "");
> +        arguments.addArgument("percentiles", DEFAULT_PERCENTILES);
>           return arguments;
>       }
>   }
>
> Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=1642603&r1=1642602&r2=1642603&view=diff
> ==============================================================================
> --- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
> +++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sun Nov 30 20:29:49 2014
> @@ -3402,6 +3402,19 @@ By default, a Graphite implementation is
>    <property name="Async Queue size" required="Yes">Size of the queue that holds the SampleResults while they are processed asynchronously.</property>
>    <property name="Parameters" required="Yes">Parameters of the BackendListenerClient implementation.</property>
>    </properties>
> +
> +
> +     <p>The following parameters apply to the <b>GraphiteBackendListenerClient</b> implementation:</p>
> +
> +    <properties>
> +        <property name="graphiteMetricsSender" required="Yes">org.apache.jmeter.visualizers.backend.graphite.TextGraphiteMetricsSender or org.apache.jmeter.visualizers.backend.graphite.PickleGraphiteMetricsSender</property>
> +        <property name="graphiteHost" required="Yes">Graphite or InfluxDB or CollectD server port</property>
> +        <property name="graphitePort" required="Yes">Graphite or InfluxDB or CollectD server port, defaults to 2003. Note PickleGraphiteMetricsSender can only talk to Graphite server.</property>
> +        <property name="rootMetricsPrefix" required="Yes">Prefix of metrics sent to backend. Defaults to ""jmeter."</property>
> +        <property name="summaryOnly" required="Yes">Only send a summary with no detail. Defaults to true.</property>
> +        <property name="samplersList" required="Yes">Comma separated list of samplers for which you want to report metrics to backend.</property>
You are using a semicolon to separate the property above.

Regards
  Felix

> +        <property name="percentiles" required="Yes">The percentiles you want to send to backend. List must be semicolon separated.</property>
> +    </properties>
>   </component>
>   
>   <a href="#">^</a>
>
>


Re: svn commit: r1642603 - in /jmeter/trunk: src/components/org/apache/jmeter/visualizers/backend/ src/components/org/apache/jmeter/visualizers/backend/graphite/ xdocs/usermanual/

Posted by Philippe Mouawad <ph...@gmail.com>.
On Sunday, November 30, 2014, Felix Schumacher <
felix.schumacher@internetallee.de> wrote:

> Hi Philippe,
>
> a few comments inline.
>
> Am 30.11.2014 um 21:29 schrieb pmouawad@apache.org:
>
>> Author: pmouawad
>> Date: Sun Nov 30 20:29:49 2014
>> New Revision: 1642603
>>
>> URL: http://svn.apache.org/r1642603
>> Log:
>> Bug 57246 - BackendListener : Create a Graphite implementation
>> Make reported percentiles configurable
>> Compute min and max within sliding window
>> Move threads (Users) computing to UserMetric
>> Bugzilla Id: 57246
>>
>> Added:
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java
>>  (with props)
>> Modified:
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/SamplerMetric.java
>>      jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/graphite/GraphiteBackendListenerClient.java
>>      jmeter/trunk/xdocs/usermanual/component_reference.xml
>>
>> Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/AbstractBackendListenerClient.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/AbstractBackendListenerClient.
>> java?rev=1642603&r1=1642602&r2=1642603&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java (original)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/
>> AbstractBackendListenerClient.java Sun Nov 30 20:29:49 2014
>> @@ -53,6 +53,7 @@ import org.apache.log.Logger;
>>   public abstract class AbstractBackendListenerClient implements
>> BackendListenerClient {
>>         private static final Logger LOGGER = LoggingManager.
>> getLoggerForClass();
>> +    private UserMetric userMetrics = new UserMetric();
>>             private ConcurrentHashMap<String, SamplerMetric>
>> metricsPerSampler = new ConcurrentHashMap<String, SamplerMetric>();
>>   @@ -117,4 +118,10 @@ public abstract class AbstractBackendLis
>>           return metricsPerSampler;
>>       }
>>   +    /**
>> +     * @return UserMetric
>> +     */
>> +    protected UserMetric getUserMetrics() {
>> +        return userMetrics;
>> +    }
>>   }
>>
>> Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/SamplerMetric.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/SamplerMetric.java?
>> rev=1642603&r1=1642602&r2=1642603&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>> (original)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/SamplerMetric.java
>> Sun Nov 30 20:29:49 2014
>> @@ -20,20 +20,19 @@ package org.apache.jmeter.visualizers.ba
>>     import org.apache.commons.math3.stat.descriptive.
>> DescriptiveStatistics;
>>   import org.apache.jmeter.samplers.SampleResult;
>> +import org.apache.jmeter.util.JMeterUtils;
>>     /**
>>    * Sampler metric
>>    * @since 2.13
>>    */
>>   public class SamplerMetric {
>> -    // Limit to sliding window of 100 values
>> -    private DescriptiveStatistics stats = new DescriptiveStatistics(100);
>> -    private int success;
>> -    private int failure;
>> -    private long maxTime=0L;
>> -    private long minTime=Long.MAX_VALUE;
>> -    private int maxActiveThreads = 0;
>> -    private int minActiveThreads = Integer.MAX_VALUE;
>> +    private static final int SLIDING_WINDOW_SIZE =
>> JMeterUtils.getPropDefault("backend_metrics_window", 100); //$NON-NLS-1$
>> +
>> +    // Limit to sliding window of SLIDING_WINDOW_SIZE values
>> +    private DescriptiveStatistics responsesStats = new
>> DescriptiveStatistics(SLIDING_WINDOW_SIZE);
>> +    private int successes;
>>
> I would have named it successCount and failureCount and shouldn't they
> also be windowed, if all other values are?


There are windowed through the call of resetForTimenterval no ?

>  +    private int failures;
>>       /**
>>        *
>>        */
>> @@ -46,20 +45,15 @@ public class SamplerMetric {
>>        */
>>       public synchronized void add(SampleResult result) {
>>           if(result.isSuccessful()) {
>> -            success++;
>> +            successes++;
>>           } else {
>> -            failure++;
>> +            failures++;
>>           }
>>           long time = result.getTime();
>> -        int activeThreads = result.getAllThreads();
>> -        maxTime = Math.max(time, maxTime);
>> -        minTime = Math.min(time, minTime);
>> -        maxActiveThreads = Math.max(maxActiveThreads, activeThreads);
>> -        minActiveThreads = Math.min(minActiveThreads, activeThreads);
>>           if(result.isSuccessful()) {
>>               // Should we also compute KO , all response time ?
>>               // only take successful requests for time computing
>> -            stats.addValue(time);
>> +            responsesStats.addValue(time);
>>           }
>>       }
>>       @@ -67,14 +61,10 @@ public class SamplerMetric {
>>        * Reset metric except for percentile related data
>>        */
>>       public synchronized void resetForTimeInterval() {
>> -        // We don't clear stats as it will slide as per my understanding
>> of
>> +        // We don't clear responsesStats nor usersStats as it will slide
>> as per my understanding of
>>           // http://commons.apache.org/proper/commons-math/userguide/
>> stat.html
>> -        success = 0;
>> -        failure = 0;
>> -        maxTime=0L;
>> -        minTime=Long.MAX_VALUE;
>> -        maxActiveThreads = 0;
>> -        minActiveThreads = Integer.MAX_VALUE;
>> +        successes = 0;
>> +        failures = 0;
>>       }
>>         /**
>> @@ -83,7 +73,7 @@ public class SamplerMetric {
>>        * @return The arithmetic mean of the stored values
>>        */
>>       public double getMean() {
>> -        return stats.getMean();
>> +        return responsesStats.getMean();
>>       }
>>             /**
>> @@ -95,7 +85,7 @@ public class SamplerMetric {
>>        *         values.
>>        */
>>       public double getPercentile(double percentile) {
>> -        return stats.getPercentile(percentile);
>> +        return responsesStats.getPercentile(percentile);
>>       }
>>         /**
>> @@ -104,7 +94,7 @@ public class SamplerMetric {
>>        * @return number of total requests
>>        */
>>       public int getTotal() {
>> -        return success+failure;
>> +        return successes+failures;
>>       }
>>             /**
>> @@ -112,8 +102,8 @@ public class SamplerMetric {
>>        *
>>        * @return number of successful requests
>>        */
>> -    public int getSuccess() {
>> -        return success;
>> +    public int getSuccesses() {
>> +        return successes;
>>       }
>>         /**
>> @@ -121,43 +111,27 @@ public class SamplerMetric {
>>        *
>>        * @return number of failed requests
>>        */
>> -    public int getFailure() {
>> -        return failure;
>> +    public int getFailures() {
>> +        return failures;
>>       }
>>         /**
>> -     * Get the maximal elapsed time for all requests
>> +     * Get the maximal elapsed time for requests within sliding window
>>        *
>>        * @return the maximal elapsed time, or <code>0</code> if no
>> requests have
>>        *         been added yet
>>        */
>> -    public long getMaxTime() {
>> -        return maxTime;
>> +    public double getMaxTime() {
>> +        return responsesStats.getMax();
>>       }
>>         /**
>> -     * Get the minimal elapsed time for all requests
>> +     * Get the minimal elapsed time for requests within sliding window
>>        *
>>        * @return the minTime, or {@link Long#MAX_VALUE} if no requests
>> have been
>>        *         added yet
>>        */
>> -    public long getMinTime() {
>> -        return minTime;
>> -    }
>> -
>> -    /**
>> -     * @return the max number of active threads for this test run, or
>> -     *         <code>0</code> if no samples have been added yet
>> -     */
>> -    public int getMaxActiveThreads() {
>> -        return maxActiveThreads;
>> -    }
>> -
>> -    /**
>> -     * @return the min number of active threads for this test run, or
>> -     *         {@link Integer#MAX_VALUE} if no samples have been added
>> yet
>> -     */
>> -    public int getMinActiveThreads() {
>> -        return minActiveThreads;
>> +    public double getMinTime() {
>> +        return responsesStats.getMin();
>>       }
>>   }
>>
>> Added: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/UserMetric.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/UserMetric.java?rev=
>> 1642603&view=auto
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java
>> (added)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/backend/UserMetric.java
>> Sun Nov 30 20:29:49 2014
>> @@ -0,0 +1,78 @@
>> +/*
>> + * 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.visualizers.backend;
>> +
>> +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
>> +import org.apache.jmeter.samplers.SampleResult;
>> +import org.apache.jmeter.util.JMeterUtils;
>> +
>> +/**
>> + * User metric
>> + * @since 2.13
>> + */
>> +public class UserMetric {
>> +    private static final int SLIDING_WINDOW_SIZE =
>> JMeterUtils.getPropDefault("backend_metrics_window", 100); //$NON-NLS-1$
>> +
>> +    // Limit to sliding window of SLIDING_WINDOW_SIZE values
>> +    private DescriptiveStatistics usersStats = new
>> DescriptiveStatistics(SLIDING_WINDOW_SIZE);
>> +    /**
>> +     *
>> +     */
>> +    public UserMetric() {
>> +    }
>> +
>> +    /**
>> +     * Add a {@link SampleResult} to be used in the statistics
>> +     * @param result {@link SampleResult} to be used
>> +     */
>> +    public synchronized void add(SampleResult result) {
>> +        usersStats.addValue(result.getAllThreads());
>> +    }
>> +
>> +    /**
>> +     * Reset metric except for percentile related data
>> +     */
>> +    public synchronized void resetForTimeInterval() {
>> +        // NOOP
>> +    }
>> +
>> +    /**
>> +     * @return the max number of active threads for this test run
>> +     *          using a sliding window of SLIDING_WINDOW_SIZE
>> +     */
>> +    public int getMaxActiveThreads() {
>> +        return (int) usersStats.getMin();
>> +    }
>> +
>> +    /**
>> +     * @return the mean number of active threads for this test run
>> +     *          using a sliding window of SLIDING_WINDOW_SIZE
>> +     */
>> +    public int getMeanActiveThreads() {
>> +        return (int) usersStats.getMean();
>> +    }
>> +
>> +    /**
>> +     * @return the min number of active threads for this test run
>> +     *          using a sliding window of SLIDING_WINDOW_SIZE
>> +     */
>> +    public int getMinActiveThreads() {
>> +        return (int) usersStats.getMax();
>> +    }
>> +}
>>
>> Propchange: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/UserMetric.java
>> ------------------------------------------------------------
>> ------------------
>>      svn:mime-type = text/plain
>>
>> Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/graphite/GraphiteBackendListenerClient.java
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/
>> org/apache/jmeter/visualizers/backend/graphite/
>> GraphiteBackendListenerClient.java?rev=1642603&r1=1642602&
>> r2=1642603&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/graphite/GraphiteBackendListenerClient.java (original)
>> +++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/
>> backend/graphite/GraphiteBackendListenerClient.java Sun Nov 30 20:29:49
>> 2014
>> @@ -18,6 +18,8 @@
>>     package org.apache.jmeter.visualizers.backend.graphite;
>>   +import java.text.DecimalFormat;
>> +import java.util.HashMap;
>>   import java.util.HashSet;
>>   import java.util.List;
>>   import java.util.Map;
>> @@ -26,6 +28,7 @@ import java.util.concurrent.Executors;
>>   import java.util.concurrent.ScheduledExecutorService;
>>   import java.util.concurrent.TimeUnit;
>>   +import org.apache.commons.lang3.StringUtils;
>>   import org.apache.jmeter.config.Arguments;
>>   import org.apache.jmeter.samplers.SampleResult;
>>   import org.apache.jmeter.threads.JMeterContextService;
>> @@ -48,7 +51,9 @@ public class GraphiteBackendListenerClie
>>       private static final Logger LOGGER = LoggingManager.
>> getLoggerForClass();
>>       private static final String DEFAULT_METRICS_PREFIX = "jmeter.";
>> //$NON-NLS-1$
>>       private static final String CUMULATED_METRICS = "__cumulated__";
>> //$NON-NLS-1$
>> -    private static final String METRIC_ACTIVE_THREADS = "activeThreads";
>> //$NON-NLS-1$
>> +    private static final String METRIC_MAX_ACTIVE_THREADS =
>> "maxActiveThreads"; //$NON-NLS-1$
>> +    private static final String METRIC_MIN_ACTIVE_THREADS =
>> "minActiveThreads"; //$NON-NLS-1$
>> +    private static final String METRIC_MEAN_ACTIVE_THREADS =
>> "meanActiveThreads"; //$NON-NLS-1$
>>       private static final String METRIC_STARTED_THREADS =
>> "startedThreads"; //$NON-NLS-1$
>>       private static final String METRIC_STOPPED_THREADS =
>> "stoppedThreads"; //$NON-NLS-1$
>>       private static final String METRIC_FAILED_REQUESTS = "failure";
>> //$NON-NLS-1$
>> @@ -56,10 +61,10 @@ public class GraphiteBackendListenerClie
>>       private static final String METRIC_TOTAL_REQUESTS = "total";
>> //$NON-NLS-1$
>>       private static final String METRIC_MIN_RESPONSE_TIME = "min";
>> //$NON-NLS-1$
>>       private static final String METRIC_MAX_RESPONSE_TIME = "max";
>> //$NON-NLS-1$
>> -    private static final String METRIC_PERCENTILE90_RESPONSE_TIME =
>> "percentile90"; //$NON-NLS-1$
>> -    private static final String METRIC_PERCENTILE95_RESPONSE_TIME =
>> "percentile95"; //$NON-NLS-1$
>> +    private static final String METRIC_PERCENTILE_PREFIX = "percentile";
>> //$NON-NLS-1$
>>       private static final long ONE_SECOND = 1L;
>>       private static final int MAX_POOL_SIZE = 1;
>> +    private static final String DEFAULT_PERCENTILES = "90;95;99";
>>
> In the documentation below you state, that this property will be split
> upon comma. I think the semicolon here is a better choice.


 Good catch, I think also samplelist should be split around semi colon also.

>          private String graphiteHost;
>>       private int graphitePort;
>> @@ -67,6 +72,7 @@ public class GraphiteBackendListenerClie
>>       private String rootMetricsPrefix;
>>       private String samplersList = ""; //$NON-NLS-1$
>>       private Set<String> samplersToFilter;
>> +    private HashMap<String, Float> percentiles;
>>
> I would just declare Map<String, Float> instead of the specific HashMap.

ok

>                private GraphiteMetricsSender pickleMetricsManager;
>> @@ -93,7 +99,9 @@ public class GraphiteBackendListenerClie
>>           }
>>                     ThreadCounts tc = JMeterContextService.
>> getThreadCounts();
>> -        pickleMetricsManager.addMetric(timestamp,
>> CUMULATED_CONTEXT_NAME, METRIC_ACTIVE_THREADS, Integer.toString(tc.
>> activeThreads));
>> +        pickleMetricsManager.addMetric(timestamp,
>> CUMULATED_CONTEXT_NAME, METRIC_MIN_ACTIVE_THREADS, Integer.toString(
>> getUserMetrics().getMaxActiveThreads()));
>> +        pickleMetricsManager.addMetric(timestamp,
>> CUMULATED_CONTEXT_NAME, METRIC_MAX_ACTIVE_THREADS, Integer.toString(
>> getUserMetrics().getMinActiveThreads()));
>> +        pickleMetricsManager.addMetric(timestamp,
>> CUMULATED_CONTEXT_NAME, METRIC_MEAN_ACTIVE_THREADS, Integer.toString(
>> getUserMetrics().getMeanActiveThreads()));
>>           pickleMetricsManager.addMetric(timestamp,
>> CUMULATED_CONTEXT_NAME, METRIC_STARTED_THREADS, Integer.toString(tc.
>> startedThreads));
>>           pickleMetricsManager.addMetric(timestamp,
>> CUMULATED_CONTEXT_NAME, METRIC_STOPPED_THREADS, Integer.toString(tc.
>> finishedThreads));
>>   @@ -107,14 +115,16 @@ public class GraphiteBackendListenerClie
>>        * @param metric
>>        */
>>       private void addMetrics(long timestamp, String contextName,
>> SamplerMetric metric) {
>> -        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_FAILED_REQUESTS, Integer.toString(metric.getFailure()));
>> -        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_SUCCESSFUL_REQUESTS, Integer.toString(metric.getSuccess()));
>> +        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_FAILED_REQUESTS, Integer.toString(metric.getFailures()));
>> +        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_SUCCESSFUL_REQUESTS, Integer.toString(metric.getSuccesses()));
>>           pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_TOTAL_REQUESTS, Integer.toString(metric.getTotal()));
>> -        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_MIN_RESPONSE_TIME, Long.toString(metric.getMinTime()));
>> -        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_MAX_RESPONSE_TIME, Long.toString(metric.getMaxTime()));
>> -        // TODO Make this customizable
>> -        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_PERCENTILE90_RESPONSE_TIME, Double.toString(metric.
>> getPercentile(90)));
>> -        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_PERCENTILE95_RESPONSE_TIME, Double.toString(metric.
>> getPercentile(95)));
>> +        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_MIN_RESPONSE_TIME, Double.toString(metric.getMinTime()));
>> +        pickleMetricsManager.addMetric(timestamp, contextName,
>> METRIC_MAX_RESPONSE_TIME, Double.toString(metric.getMaxTime()));
>> +        for (Map.Entry<String, Float> entry : percentiles.entrySet()) {
>> +            pickleMetricsManager.addMetric(timestamp, contextName,
>> +                    entry.getKey(),
>> +                    Double.toString(metric.
>> getPercentile(entry.getValue().floatValue())));
>> +        }
>>       }
>>         /**
>> @@ -135,6 +145,7 @@ public class GraphiteBackendListenerClie
>>       public void handleSampleResults(List<SampleResult> sampleResults,
>>               BackendListenerContext context) {
>>           for (SampleResult sampleResult : sampleResults) {
>> +            getUserMetrics().add(sampleResult);
>>               if(!summaryOnly && samplersToFilter.contains(
>> sampleResult.getSampleLabel())) {
>>                   SamplerMetric samplerMetric =
>> getSamplerMetric(sampleResult.getSampleLabel());
>>                   samplerMetric.add(sampleResult);
>> @@ -153,6 +164,22 @@ public class GraphiteBackendListenerClie
>>           summaryOnly = context.getBooleanParameter("summaryOnly", true);
>>           samplersList = context.getParameter("samplersList", "");
>>           rootMetricsPrefix = context.getParameter("rootMetricsPrefix",
>> DEFAULT_METRICS_PREFIX);
>> +        String percentilesAsString = context.getParameter("percentiles",
>> DEFAULT_METRICS_PREFIX);
>> +        String[]  percentilesStringArray = percentilesAsString.split(";")
>> ;
>> +        percentiles = new HashMap<String, Float>(percentilesStringArray.
>> length);
>> +        DecimalFormat format = new DecimalFormat("0.##");
>> +        for (int i = 0; i < percentilesStringArray.length; i++) {
>>
> Any reason for not using for(String percentile:
> percentilesAsString.split(";")) { instead?

Because at first I used an array then I changed to map and didn't update
code :)

> Below in the documentation you state, that the property will be split upon
> a comma (",").
>
>> +            if(!StringUtils.isEmpty(percentilesStringArray[i].trim())) {
>> +                try {
>> +                    Float percentileValue = Float.parseFloat(
>> percentilesStringArray[i].trim());
>> +                    percentiles.put(
>> +                            METRIC_PERCENTILE_PREFIX+
>> AbstractGraphiteMetricsSender.sanitizeString(format.format(
>> percentileValue)),
>> +                            percentileValue);
>> +                } catch(Exception e) {
>> +                    LOGGER.error("Error parsing percentile:'"+
>> percentilesStringArray[i]+"'");
>>
> You could include the exception in the log message.

yes

> Do we want to catch any exception here, or just those that get thrown by
> parseFloat?

thrown by parseFloat

>  +                }
>> +            }
>> +        }
>>           Class<?> clazz = Class.forName(graphiteMetricsSenderClass);
>>           this.pickleMetricsManager = (GraphiteMetricsSender)
>> clazz.newInstance();
>>           pickleMetricsManager.setup(graphiteHost, graphitePort,
>> rootMetricsPrefix);
>> @@ -189,6 +216,7 @@ public class GraphiteBackendListenerClie
>>           arguments.addArgument("rootMetricsPrefix",
>> DEFAULT_METRICS_PREFIX);
>>           arguments.addArgument("summaryOnly", "true");
>>           arguments.addArgument("samplersList", "");
>> +        arguments.addArgument("percentiles", DEFAULT_PERCENTILES);
>>           return arguments;
>>       }
>>   }
>>
>> Modified: jmeter/trunk/xdocs/usermanual/component_reference.xml
>> URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/usermanual/
>> component_reference.xml?rev=1642603&r1=1642602&r2=1642603&view=diff
>> ============================================================
>> ==================
>> --- jmeter/trunk/xdocs/usermanual/component_reference.xml (original)
>> +++ jmeter/trunk/xdocs/usermanual/component_reference.xml Sun Nov 30
>> 20:29:49 2014
>> @@ -3402,6 +3402,19 @@ By default, a Graphite implementation is
>>    <property name="Async Queue size" required="Yes">Size of the queue
>> that holds the SampleResults while they are processed
>> asynchronously.</property>
>>    <property name="Parameters" required="Yes">Parameters of the
>> BackendListenerClient implementation.</property>
>>    </properties>
>> +
>> +
>> +     <p>The following parameters apply to the <b>
>> GraphiteBackendListenerClient</b> implementation:</p>
>> +
>> +    <properties>
>> +        <property name="graphiteMetricsSender" required="Yes">org.apache.
>> jmeter.visualizers.backend.graphite.TextGraphiteMetricsSender or
>> org.apache.jmeter.visualizers.backend.graphite.
>> PickleGraphiteMetricsSender</property>
>> +        <property name="graphiteHost" required="Yes">Graphite or
>> InfluxDB or CollectD server port</property>
>> +        <property name="graphitePort" required="Yes">Graphite or
>> InfluxDB or CollectD server port, defaults to 2003. Note
>> PickleGraphiteMetricsSender can only talk to Graphite server.</property>
>> +        <property name="rootMetricsPrefix" required="Yes">Prefix of
>> metrics sent to backend. Defaults to ""jmeter."</property>
>> +        <property name="summaryOnly" required="Yes">Only send a summary
>> with no detail. Defaults to true.</property>
>> +        <property name="samplersList" required="Yes">Comma separated
>> list of samplers for which you want to report metrics to backend.</property>
>>
> You are using a semicolon to separate the property above.
>
> Regards
>  Felix
>
>  +        <property name="percentiles" required="Yes">The percentiles you
>> want to send to backend. List must be semicolon separated.</property>
>> +    </properties>
>>   </component>
>>     <a href="#">^</a>
>>
>>
>>
>

-- 
Cordialement.
Philippe Mouawad.