Skip to content

JSR223

There are two types of JSR223:

  • Actions: can be dropped anywhere,
  • Pre/Post processors: can be dropped under HTTP Request Actions. These are like JSR223 actions but executed right before or after the enclosing HTTP action.

If you're looking for examples, make sure to also check our samples page.

Purpose

As OctoPerf is a GUI driven tool, you might encounter some limitation. The JSR223 component opens a new world of possibilities by giving you control of everything through a script:

  • Concatenate values
  • Find the next working day
  • Manipulate variables

Configuration

JSR223 Action

Parameter name Description Required
Name Descriptive name for this script. No
Language All languages supported by JMeter out of the box are also currently supported by OctoPerf. Yes
Parameters Values to be passed to the script, space separated. Automatically split into an array of strings namedargs[] No
Script The script executed each time the Virtual User comes to this action. Yes
File If provided, will override the Script with the content of the file. No

Tip

JSR223 Action are samplers, and as such have an Ok/Ko result and a response time. If you do not want any of this, you can add the following inside the JSR223 action: SampleResult.setIgnore();.

Language

The JSR223 allows you to execute a script, written in various languages: JSR223 Language

More information is available in the JMeter documentation.

Note

In this page, we will focus on Groovy, Java and JavaScript as they are the most common languages.

Parameters

Let's take an example to understand how these work:

jsr223-parameters

We have 3 parameters, separated by spaces:

  • first
  • second
  • last

Script and its resulting log messages

log.info("Number of parameters: " + args.length)
log.info("Parameters array: " + args)
log.info("All parameters: " + Parameters)
log.info("First parameter: " + args[0])
log.info("Second parameter: " + args[2])
INFO JSR223: Number of parameters: 3
INFO JSR223: Parameters array: [first, second, last]
INFO JSR223: All parameters: first second last
INFO JSR223: First parameter: first
INFO JSR223: Second parameter: last

Variables

The following variables can be used in any JSR223 script:

name Description Example
ctx Execution context ctx.isSamplingStarted();
vars Variables in the scope vars.get("counter");
props System properties props.get("START.HMS");
log Log messages in the log file log.info("Hello World!");
SampleResult Points to the current SampleResult SampleResult.setIgnore();
OUT Console output OUT.println("Hello World!");
sampler Pointer to the current Sampler. sampler.addArgument("name", "value");

JMeter variables and functions

The underlying JMeter will process variables and functions before passing the script field to the interpreter.

We always cache-compile groovy scripts for performance, and you should be extra careful with that language.

Before and after cache-compilation

int starttime = ${__time()}
int starttime = 1604320548420

It may not seem like much but after this, the cache-compiled version is going to be used for the rest of the test. Which means the date is not updated anymore.

To understand the difference, use the following script, along with a single Parameter ${__time()} :

log.info("Parameter: " + args[0])
log.info("Function : ${__time()}")

If you run it for several iterations, here's the result:

INFO Parameter: 1646063858453
INFO Function : 1646063858453
INFO Parameter: 1646063860128
INFO Function : 1646063858453
INFO Parameter: 1646063860515
INFO Function : 1646063858453

We clearly see that on iteration 1 both times are identical and accurate, but as further iterations go, only the parameter is updated.

In these situations here are some scripted alternatives:

Action type Raw Groovy Cache-compiled Groovy
Variable use ${myvar} vars.get(myvar)
Functions ${__time()} Pass ${__time()} as a Parameter

Warning

Additionally, a function even if commented out in your script might cause an error if it is not properly configured. The reason being that JMeter will process it before the script is interpreted, not knowing if it is commented out.

Pre/Post processors

Order

Script processors can be attached to a request, in which case the order of actions will be:

  • Pre-processors from top to bottom
  • HTTP Request
  • Post processors from top to bottom

Here's an example with a bunch of processors:

jsr223-processors

Each processor will log its name to the standard log, and the result is:

Processors order log

ERROR o.a.j.m.J.77b6b9ab-54b7-40be-a219-f3cefa0a0f62: Pre Processor 1
ERROR o.a.j.m.J.ab0724ab-6845-4ef9-aa05-52d75ab18e3f: Pre Processor 2
INFO o.a.j.r.Summariser: summary =      1 in 00:00:01 =    0.8/s Avg:   186 Min:   186 Max:   186 Err:     1 (100.00%)
ERROR o.a.j.e.J.e00f2117-6910-4298-89ab-c384dfc50d6c: Post Processor 1
ERROR o.a.j.e.J.5b3e7453-7082-417f-a79a-3724e75768fc: Post Processor 2
ERROR o.a.j.e.J.1a99c95a-265c-4156-8083-6ce438b3e91b: Post Processor 3

Scope

Processors will apply to all the requests that are at the same level than them or below.

To fully understand the meaning of this sentence, we need to understand that these situations are equivalent:

Identical situations

jsr223-processors-scope1

jsr223-processors-scope2

jsr223-processors-scope3

Since there's only one request on the same level or one level below in all these situations it doesn't matter where the processor is.

And another example where the situation is not equivalent:

Different situations

jsr223-processors-scope4

Here the processor applies only to the first request, but if we move it at the same level then it applies to both:

jsr223-processors-scope5

What can be counter intuitive is that its vertical position doesn't matter (it could be first or last, the effect would be the same), only its horizontal (indentation) position enters into account.

Best practices

Script actions can drastically increase the weight of your virtual users, try to use them sparingly. You have to remember that they will be executed by every virtual user, every iteration, and so their effects multiply quickly.

For reference, we place 1000 virtual user on each load generator in a standard OctoPerf test. On fast paced tests that means your JSR223 scripts could run thousands of times per minute.

Use groovy

Use Groovy because it's the only language that can be compiled in JMeter. That makes it far more efficient than all others.

Beware of processor placement

processor-placement

Do not use Pre/Post processors at the root level of your virtual user, otherwise they would be executed for EVERY sampler, including resources and third party calls.

If you have to do it anyway, keep it as simple as possible, a one line script can already slow down your execution significantly. Especially in combination with one of the other topics below.

Don't reinvent the wheel

groovy-http-request

Avoid Actions that can be performed by other well optimized samplers/processors.

Also check if a function exists that could answer your need. And remember that functions can be passed as parameters to avoid cache effects.

Avoid disk operations

Disk Read/Write operations can quickly overload the hard drive of the load generators. They are optimized to provide a lot of CPU and memory but the hard drive is usually not efficient enough for hundreds of read/write operations per second.

It is even worse when you write from the same file in every virtual user. You're likely to get a lot of write wait time because the file can only be accessed by one of the virtual users at a time. In that case all other users wait in line to access it and write their changes.

Disable logging

excessive-logging

Excessive logging can also overload the hard drive, even when it doesn't it will still slow down your hit rate significantly. But most importantly we only store up to 100 Mb of zipped test logs. So if you go over this limit the test log will not be stored in OctoPerf's report at all.

Do not load large files

Avoid loading huge quantity of data in memory. For example large files or functions like prev.getResponseDataAsString().

You can generate an important memory overhead quickly since it will be multiplied by the number of concurrent users doing so. This can also overload the CPU if the worst happens and the Heap memory is overloaded.

No dependence on third parties

Avoid sending calls over the network like fetching a value from a 3rd party. If there's any issue, the call may fail thus creating a huge waiting time and you will have a hard time debugging that.

It's easier to do these things once before or after the test and to isolate them into a setup or teardown thread. This way you can tell when they are failing and they won't impact your test as much.

Be careful of the usual suspects

for-in-while

Pay attention to loops and other pieces of code that require a long execution time, they can also slow down the hit rate of your virtual users significantly.

Especially in combination with one of the other items above.