Skip to content


There are two types of JSR223:

  • Actions: can be dropped anywhere,
  • Pre/Post processors: can be dropped under HTTP Request Actions.

JSR223 Pre/Post processors

These are like JSR223 actions but executed right before or after the enclosing HTTP action.

JSR223 Action

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

More information is available in the JMeter documentation.

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
Script The script executed each time the Virtual User comes to ths action. Yes

JSR223 Action

The following table described some of most importable global script variables already defined:

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"Hello World!");
SampleResult Points to the current SampleResult SampleResult.getLatency();
OUT Console output OUT.println("Hello World!");

If you need more information about the existing global variables, see the Beanshell Sampler documentation.


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. Of course the prupose of OctoPerf is still to use the graphical interface for most of your scenario. But JSR223 will let you do anything that your application may require:

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

Basic samples

This section lists various samples for JSR223 action scripts that you may need for complex Virtual Users. Note that unless told otherwise they written in Java, so make sure you select this language in your script action.

Log a Message

This script is an example of how to log a message and the logging levels available. Note that the resulting message will be visible in the JMeter log file after the test only."This is the log for INFOR level");
log.warn("This is the log for WARNING level");
log.error("This is the log for ERROR level");

Manipulate a Variable

This script shows how to get variables from outside the script context and put them back afterwards.


String my_var = vars.get("MY_VARIABLE");"The value of my_var is " + my_var);

You'll notice that variables are read and written as strings, so make sure to convert them to the right format before/after using them.


Although vars.put will create the variable if it does not exists, it will not be available in the autocompletion unless you also create it in the variable screen.

Increment an Integer

A simple script to add a value to an integer. This is an interesting example to have since vars.get and vars.put work with strings.

int my_number = vars.get("MY_NUMBER").toInteger();
int new_number = 3;

int add = my_number + new_number;

vars.put("MY_NUMBER", add.toString());

Replace String in a Variable

This quick script will replace a set of chars by another, here \/ is replaced by \:

// Replaces "\/" by "/"


This script puts a random value between 5 and 10 in the variable random:

var random = new java.util.Random().nextInt(6) + 5;
vars.put("random", random.toString());

Log Sampler Info "The Sample Label is : " + SampleResult.getSampleLabel() ); "The Start Time in miliseconds is : " + SampleResult.getStartTime() ); "The Response Code is : " + SampleResult.getResponseCode() ); "The Response Message is : " + SampleResult.getResponseMessage() );

Date and time scripts


This script must be configured with the GROOVY language, it uses the __time function to get the current time:

int starttime = ${__time()};
int duration = 1800000;
int end = starttime + duration;

vars.put("endtime", end.toString());
vars.put("starttime", starttime.toString());


This script must be configured with the GROOVY language, it uses the __timeShift function to create a time stamp:

long timestamp = ${__timeShift(,,,,)};
log.error("Current date in millis: " + timestamp);

String date = "${__timeShift(yyyy/MM/dd,,,,)}";"Current date yyyy/MM/dd: " + date);

String date1 = "${__timeShift(y-MM-dd HH:mm:ss,,,,)}";"Current date y-MM-dd HH:mm:ss: " + date1);

${__timeShift(dd/MM/yyyy,,P1D,, tomorrow)};"Tomorrow: " + "${tomorrow}");

${__timeShift(dd-MM-y-HH-mm-ss,,P1DT3H4M,, tomorrow1)};"Tomorrow +3h4min: " + "${tomorrow1}");

${__timeShift(dd/MM/yyyy,,P-1D,, yesterday)};"Yesterday: " + "${yesterday}");

${__timeShift(dd/MM/yyyy,,P365D,, nextyear)};"Next year: " + "${nextyear}");

${__timeShift(y MMM dd HH:mm:ss,,,fr_FR, localization)};"Current date with localization: " + "${localization}");

${__timeShift(dd/MM/yyyy,30/06/2020,P365D,, nextyear1)};"Next year: " + "${nextyear1}");

Java code

This script puts a timestamp in the variable timestamp. Optional sections allow to add time to the current date or format it differently.

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

Date now = new Date(); // get current time
Calendar c = Calendar.getInstance(); // get Java Calendar instance
c.setTime(now); // set Calendar time to now

//Add 5 minutes to current time
//c.add(Calendar.MINUTE, 5); 

//Get a timestamp
Date now = c.getTimeInMillis(); // get Date value for amended time
String mydate = now.toString();

//OR Create a formatter for date
//Date now = c.getTime();
//SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 
//String mydate = sdf.format(now); // format date as string

vars.put("timestamp",mydate); // save date to JMeter variable named "timestamp"

Next Working Day

This one is a bit more complex. It will create a new date and then proceed to compute the next working day and store it into the nextworkingday variable. This can be usefull when you have to enter an attendance or any work related date in a calendar.

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

public boolean isWorkingDay(Date date, Calendar calendar) {
  // set calendar time with given date
  int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
  // check if it is Saturday(day=7) or Sunday(day=1)
  if ((dayOfWeek ==  7) || (dayOfWeek == 1)) {
    return false;
  return true;  

Calendar c = Calendar.getInstance();
Date now = new Date();

c.add(Calendar.DAY_OF_WEEK, 1);
while(!isWorkingDay(c.getTime(), c)) {
  c.add(Calendar.DAY_OF_WEEK, 1);
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
vars.put("nextworkingday", df.format(c.getTime()));


Because of references to the current sampler, these scripts only works as Pre-processors.


This script adds a cookie named "foo" with the value " bar" for the server "my server".

import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.protocol.http.control.Cookie;

Cookie cookie = new Cookie("foo","bar","my server","/",false,-1);
CookieManager manager = ctx.getCurrentSampler().getProperty("HTTPSampler.cookie_manager").getObjectValue();

Do not store large response contents

Very large response content can have a negative impact on JMeter memory. To minimize it, you can activate the storage of a particular response as a MD5 Hash. Just put a Pre-Processor under your request with this script:


Overwrite a header for all requests

This script allows to overwrite any header, even the user-agent that we normally change at runtime.

Place it as a Pre-processor script at the root level or on the specific requests you want to override:

import org.apache.jmeter.protocol.http.control.Header;
import org.apache.jmeter.protocol.http.control.HeaderManager;

HeaderManager manager = ctx.getCurrentSampler().getHeaderManager();
manager.add(new Header("User-Agent","octoperf-jamg"));


Ignore Http Status Code

Ignore globally

It is possible to ignore an error code (4xx OR 5xx code) by adding the following in a Post-processor script under any request, or at the top level (groovy):


And if you would like to ignore only a specific error code you can do it this way (groovy):

if(prev.getResponseCode() == "404") {

Activable through property

This script allows you to ignore certain errors based on HTTP Response Code:

final String prop = props.get("filterErrors");
final boolean isFilterErrors = prop == null ? true : Boolean.valueOf(prop);

if (isFilterErrors) {
  int responseCode = 200;

  try {
    responseCode = Integer.parseInt(prev.getResponseCode());
  } catch (final NumberFormatException e) {
    // Ignore

  if (responseCode >= 400 && responseCode < 500) {

This script can be enabled / disabled live during the test via JMeter property filterErrors. Set it to:

  • false to disable ignoring errors,
  • true to ignore certain errors again.

Edit sample results

Modifying Current SampleResult

Modifying the current sample result is actually quite simple. It can be useful when you want to programmatically control the response content.

SampleResult.setSampleLabel("This test is modified by JSR223 script");

def start = System.currentTimeMillis(); //return current time in milliseconds
SampleResult.setStartTime(start); // set StartTime"Start Time should be: " + (new Date(start)).toString()); //print the start time in Date format

SampleResult.setResponseMessage("This is message returned from JSR223 script");
SampleResult.setResponseData("You will see this sentence in Response Data tab", "UTF-8");

Read Previous SampleResult

Using the prev variable you can also check the content of the previous sample result:"Thread Group name is: " + prev.getThreadName());

def end_time = prev.getEndTime()"End Time is: " + (new Date(end_time).toString()));"Response Time is: " + prev.getTime().toString());"Connect Time is: " + prev.getConnectTime().toString());"Latency is: " + prev.getLatency().toString());"Size in bytes is: " + prev.getBytesAsLong().toString());"URL is: " + prev.getURL());"The result is passed: " + prev.isSuccessful().toString());"Headers are: " + prev.getResponseHeaders());

Modify Previous SampleResult

And of course you can also edit the previous sample result. Here is an example overriding response times that are over a certain value:

def response_time = prev.getTime().toInteger();

def expected_response_time = 500;

if (response_time > expected_response_time) {
 prev.setSampleLabel("The response time is too long");
 prev.setResponseMessage("The expected response time is : " + expected_response_time + "ms but it took: " + response_time + "ms");

Edit JMeter/JVM settings

Modify HTTP Request

JSR scripts also allow you to edit requests. This is especially useful in specific situations since OctoPerf's interface already allows editing requests:


JMeter Context

This script provides examples of what you can achieve through the ctx variable:"Current Sampler class is: " + ctx.getCurrentSampler());"JMeter Engine class is: " + ctx.getEngine());

log.error("Previous Response Message is: " + ctx.getPreviousResult().getResponseDataAsString());"Previous Response Code is: " + ctx.getPreviousResult().getResponseCode());"Previous Response URL is: " + ctx.getPreviousResult().getURL());"Previous Response Time is: " + ctx.getPreviousResult().getTime());"Previous Domain is: " + ctx.getPreviousSampler().getDomain());"Previous Protocol is: " + ctx.getPreviousSampler().getProtocol());"Previous Port is: " + ctx.getPreviousSampler().getPort());"Previous Method is: " + ctx.getPreviousSampler().getMethod());"Thread Name is: " + ctx.getThread().getThreadName());"Thread Start Time is: " + ctx.getThread().getStartTime());"Thread End Time is: " + ctx.getThread().getEndTime());"Start Next Thread Loop on Error: " + ctx.getThreadGroup().getOnErrorStartNextLoop());"Stop Test on Error: " + ctx.getThreadGroup().getOnErrorStopTest());

Read Write JMeter Properties

JMeter properties can be edited this way:

props.put("PROPERTY_NAME", "VALUE");

//update the existing property

JVM configuration change

As we take care of installing and maintaining the JVM for you, not all the usual settings are available. But some settings can be edited after the JVM is started using this script:

System.setProperty("jsse.enableSNIExtension", "false");


It is also possible to use PRE or POST test SH scripts to interact with the underlying JVM.

Set a proxy for all requests

While the proxy option is not available in OctoPerf, it is still possible to add a proxy to every HTTP request using the following code:

import org.apache.jmeter.ProxyAuthenticator;

System.setProperty("http.proxyHost", "XXX.XXX.XXX.XXX");
System.setProperty("http.proxyPort", "XXXX");
System.setProperty("http.nonProxyHosts", "XXX.XXX.XXX.XXX,XXX.XXX.XXX.XXX");


Note that we do not recommend load testing through a proxy since you will be limited by the proxy capacity. If you proceed with load testing through a proxy, make sure to monitor the proxy server as well.

Write data to a local file

This script allows you to write data to a local file named file.csv. This can be useful if you want to prepare a dataset for a later test or just save information for later use.


The file will be cleaned automatically after the test when we destroy the load generator. But you can use an after test script to upload it to our report engine


BufferedWriter bw = null;
FileWriter fw = null;
String filename="file.csv";
String data="\n"+vars.get("token")+","+vars.get("login")+","+vars.get("password");
File file = new File(filename);

// if file does not exists, then create it
if (!file.exists()) {
fw = new FileWriter(file.getAbsoluteFile(), true);
bw = new BufferedWriter(fw);


Iteration pacing


Since OctoPerf 11.7.0 this feature is natively available from the runtime screen.

Iteration pacing is a good way to make sure every iteration will have the same duration whatever the response time. To implement it, we will use two scripts and a constant variable named pacing that contains the duration of the pacing in milliseconds.

Put a first script at the very beginning of your Virtual user profile:

//Remove current script sampler results from report

Then the last action in your user profile should be a script with:

import java.util.Map;

Map env = System.getenv();

Stopwatch watch = vars.getObject("watch");
long elapsed = watch.elapsed(java.util.concurrent.TimeUnit.MILLISECONDS);
long pacing = Long.parseLong(vars.get("pacing"));

//We do not replay pacing for VU validation
if (elapsed <= pacing && "STANDARD".equals(env.get("TEST_MODE"))) {
    long sleep = pacing-elapsed;
//Remove current script sampler results from report


We use TEST_MODE to ensure the pacing is only used during a real test and not a during a validation.