> OctoPerf load testing - JSR223 Action samples. This page lists all the samples we've collected over the years.

Source: https://api.octoperf.com/doc/design/edit-virtual-user/action-types/jsr223-actions/jsr223-samples/

# JSR223

This page lists **all the script samples that we have collected over the years**. We try to provide alternatives in the various languages supported by JMeter when possible. 
These scripts are tested at regular intervals but if you encounter an issue with one of them, please report it to [support@octoperf.com](mailto:support@octoperf.com).

!!! note
    The Groovy, Java and JavaScript versions are sometimes identical but we provided them all anyway as examples of what can be achieved.
    We recommended Groovy since it is more efficient. In some situations others can work as well, especially for short scripts where efficiency is not critical.

## Basic examples

### 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](https://api.octoperf.com/doc/analysis/edit-bench-report/test-logs/#jmeter-logs) after the test only.

!!! Example "Log a message"

    === "Groovy"
    
        ``` groovy
        log.info("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")
        ```
    
    === "Java"
    
        ``` java
        log.info("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");
        ```
    
    === "JS"
    
        ``` javascript
        log.info("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 JMeter using the `vars` preconfigured [variable](https://api.octoperf.com/doc/design/edit-virtual-user/action-types/jsr223-actions/#variables) and write them back afterwards.

!!! Example "Manipulate a variable"

    === "Groovy"
    
        ``` groovy
        def my_var = vars.get("MY_VARIABLE")
        log.info("The value of my_var is " + my_var)
        vars.put("VARIABLE_NAME","VALUE")
        ```
    
    === "Java"
    
        ``` java
        String my_var = vars.get("MY_VARIABLE");
        log.info("The value of my_var is " + my_var);
        vars.put("VARIABLE_NAME","VALUE");
        ```
    
    === "JS"
    
        ``` javascript
        String my_var = vars.get("MY_VARIABLE");
        log.info("The value of my_var is " + my_var);
        vars.put("VARIABLE_NAME","VALUE");
        ```

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. There's plenty of examples below with integers.

!!! note
    Although `vars.put` will create the variable if it does not exist, it will not be available in the autocompletion unless you also create it in the [variables](https://api.octoperf.com/doc/design/edit-virtual-user/configuration/variables/) 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.

!!! Example "Increment"

    === "Groovy"
    
        ``` groovy
        def my_number = vars.get("MY_NUMBER").toInteger()
        def add = my_number + 3
        vars.put("MY_NUMBER", add.toString())
        ```
    
    === "Java"
    
        ``` java
        int my_number = Integer.parseInt(vars.get("MY_NUMBER"));
        int add = my_number + 3;
        vars.put("MY_NUMBER", add.toString());
        ```
    
    === "JS"
    
        ``` javascript
        var my_number = vars.get("MY_NUMBER");
        var add = my_number + 3;
        vars.put("MY_NUMBER", add);
        ```

### Replace String in a Variable

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

!!! Example "Replace"

    === "Groovy"
    
        ``` groovy
        def my_var = vars.get("MY_VARIABLE")
        vars.put("MY_VARIABLE",my_var.replace("\\/","/"))
        ```
    
    === "Java"
    
        ``` java
        String my_var = vars.get("MY_VARIABLE");
        vars.put("MY_VARIABLE",my_var.replace("\\/","/"));
        ```
    
    === "JS"
    
        ``` javascript
        var my_var = vars.get("MY_VARIABLE");
        vars.put("MY_VARIABLE",my_var.replace("\\/","/"));
        ```

### Random

This script puts a random value **between 50 and 100** in the variable `random`:

!!! Example "Random"

    === "Groovy"
    
        ``` groovy
        def random = new java.util.Random().nextInt(50) + 50
        vars.put("MY_NUMBER", random.toString())
        ```
    
    === "Java"
    
        ``` java
        int random = new java.util.Random().nextInt(50) + 50;
        vars.put("MY_NUMBER", random.toString());
        ```
    
    === "JS"
    
        ``` javascript
        var random = new java.util.Random().nextInt(50) + 50;
        vars.put("MY_NUMBER", random.toString());
        ```

### Log Sampler Info

Using [JMeter's API](https://jmeter.apache.org/api/) it is possible to log information:

!!! Example "Sampler info"

    === "Groovy"
    
        ```groovy
        log.info( "The Sample Label is : " + SampleResult.getSampleLabel() )
        log.info( "The Start Time in miliseconds is : " + SampleResult.getStartTime() )
        log.info( "The Response Code is : " + SampleResult.getResponseCode() )
        log.info( "The Response Message is : " + SampleResult.getResponseMessage() )
        ```
    
    === "Java"
    
        ```java
        log.info( "The Sample Label is : " + SampleResult.getSampleLabel() );
        log.info( "The Start Time in miliseconds is : " + SampleResult.getStartTime() );
        log.info( "The Response Code is : " + SampleResult.getResponseCode() );
        log.info( "The Response Message is : " + SampleResult.getResponseMessage() );
        ```
    
    === "JS"
    
        ```javascript
        log.info( "The Sample Label is : " + SampleResult.getSampleLabel() );
        log.info( "The Start Time in miliseconds is : " + SampleResult.getStartTime() );
        log.info( "The Response Code is : " + SampleResult.getResponseCode() );
        log.info( "The Response Message is : " + SampleResult.getResponseMessage() );
        ```


More options regarding the `SampleResult` class is available in [the API documentation](https://jmeter.apache.org/api/org/apache/jmeter/samplers/SampleResult.html).

## Date and time scripts

### Timestamp, formatting and time offsets

While it is possible to use `__time()` and `__timeShift()` we do not recommend it for [reasons explained in the introduction](https://api.octoperf.com/doc/design/edit-virtual-user/action-types/jsr223-actions/#jmeter-variables-and-functions).
Instead, it is possible to rely on the following code:

!!! Example "Date functions"

    === "Groovy"
    
        ```groovy
        import java.text.SimpleDateFormat
        import java.util.Calendar
        import java.util.Date
    
        def now = new Date()
        def cal = Calendar.getInstance()
        def sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
    
        cal.setTime(now)
        log.error("Timestamp now: " + cal.getTimeInMillis().toString())
    
        cal.add(Calendar.MINUTE, 5)
        log.error("Timestamp in 5 min: " + sdf.format(cal.getTime()))
    
        cal.add(Calendar.DATE, +1)
        log.error("Tomorrow: " + sdf.format(cal.getTime()))
    
        cal.add(Calendar.MONTH, -1)
        log.error("Last month: " + sdf.format(cal.getTime()))
        ```
    
    === "Java"
    
        ```java
        import java.text.SimpleDateFormat;
        import java.util.Calendar;
        import java.util.Date;
    
        Date now = new Date();
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 
    
        cal.setTime(now);
        log.error("Timestamp now: " + cal.getTimeInMillis().toString());
    
        cal.add(Calendar.MINUTE, 5); 
        log.error("Timestamp in 5 min: " + sdf.format(cal.getTime()));
    
        cal.add(Calendar.DATE, +1);
        log.error("Tomorrow: " + sdf.format(cal.getTime()));
    
        cal.add(Calendar.MONTH, -1);
        log.error("Last month: " + sdf.format(cal.getTime()));
        ```

!!! warning
    The dates and times generated in OctoPerf will always be in the [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time)+0 timezone. This way all the load generators share the same time.

### 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.

!!! Example "Next working day"

    === "Java"
    
        ```java
        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
          calendar.setTime(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.setTime(now);
        
        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()));
        ```

### Stop an iteration

You might want to stop an iteration at a certain point in your execution, so that only a portion of your script will be executed.
This script will stop the iteration immediately and start the next one :

!!! Example "Skip to next Iteration"

    === "Groovy"
    
        ``` groovy
        SampleResult.setIgnore()
        ctx.setTestLogicalAction(org.apache.jmeter.threads.JMeterContext.TestLogicalAction.START_NEXT_ITERATION_OF_CURRENT_LOOP)
        ```
    
    === "Java"
    
        ``` java
        SampleResult.setIgnore();
        ctx.setTestLogicalAction(org.apache.jmeter.threads.JMeterContext.TestLogicalAction.START_NEXT_ITERATION_OF_CURRENT_LOOP);
        ```
    
    === "JS"
    
        ``` javascript
        SampleResult.setIgnore();
        ctx.setTestLogicalAction(org.apache.jmeter.threads.JMeterContext.TestLogicalAction.START_NEXT_ITERATION_OF_CURRENT_LOOP);
        ```

### RendezVous

In order to use this script, a property named `startTime` exists. We recommend creating it as part of a [Setup thread](https://api.octoperf.com/doc/runtime/edit-scenario/edit-user-profile/options/setup-teardown/) so that it is the first thing created during the test.

For tests distributed over several load generators, make sure to configure your **Setup Thread** to be **Global** so it is executed only once per test (instead of once per load generator). You will also need to use a [property logic action](https://api.octoperf.com/doc/design/edit-virtual-user/action-types/logic-actions/set-runtime-property-action/) to share the same timestamp to every load generator. Check <a href="https://api.octoperf.com/doc/design/edit-virtual-user/action-types/jsr223-actions/img/SetTime.jmx" download>our example JMX script</a>. 

You then need to pass this timestamp (in ms) as a [parameter](https://api.octoperf.com/doc/design/edit-virtual-user/action-types/jsr223-actions/#parameters) of the following script:

!!! Example "Wait until RendezVous"

    === "Groovy"
    
        ``` groovy
        def now = new Date()
        def elapsed = now.getTime() - props.get("startTime").toLong()
        def wait = args[0].toLong()
        
        Map env = System.getenv()
        
        //We do not replay rendezVous for VU validation
        if (elapsed <= wait && "STANDARD".equals(env.get("TEST_MODE"))) {
            def sleep = wait-elapsed
            Thread.sleep(sleep)
        }
        ```
    
    === "Java"
    
        ``` java
        Date now = new Date();
        long elapsed = now.getTime() - props.get("startTime").toLong();
        long wait = args[0].toLong();
        
        Map env = System.getenv();
        
        //We do not replay rendezVous for VU validation
        if (elapsed <= wait && "STANDARD".equals(env.get("TEST_MODE"))) {
            long sleep = wait-elapsed;
            Thread.sleep(sleep);
        }
        ```

## Pre-processors

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

### Variable number of parameters

Assuming you have extracted multiple occurrences into a variable called `myvar`, this script adds a new parameter to the request for every occurrence:

!!! Example "Add parameter"

    === "Groovy"
    
        ``` groovy
        def max = vars.get("myvar_matchNr").toInteger()
        for (def i : 1..max) {
            def name = "Parameter" + i
            def value = vars.get("myvar_" + i)
            sampler.addArgument(name, value)
        }
        ```
    
    === "Java"
    
        ``` java
        int max = Integer.parseInt(vars.get("myvar_matchNr"));
        for (int i = 1; i <= max; i++) {
            String name = "Parameter" + i;
            String value = vars.get("myvar_" + i);
            sampler.addArgument(name, value);
        }
        ```
    
    === "JS"
    
        ``` javascript
        var max = vars.get("myvar_matchNr");
        for (var i = 1; i <= max; i++) {
            var name = "Parameter" + i;
            var value = vars.get("myvar_" + i);
            sampler.addArgument(name, value);
        }
        ```

### Cookies

This script adds a cookie named "foo" with the value " bar" for the server "my server".
If you leave the [cookie settings](https://api.octoperf.com/doc/runtime/edit-scenario/edit-user-profile/options/device/#cookies) by default, the new value will be picked by the cookie manager and automatically sent in further requests:

!!! Example "Add cookie"

    === "Groovy"
    
        ``` groovy
        import org.apache.jmeter.protocol.http.control.CookieManager
        import org.apache.jmeter.protocol.http.control.Cookie
    
        Cookie cookie = new Cookie("name","value","octoperf.com","/",false,-1)
        CookieManager manager = ctx.getCurrentSampler().getProperty("HTTPSampler.cookie_manager").getObjectValue()
        manager.add(cookie)
        ```
    
    === "Java"
    
        ``` java
        import org.apache.jmeter.protocol.http.control.CookieManager;
        import org.apache.jmeter.protocol.http.control.Cookie;
    
        Cookie cookie = new Cookie("name","value","octoperf.com","/",false,-1);
        CookieManager manager = ctx.getCurrentSampler().getProperty("HTTPSampler.cookie_manager").getObjectValue();
        manager.add(cookie);
        ```


### 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](https://en.wikipedia.org/wiki/MD5#MD5_hashes).
Just put a Pre-Processor under your request with this script:

!!! Example "MD5 Hash"

    === "Groovy"
    
        ``` groovy
        sampler.setMD5(true)
        ```
    
    === "Java"
    
        ``` java
        sampler.setMD5(true);
        ```
    
    === "JS"
    
        ``` javascript
        sampler.setMD5(true);
        ```

!!! warning
    Hashing the response cannot be reversed. Once activated, even the [error table](https://api.octoperf.com/doc/analysis/edit-bench-report/report-items/errors-table/) will only be able to display the hashed body for the response.

### 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:

!!! Example "Replace header"

    === "Groovy"
    
        ``` groovy
        import org.apache.jmeter.protocol.http.control.Header
        import org.apache.jmeter.protocol.http.control.HeaderManager
    
        HeaderManager manager = ctx.getCurrentSampler().getHeaderManager()
        manager.removeHeaderNamed("User-Agent")
        manager.add(new Header("User-Agent","octoperf-jamg"))
        ```
    
    === "Java"
    
        ``` java
        import org.apache.jmeter.protocol.http.control.Header;
        import org.apache.jmeter.protocol.http.control.HeaderManager;
    
        HeaderManager manager = ctx.getCurrentSampler().getHeaderManager();
        manager.removeHeaderNamed("User-Agent");
        manager.add(new Header("User-Agent","octoperf-jamg"));
        ```

!!! warning
    For this script to work, a header manager must exist, so make there is [at least one header](https://api.octoperf.com/doc/design/edit-virtual-user/action-types/http-actions/#request-headers) defined in OctoPerf.

### Modify HTTP Request

OctoPerf's interface already allows editing requests, but JSR scripts can do it as well:

!!! Example "Modify HTTP request"

    === "Groovy"
    
        ```groovy
        sampler.setDomain("petstore.octoperf.com")
        sampler.setProtocol("HTTPS")
        sampler.setMethod("GET")
        sampler.setPort(443)
        sampler.setImplementation("Java")
        ```
    
    === "Java"
    
        ```java
        sampler.setDomain("petstore.octoperf.com");
        sampler.setProtocol("HTTPS");
        sampler.setMethod("GET");
        sampler.setPort(443);
        sampler.setImplementation("Java");
        ```
    
    === "JS"
    
        ```javascript
        sampler.setDomain("petstore.octoperf.com");
        sampler.setProtocol("HTTPS");
        sampler.setMethod("GET");
        sampler.setPort(443);
        sampler.setImplementation("Java");
        ```

## Post-processor

### Ignore Http Status Code

#### Ignore globally

It is possible to ignore an error code (`4xx` OR `5xx` code) with the help of a Post-processor script. This will effectively make the response code `200`:

!!! Example "Ignore error"

    === "Groovy"
    
        ``` groovy
        prev.setResponseOK()
        ```
    
    === "Java"
    
        ``` java
        prev.setResponseOK();
        ```
    
    === "JS"
    
        ``` javascript
        prev.setResponseOK();
        ```

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

!!! Example "Ignore specific error"

    === "Groovy"
    
        ``` groovy
        if(prev.getResponseCode() == "404") {
         prev.setResponseOK()
        }
        ```
    
    === "Java"
    
        ``` java
        if(prev.getResponseCode() == "404") {
         prev.setResponseOK();
        }
        ```
    
    === "JS"
    
        ``` javascript
        if(prev.getResponseCode() == "404") {
         prev.setResponseOK();
        }
        ```

#### Activable through property

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

!!! Example "Activable through property"

    === "Java"
    
        ```java
        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) {
            prev.setResponseOK();
          }
        }
        ```

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.

### Read Previous SampleResult

Using the `prev` variable you can check the content of the previous sample result:

!!! Example "Read previous results"

    === "Groovy"
    
        ```groovy
        log.info("Thread Group name is: " + prev.getThreadName())
        def end_time = prev.getEndTime()
    
        log.info("End Time is: " + (new Date(end_time).toString()))
        log.info("Response Time is: " + prev.getTime().toString())
        log.info("Connect Time is: " + prev.getConnectTime().toString())
        log.info("Latency is: " + prev.getLatency().toString())
        log.info("Size in bytes is: " + prev.getBytesAsLong().toString())
        log.info("URL is: " + prev.getURL())
        log.info("The result is passed: " + prev.isSuccessful().toString())
        log.info("Headers are: " + prev.getResponseHeaders())
        ```
    
    === "Java"
    
        ```java
        log.info("Thread Group name is: " + prev.getThreadName());
        long end_time = prev.getEndTime();
    
        log.info("End Time is: " + (new Date(end_time).toString()));
        log.info("Response Time is: " + prev.getTime().toString());
        log.info("Connect Time is: " + prev.getConnectTime().toString());
        log.info("Latency is: " + prev.getLatency().toString());
        log.info("Size in bytes is: " + prev.getBytesAsLong().toString());
        log.info("URL is: " + prev.getURL());
        log.info("The result is passed: " + prev.isSuccessful().toString());
        log.info("Headers are: " + prev.getResponseHeaders());
        ```

### Modify previous SampleResult

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

#### Dynamic change

Here is an example overriding response times that are over a certain value:

!!! Example "Dynamically modify results"

    === "Groovy"
    
        ```groovy
        def response_time = prev.getTime().toInteger()
         
        def expected_response_time = 500
         
        if (response_time > expected_response_time) {
            prev.setResponseMessage("The response time is too long")
            prev.setSuccessful(false)
            prev.setResponseCode("500")
            prev.setResponseData("The expected response time is : " + expected_response_time + "ms but it took: " + response_time + "ms")
        }
        ```
    
    === "Java"
    
        ```java
        long response_time = prev.getTime().toInteger();
         
        long expected_response_time = 500;
         
        if (response_time > expected_response_time) {
            prev.setResponseMessage("The response time is too long");
            prev.setSuccessful(false);
            prev.setResponseCode("500");
            prev.setResponseData("The expected response time is : " + expected_response_time + "ms but it took: " + response_time + "ms");
        }
        ```

!!! warning
    While it is also possible to change the Sample Label we do not recommend it. We use the SampleLabel to tie each sample to its corresponding element in the virtual user tree. Because of this editing the SampleLabel will cause OctoPerf to lose track of this SampleResult.

#### Edit response time

This script will edit the response time to always be *10 sec*:

!!! Example "Edit response time"

    === "Groovy"
    
        ```groovy
        def newTime = new Date()
        
        prev.setStartTime(newTime.getTime())
        prev.setEndTime(newTime.getTime() + 10000)
        ```
    
    === "Java"
    
        ```java
        Date newTime = new Date();
        
        prev.setStartTime(newTime.getTime())
        prev.setEndTime(newTime.getTime() + 10000)
        ```

!!! warning
    While this is a very good way to log a custom value, the original response time will be lost.

## JMeter & environment settings

### JMeter Context

This script provides examples of what you can achieve through the `ctx` variable:

!!! Example "Read from context"

    === "Groovy"
    
        ```Groovy
        log.info("Current Sampler class is: " + ctx.getCurrentSampler())
        log.info("JMeter Engine class is: " + ctx.getEngine())
        log.error("Previous Response Message is: " + ctx.getPreviousResult().getResponseDataAsString())
        log.info("Previous Response Code is: " + ctx.getPreviousResult().getResponseCode())
        log.info("Previous Response URL is: " + ctx.getPreviousResult().getURL())
        log.info("Previous Response Time is: " + ctx.getPreviousResult().getTime())
        log.info("Previous Domain is: " + ctx.getPreviousSampler().getDomain())
        log.info("Previous Protocol is: " + ctx.getPreviousSampler().getProtocol())
        log.info("Previous Port is: " + ctx.getPreviousSampler().getPort())
        log.info("Previous Method is: " + ctx.getPreviousSampler().getMethod())
        log.info("Thread Name is: " + ctx.getThread().getThreadName())
        log.info("Thread Start Time is: " + ctx.getThread().getStartTime())
        log.info("Thread End Time is: " + ctx.getThread().getEndTime())
        log.info("Start Next Thread Loop on Error: " + ctx.getThreadGroup().getOnErrorStartNextLoop())
        log.info("Stop Test on Error: " + ctx.getThreadGroup().getOnErrorStopTest())
        ```
    
    === "Java"
    
        ```java
        log.info("Current Sampler class is: " + ctx.getCurrentSampler());
        log.info("JMeter Engine class is: " + ctx.getEngine());
        log.error("Previous Response Message is: " + ctx.getPreviousResult().getResponseDataAsString());
        log.info("Previous Response Code is: " + ctx.getPreviousResult().getResponseCode());
        log.info("Previous Response URL is: " + ctx.getPreviousResult().getURL());
        log.info("Previous Response Time is: " + ctx.getPreviousResult().getTime());
        log.info("Previous Domain is: " + ctx.getPreviousSampler().getDomain());
        log.info("Previous Protocol is: " + ctx.getPreviousSampler().getProtocol());
        log.info("Previous Port is: " + ctx.getPreviousSampler().getPort());
        log.info("Previous Method is: " + ctx.getPreviousSampler().getMethod());
        log.info("Thread Name is: " + ctx.getThread().getThreadName());
        log.info("Thread Start Time is: " + ctx.getThread().getStartTime());
        log.info("Thread End Time is: " + ctx.getThread().getEndTime());
        log.info("Start Next Thread Loop on Error: " + ctx.getThreadGroup().getOnErrorStartNextLoop());
        log.info("Stop Test on Error: " + ctx.getThreadGroup().getOnErrorStopTest());
        ```
    
    === "JS"
    
        ```javascript
        log.info("Current Sampler class is: " + ctx.getCurrentSampler());
        log.info("JMeter Engine class is: " + ctx.getEngine());
        log.error("Previous Response Message is: " + ctx.getPreviousResult().getResponseDataAsString());
        log.info("Previous Response Code is: " + ctx.getPreviousResult().getResponseCode());
        log.info("Previous Response URL is: " + ctx.getPreviousResult().getURL());
        log.info("Previous Response Time is: " + ctx.getPreviousResult().getTime());
        log.info("Previous Domain is: " + ctx.getPreviousSampler().getDomain());
        log.info("Previous Protocol is: " + ctx.getPreviousSampler().getProtocol());
        log.info("Previous Port is: " + ctx.getPreviousSampler().getPort());
        log.info("Previous Method is: " + ctx.getPreviousSampler().getMethod());
        log.info("Thread Name is: " + ctx.getThread().getThreadName());
        log.info("Thread Start Time is: " + ctx.getThread().getStartTime());
        log.info("Thread End Time is: " + ctx.getThread().getEndTime());
        log.info("Start Next Thread Loop on Error: " + ctx.getThreadGroup().getOnErrorStartNextLoop());
        log.info("Stop Test on Error: " + ctx.getThreadGroup().getOnErrorStopTest());
        ```

### Read Write JMeter Properties

JMeter properties can be edited this way:

!!! Example "Properties"

    === "Groovy"
    
        ``` groovy
        props.get("PROPERTY_NAME")
        props.put("PROPERTY_NAME", "VALUE")
        ```
    
    === "Java"
    
        ``` java
        props.get("PROPERTY_NAME");
        props.put("PROPERTY_NAME", "VALUE");
        ```
    
    === "JS"
    
        ``` javascript
        props.get("PROPERTY_NAME");
        props.put("PROPERTY_NAME", "VALUE");
        ```

!!! info
    For a complete list of existing properties, you can use the [Debug action](https://api.octoperf.com/doc/design/edit-virtual-user/action-types/post-processors/debug-action/). Make sure to activate the display of JMeter and/or system properties if you do so.

### 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.
It can be set in a [setup threadgroup](https://api.octoperf.com/doc/runtime/edit-scenario/edit-user-profile/options/setup-teardown/) so that the property is changed once before the test starts:

!!! Example "Proxy"

    === "Groovy"
    
        ``` groovy
        import java.net.Authenticator
        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")
        ```
    
    === "Java"
    
        ``` java
        import java.net.Authenticator;
        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");
        ```

!!! info
    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.

### List environment variables

OctoPerf comes with many preset environment variables. We prefer not to list them since they may change on a regular basis.

But using the following script you can write their names and values to the standard log.

!!! Example "Environment variables"

    === "Groovy"
    
        ``` groovy
        import java.util.Map
    
        Map env = System.getenv()
    
        env.entrySet().forEach(entry -> {
            log.error(entry.getKey() + " " + entry.getValue())
        })
        ```
    
    === "Java"
    
        ``` java
        import java.util.Map;
    
        Map env = System.getenv();
    
        env.entrySet().forEach(entry -> {
            log.error(entry.getKey() + " " + entry.getValue());
        });
        ```

!!! warning
    Environment variables may change all the time with product evolutions, make sure to use them only as a last resort.

## Write data to a local file

The following script examples will allow you to write data into a local file. We do not recommend this practice as it is likely to saturate the write buffer on the disk and will cause your load test to throttle. Use it at your own risk.

!!! warning
    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](https://api.octoperf.com/doc/design/edit-virtual-user/configuration/files/#uploading-a-csv-to-test-logs)

### Groovy

In this first example we write a single value inside a file named `file.csv`

!!! Example "Write single value to a file in groovy"

    ```groovy
    def csv = new File("resources/file.csv")
    csv << "Category: " << vars.get("RandomCategory") << System.getProperty("line.separator")
    ```

In this second example we write a list of values from a post processor using `_matchNr` as the total number of values to write:

!!! Example "Write multiple values to a file in groovy"

    ```groovy
    def csv = new File("resources/file.csv")
    1.upto(vars.get("Category_matchNr") as int, {
      csv << "Category: " << vars.get("Category_$it") << System.getProperty("line.separator")
    })
    ```

### Java

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.


!!! Example "Write to a local file in java"

    ```java
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    
    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()) {
      file.createNewFile();
    }
    fw = new FileWriter(file.getAbsoluteFile(), true);
    bw = new BufferedWriter(fw);
    bw.write(data);
    bw.close();
    ```

## Deprecated

### Iteration pacing

!!! warning
    Since OctoPerf `11.7.0` this feature is natively available [from the runtime screen](https://api.octoperf.com/doc/runtime/edit-scenario/edit-user-profile/options/policies/#pacing).

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.

!!! Example "Pacing"

    Put a first script at the very beginning of your Virtual user profile:
    
    === "Java"
    
        ```java
        import com.google.common.base.Stopwatch;
        vars.putObject("watch",Stopwatch.createStarted());
        //Remove current script sampler results from report
        SampleResult.setIgnore();
        ```
    
    Then the last action in your user profile should be a script with:
    
    === "Java"
    
        ```java
        import com.google.common.base.Stopwatch;
        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;
            Thread.sleep(sleep);
        }
        //Remove current script sampler results from report
        SampleResult.setIgnore();
        ```

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