JMeter tips

JMeter tips and tricks scratchpad

NOTE: This project has been developed over several years in my spare time and whilst working for several different clients. This is open source and has no commercial ties to any company I have worked for. Screen shots may reflect this as they are home made and may not be truly representative of a full commercial environment. However, these solutions have been used commercially and are known to work in those environments.

I've been avoiding doing this page (do I really want to give away all my trade secrets!). But this is useful for me just to have a place to dump bits of code and information for all those repetitive tasks that need some bespoke JMeter approach. So here goes.

First, I tend to use Groovy with the JSR223 modules. Note you have to pick the appropriate module, for example the JSR223 POST processor will always be run AFTER any samplers. It wont work as an inline request sampler for example.

Put these extensions under jmeter/lib/ext: jmeter

Before downloading, please read our terms and conditions

To find information on JMeter methods etc. work from this page:

[I'll write this page as things come up] To get to previous results use the prev variable or ctx:


For random numbers you need to initialize the engine just once per thread. I did try one object per instance using global properties but couldn't get it working. I came up with this for thread random object initialization. I did test the output and it does work:

if(vars.getObject('rand') == null)
   r  = new Random(System.currentTimeMillis())
   vars.putObject 'rand',r
   //f.append 'setting random generator\n'

Then go:
rnd = vars.getObject('rand').nextInt(100)


To create a realistic load scenario, with correct ratios of calls, which is easily scalable with jmeter, I use a simple statistical method which allows for an 'all-in-one' script solution. In fact I do use this with enterprise tools for simple services etc. It avoids the need to build complex scenarios (sometimes!)

First step is to organize your script with a selection sampler and a list of if controllers:


The selection sampler does this:

rnd = vars.getObject('rand').nextInt(100)

if (rnd < 4)
   vars.put 'nextPage', 'top'
else if (rnd < 5)
   vars.put 'nextPage', 'search'
else if (rnd < 13)
   vars.put 'nextPage', 'progInfo'
else if (rnd < 67)
   vars.put 'nextPage', 'packs'
else if (rnd < 86)
   vars.put 'nextPage', 'news'
else if (rnd < 93)
   vars.put 'nextPage', 'listings'
   vars.put 'nextPage', 'images'

And then each if controller checks to see whether it's their turn to run:

if condition: ${__javaScript("${nextPage}"=="top")}

So in the above, we will get 4% of calls to top, 1% to search, 8% to progInfo etc.

And to scale this up or down you simply adjust the number of users. This is particularly good for the cloud solution shown elsewhere on this site as you can simply increase the number of injectors to increase the load.

Get the script base directory. useful for saving files to a known location relative to the script rather than the jmeter/bin directory:


System.setProperty('baseDir',FileServer.getFileServer().getBaseDir()) 'baseDir = ' + System.getProperty('baseDir')

Get and put thread variables (and convert to/from integer):

while_counter  = vars.get('while_counter').toInteger() [NOTE: use String.valueOf() for non-integers]

vars.put 'while_counter',Integer.toString(while_counter)

While counter expression:

${__javaScript("${status}"!="DONE" && "${while_counter}"<"${while_limit}")}

Regular expressions to get data out of responses:

1. .*? means everything but not greedy. Everything counts so in this case the quotes are part of the response - the last quote is the end marker in the response for the search (bad eaxmple!)


2. Greedy (I suppose). basic search finds the first match in the middle of those things:


3. This section is here really for me to remember this one. If you want the whole response including ALL lines - (?s) means single line mode and the dot will match everything including line feeds:


4. You can grab multiple items at once with regex like:


That expression in the middle wasn't mine but I've looked it up (of course, the + means 1 or more):

Nonmatching lists are similar to matching lists except that they match a single character not represented by one of the list items. You use an open-nonmatching-list operator represented by `[^'  instead of an open-matching-list operator to start a nonmatching list.

For example, `[^ab]' matches any character except `a' or `b'.


A typical snippet of response from our call is:


The template means the values are then represented as variables as follows:

accesToken: ${tokens_g1}
ssoCode: ${tokens_g3}

So we get ${tokens_g1 = 7y6pgkdx22nhjjyc and ${tokens_g3} = 6f45d2510f4386fc


NOTE: You can do more complex regex expressions and get quite complex pieces of data straight into variables. HOWEVER, I have found that expressions that work under debug conditions (a couple of users whilst you check your scripts) can fail under load. I suspect the regex engine is not perfect, perhaps with memory issues. I find it more reliable to use a basic expression to get the full response and then use groovy code to extract everything you need (use 3. above)

To catch a series of similar values, such as out of a table or from a list of similar embedded urls, use '-1' as follows:


Values can then be grabbed as ${slices_1}, ${slices_2} etc. and the number of values found = ${slices_matchNr)

So we can setup a loop as follows:

//'first slice = ' + vars.get('slices_1'))
//'second slice = ' + vars.get('slices_2'))
//'number of matches = ' + vars.get('slices_matchNr'))

if(vars.get('slices_matchNr').toInteger() <= 0)

vars.put 'sliceNumber', '1'
vars.put 'ourSlice', vars.get('slices_1')

[Couldn't get the ForEach Controller working but have coded one myself with a While Controller:]


Inside the While loop have this somewhere:

maxSlice = vars.get('slices_matchNr').toInteger()
currentSlice = vars.get('sliceNumber').toInteger()
if(currentSlice + 1 > maxSlice)
                vars.put 'sliceNumber', 'Finished'
                vars.put 'sliceNumber', String.valueOf(currentSlice + 1)

Sometimes it can be useful to stop a thread, say if a login has failed. So for instance within an if controller ( condition: ${__javaScript("${JMeterThread.last_sample_ok}" == "false" ) add a JSR223 sampler and from there you can call:


NOTE: SampleResult is only active in the samplers, not the post processors (for example). I found this the hard way, trying to use it in a JSR223 post processor...

in a JS223 post processor you can use:


Note: You can also use the 'Result Status Action Handler' module, say after an assertion on  a specific cookie response header existing for example.

Command line variables are very useful, especially with automated test runs, such as through Jenkins (UPDATE: See here). Set these up as follows and the second argument becomes the default value, for when you are running through the GUI:

Name: env Value: ${__P(env,stage)}

You can then use these in jmeter components with ${__P(variable)}, in this case ${__P(env)} or in scripts with System.getProperty('env')

I want to run a command line and have the output displayed in the response that the tree viewer can pick up. You can run commands with the OS Process sampler of if you want to use a script, use a JS223 Sampler. The following code runs the command and outputs the results to the log file and the response object.

String line;
String output;

output = "";
Process p = Runtime.getRuntime().exec("cmd /c c:\\windows\\system32\\shutdown.exe /a");

BufferedReader bri = new BufferedReader (new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader (new InputStreamReader(p.getErrorStream()));
     while ((line = bri.readLine()) != null) {;
       output += line;
     while ((line = bre.readLine()) != null) {;
       output += line;
     output += "\nDone";


Sometimes you need to get cookies as variables:

Use a cookie manager to keep hold of cookies within a thread. Then set this value in the file (and restart JMeter):

# CookieManager behaviour - should Cookies be stored as variables?
# Default is false

Cookies can then be referred to by 'COOKIE_<cookie_name> such as 'cookie My_Identity = ' + vars.get('COOKIE_My_Identity')

And to use an assertion to check that this cookie has been set in the response, check for response headers containing: My_Identity. The result of this could be used to trigger other activities.

Base64 encoding and decoding in JMeter:

Cookies and other bits and pieces are often encoded and you need to get into them or build them. Very common with web services for example.

I have two versions of these methods. Don't know why. Here they are with output shown below:

Version 1 'cookie C4_Identity = ' + vars.get('COOKIE_C4_Identity')

import org.apache.commons.codec.binary.Base64

def data = '{\"displayName\":\"Nick\",\"gender\":\"MALE\",\"age\":\"38\",\"userId\":\"%s\",\"type\":\"C1\"}'
output = data.getBytes().encodeBase64().toString()

Base64 coder = new Base64()

byte[] backagain = coder.decodeBase64(output)
answer = new String(backagain) data output answer

Version 2
def input = 'Argh, Groovy you say, mate?'
String encoded = input.bytes.encodeBase64().toString()
assert 'QXJnaCwgR3Jvb3Z5IHlvdSBzYXksIG1hdGU/' == encoded
byte[] decoded = encoded.decodeBase64()
output = new String(decoded) input encoded output

Version 1 output
2014/05/08 15:42:45 INFO - {"displayName":"Nick","gender":"MALE","age":"38","userId":"%s","type":"C1"}
2014/05/08 15:42:45 INFO - eyJkaXNwbGF5TmFtZSI6Ik5pY2siLCJnZW5kZXIiOiJNQUxFIiwiYWdlIjoiMzgiLCJ1c2VySWQiOiIlcyIsInR5cGUiOiJDMSJ9
2014/05/08 15:42:45 INFO - {"displayName":"Nick","gender":"MALE","age":"38","userId":"%s","type":"C1"}

Version 2 output
2014/05/08 15:42:45 INFO - Argh, Groovy you say, mate?
2014/05/08 15:42:45 INFO - QXJnaCwgR3Jvb3Z5IHlvdSBzYXksIG1hdGU/
2014/05/08 15:42:45 INFO - Argh, Groovy you say, mate?

Getting environment variables

I developed this method to get environment variables into jmeter, whether in windows or linux. But in the end I used a bespoke file method for my purposes. But I'll leave this here in case it's useful some other time. I haven't used it in earnest so I recommend testing before you rely on it. Also, I'm going to see if I can just provide the raw text. Follow this link and save the response as 'get_and_set_environment_variable.jmx' and then open with jmeter.

Use system property variables in modules

For a standard variable you can just use ${variable} where you want it. For system property variables, use this: ${__P(variable)}. e.g.:



Groovy substrings simple example

Just to jog the memory. Best to look up groovy online for full details and this is not the best groovy code - just a quick example to get you started:'seriesNumber = ' + vars.get('seriesNumber'))'url-on-demand = ' + vars.get('url-on-demand'))
    start = vars.get('url-on-demand').indexOf('/programmes/')'start = ' + start)
    length = vars.get('url-on-demand').length()'length = ' + length)
    enddash = vars.get('url-on-demand').lastIndexOf('/')'enddash = ' + enddash)
    if(enddash == length-1)
       vars.put 'series_url', vars.get('url-on-demand').substring(start+12,length-1)
       vars.put 'series_url', vars.get('url-on-demand').substring(start+12,length)'series_url = ' + vars.get('series_url'))

Here's another example:

    if(start1a >= 0)
       start2a = vars.get('response').indexOf('\\"requestId\\":\\"',end1a)
       if(start2a >= 0)
         //'start2a = ' + start2a)
         end2a = vars.get('response').indexOf('\\"',start2a+16)
         //'end2a = ' + end2a)
         vars.put 'asset2', vars.get('response').substring(start2a+16,end2a)
         //'asset2 = ' + vars.get('asset2'))
         vars.put 'asset2', 'notFound'
         //'asset2 = ' + vars.get('asset2'))

Stop on accumulative error count

Particularly with CI you may want a script to stop if the site starts failing. A couple of response assertions and if controllers do the trick:


1. Make the request.

2. Assert on response code = 200 AND check for error pages (in our app Akamai will return a 200 with a formatted errors page - so I check for [Ee]rror.css, which our various error pages always include)

3. If the last call passes (${__javaScript("${JMeterThread.last_sample_ok}")}), reset the error count in the sampler: System.setProperty('error_count','0')

4. If the last call fails (${__javaScript("${JMeterThread.last_sample_ok}" == "false")}), increment the error count:

    error_count = System.getProperty('error_count').toInteger()


5. And then check if we have a run of errors and we need to stop:

    if(error_count == 6)
       System.out.printf("error_count = %s: . Stopping.",System.getProperty('error_count'))


Print to stdout (and the Jenkins console in particular)

In a JSR223 (language = 'groovy') sampler, printf should print to stdout. And it does appear to work if running in standard gui mode. However, when running from Jenkins, the output wasn't showing in the console output screen.

To get output to the Jenkins console use System.out.printf. e.g.:

    def now = Calendar.getInstance()
    iteration = System.getProperty('iteration').toInteger()

    if(iteration % 100 == 0)
       System.out.printf("iteration = %s: ",System.getProperty('iteration'))
       System.out.println now.format( "yyyy-MM-dd HH:mm:ss")


Stop the test script if it runs past a certain system time

I have been running some long running tests to check urls slowly over time. But my environment is torn down in the evening, so I want the script to stop if it goes past a certain time of day. In this case 6pm:

    def now = Calendar.getInstance()
    hour = now.format( "HH")
    //"hour = " + hour)
    if( hour == "18")
       System.out.printf("hour = %s: . Stopping.",hour)"Stopping due to hour")

Most reliable way to print last request values to log (or bespoke file)

I wanted to keep an eye my results as a small simple script was running. I wanted response code and response time to the jmeter log. You can use SampleResult or 'prev' but I have found the most reliable way to be 'ctx':"Response code = " + ctx.getPreviousResult().getResponseCode() + ", Response time = " + Long.toString(ctx.getPreviousResult().getTime()) + ", Response size = " + Integer.toString(ctx.getPreviousResult().getBytes()) + " bytes")


Edit a URL to replace a date with a recent relative date

So, I've got a file full of dated URLs and I need to keep them up-to-date so my test script keeps working over time. Two main things needed here:

    1. Calculation of relative dates
    2. String replacement the easy way in java

For relative dates you can use this (note I have used my random object to set number of days to go back):

    import java.util.Date;
    import java.util.Calendar;
    import java.text.SimpleDateFormat;

    rnd = vars.getObject('rand').nextInt(28)
    back = -rnd - 1

    Calendar cal = Calendar.getInstance();   // GregorianCalendar

    cal.add(Calendar.DAY_OF_YEAR, back);

    year = cal.get(Calendar.YEAR).toString()
    month = (cal.get(Calendar.MONTH) + 1).toString()
    day = cal.get(Calendar.DAY_OF_MONTH).toString()

And for replacing the various elements in the URLs, I have used a standard java method. Note that in my case, all the dates in my URLs are hard coded with the same value (2014/08/31). This makes it easier but you may have to be a bit more clever to get the various parts of the date in the URL:

    //WATCH OUT - data is hard coded with 2014/08/31. ASSUMING 08 wont be in year and 31 wont be in year or month
    vars.put 'url-catchup-edited',vars.get('url-catchup').replaceFirst('2014',year).replaceFirst('08',month).replaceFirst('31',day)

Input of this:


Goes to something like this (11 days ago):



Add headers programmatically

For this to work you MUST already have an HTTP Header Manager in the script and you MUST use a Pre-Processor sampler, otherwise the sampler element doesn't work. So, add a JSR223 PreProcessor to your script just before the request you want to add the header to. I use the groovy language. And the script is as follows:

(Note the removeHeaderNamed() call as well - this can stop headers building up):

    import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
    import org.apache.jmeter.protocol.http.control.HeaderManager;
    import org.apache.jmeter.protocol.http.control.Header;
    String NA=sampler.getName();
    String VU=ctx.getThreadGroup().getName() + ctx.getThreadNum();
    String ending="Roo9Ut2futhiheD5Aik44rtpu"
    if(sampler instanceof HTTPSamplerBase)

     HeaderManager hm = sampler.getHeaderManager();

     Header h = new Header("X-C9-Feed-Key-Go","PaasliekuaSie4im3niefaD6g" + ending);




(Thanks must go to the Compuware Dynatrace community forum for this snippet, although I am using it for other purposes above. For dynatrace, you would use: Header h = new Header("dynaTrace","PC=JMETER;NA=" + NA + ";VU=" +VU); Compuware Dynatrace offer conversion routines to do all this for you if required.)

NOTE: The pre-processor is called for every sampler in scope. So if you only want to add this header for one of the underlying calls (or to avoid trying to add a header to your JSR223 samplers!), use the following:

    if(NA == 'brands-request')
       if(sampler instanceof HTTPSamplerBase)
             HeaderManager hm = sampler.getHeaderManager();
             ... ... ... ...

Get the thread name and run code for one thread only

I want to run a server monitor on one thread only (and from one injector only)

The injector number I can get from my initialization code - I store the number on the file system - this can be seen in the example script (link at the top of this page: JMeter Cloud )

For the thread, I use native java code to get the thread name and then filter on that name. Threads in JMeter are called things like: 'Thread Group 1-1', 'Thread Group 1-2' etc.


    String thread = Thread.currentThread().getName()
    if(thread.endsWith("-1") && (System.getProperty('injectorNo') == '0' || System.getProperty('injectorNo') == '1') )
    {'RUN THIS CODE');

Note: injectorNo is set to zero when I am running locally and counts up from 1 when in the cloud.

Output from Jmeter from this code looks like:

    2014/09/16 17:09:25 INFO - jmeter.threads.ThreadGroup: Started thread group number 1
    2014/09/16 17:09:25 INFO - jmeter.engine.StandardJMeterEngine: All thread groups have been started
    2014/09/16 17:09:25 INFO - RUN THIS CODE
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread finished: Thread Group 1-1
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread started: Thread Group 1-2
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread finished: Thread Group 1-2
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread started: Thread Group 1-3
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread finished: Thread Group 1-3
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread started: Thread Group 1-4
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread finished: Thread Group 1-4
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread started: Thread Group 1-5
    2014/09/16 17:09:25 INFO - jmeter.threads.JMeterThread: Thread finished: Thread Group 1-5


Basic authentication with jmeter

We want the following header:

    Authentication: Basic username:password

where 'username:password' is base64 encoded.

Put the following code in a JSR223 Pre-processor:

    import org.apache.commons.codec.binary.Base64
    def input = 'admin:myPassword'
    String encoded = input.bytes.encodeBase64().toString()
    vars.put 'encoded', encoded

Then add a header manager as follows:


In some cases this didn't work and I got a 500 error and forbidden. In this case, use the Cookie manager:

This is an example below. NOTE: you do need to set the Domain and path but the values are the same as with the header above:


Basic authentication with other JAVA based test tools

With c based programs (HP LoadRunner for example), we might typically do basic authentication as we do with curl:

$ curl --silent http://raRubDazF97uzJlcXuHLOTzTHvLQxFc6shblpJ87LHzQQFOd:yDMxm41DyU9GGUQDESGQC5yfwydqPgBqgeZrNZ5eoXXwRCLDZ8@pri

in this case we construct the URL to include the basic authentication:

And in Loadrunner we can simply construct the URL with this information in it.

However, with java programs (well jmeter and a fellow test team had the same issue with neoload) I found I couldn't build the URL with the extra 'username:password' section within the script - I think the java http functions don't like the extra colon.

So, I looked for a solution and found one on the net that worked in my case:

this is the original raw curl which works (changed for security):

    $ curl --silent http://raRubDazF97uzJlcXuHLOTzTHvLQxFc6shblpJ87LHzQQFOd:yDMxm41DyU9GGUQDESGQC5yfwydqPgBqgeZrNZ5eoXXwRCLD

Encrypt the 'username:password' string in base64 (using the encoding tab (with UTF-8) here) and then


is encrypted to this:


So, change the curl call above to these two lines:


Catching exceptions with try{} catch(){}

You may see some long java errors come through to the jmeter log file and you may want to catch these and do something else, or just stop the log filling up unnecessarily (if the error can't be avoided).

Example error I was having (before finding the problem):

    2014/09/22 14:21:42 INFO  - jmeter.modifiers.JSR223PreProcessor: NA (setting header) = sort out the date
    2014/09/22 14:21:42 ERROR - jmeter.modifiers.JSR223PreProcessor: Problem in JSR223 script  javax.script.ScriptException: javax.script.ScriptException: groovy.lang.MissingMethodException: No signature of method: is applicable for argument types: () values: []
                    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(
                    at javax.script.AbstractScriptEngine.eval(Unknown Source)
                    at org.apache.jmeter.util.JSR223TestElement.processFileOrScript(
                    at org.apache.jmeter.modifiers.JSR223PreProcessor.process(
                    at org.apache.jmeter.threads.JMeterThread.runPreProcessors(
                    at org.apache.jmeter.threads.JMeterThread.process_sampler(
                    at Source)
    Caused by: javax.script.ScriptException: groovy.lang.MissingMethodException: No signature of method: is applicable for argument types: () values: []
                    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(
                    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(
                    ... 7 more
    Caused by: groovy.lang.MissingMethodException: No signature of method: is applicable for argument types: () values: []
                    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(
                    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(
                    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(
                    ... 8 more

So I wrapped my code in a try{} catch(){} block:

      'NA (setting header) = ' + NA)
                 HeaderManager hm = sampler.getHeaderManager();
                Header h = new Header("dynaTrace","PC=JMETER;NA=" + NA + ";VU=" +VU);
                catch (Exception e){
                      'got our error')

And the the log file showed this:

    2014/09/22 14:25:30 INFO  - jmeter.modifiers.JSR223PreProcessor: got our error
    2014/09/22 14:25:30 INFO  - jmeter.modifiers.JSR223PreProcessor: No signature of method: is applicable for argument types: () values: []


[Home] [About (CV)] [Contact Us] [JMeter Cloud] [webPageTest] [_64 images] [asset moniitor] [Linux Monitor] [Splunk ETL] [Splunk API] [AWS bash] [LR Rules OK] [LR Slave] [LR CI Graphs] [LoadRunner CI] [LR CI Variables] [LR Bamboo] [LR Methods] [LR CI BASH] [Bash methods] [Jenkins V2] [Streaming vid] [How fast] [Finding Issues] [Reporting] [Hand over] [VB Scripts] [JMeter tips] [JM bespoke] [JMeter RAW] [Dynatrace] [Documents] [FAQ] [Legal]

In the Cartesian Elements Ltd group of companies