Skip to main content
Back to blog
tutorials 24 February 2020 3 min read (Updated: 27 September 2026)

Log Failed JMeter Responses to a File (Groovy)

A JSR223 PostProcessor in Groovy that writes each failed response (status, body, thread and time) to a text file, and why to switch it off under load.

M

Mark

Performance Testing Expert

When you require a deeper level of logging from Apache JMeter you can use the Groovy programming language and a JSR223 PostProcessor to write the full detail of every failed request to a file.

Technical Approach

The Groovy script below runs after each sample and logs every one that failed — HTTP 4xx and 5xx responses, connection errors that never got an HTTP status at all, and samples failed by an assertion. For each it records:

  • Response code and message
  • Response body content
  • Thread name
  • Sample label
  • Response timestamp (converted to a readable date and time)

Sample Implementation

import org.apache.jmeter.services.FileServer

// Log every failed sample. isSuccessful() is false for HTTP 4xx/5xx, for
// connection errors ("Non HTTP response code: ..."), and for failed assertions.
if (!prev.isSuccessful()) {

    def dateTime = new Date(prev.getTimeStamp()).format("yyyy-MM-dd HH:mm:ss")

    // Build the whole entry first, so it is written in a single call
    def entry = new StringBuilder()
    entry << "=" * 80 << "\n"
    entry << "Thread: ${prev.getThreadName()}\n"
    entry << "Sample: ${prev.getSampleLabel()}\n"
    entry << "Time: ${dateTime}\n"
    entry << "Status: ${prev.getResponseCode()} - ${prev.getResponseMessage()}\n"
    entry << "-" * 40 << "\n"
    entry << "Response:\n${prev.getResponseDataAsString()}\n"
    entry << "=" * 80 << "\n\n"

    def outputFile = new File(FileServer.getFileServer().getBaseDir(), "error_responses.txt")

    // Every virtual user writes to the same file. One lock shared across all
    // threads (held in JMeter properties) stops two entries interleaving.
    def lock = props.computeIfAbsent("errorResponsesLock", { new Object() })
    synchronized (lock) {
        outputFile.append(entry.toString(), "UTF-8")
    }
}

Two details in that script matter more than they look:

  • It checks isSuccessful(), not the status code. Converting the response code to a number and comparing it with 400 throws on a connection failure, whose “code” is text such as Non HTTP response code: java.net.ConnectException — so the script would crash on exactly the errors you most want to see.
  • Writes are serialised. Without the lock, two threads failing at the same moment can interleave their output and leave you with entries you cannot read.

Important Caveat

Writing data to files can limit the throughput of your test, and the lock means failing threads queue behind each other to write. Where you intend to push through high workloads, this level of logging may become obstructive — and when a system under load starts failing, it fails a lot at once.

Consider the following when using file-based logging:

  • Use it primarily for debugging and low-volume tests
  • Disable or remove the logging for high-throughput performance tests
  • Filter carefully to only log errors or specific conditions
  • Consider using backend listeners for production-level monitoring

Usage

  1. Add a JSR223 PostProcessor to your HTTP Request sampler (or to the Thread Group, to cover every sampler in it)
  2. Select “groovy” as the scripting language
  3. Paste the script into the Script panel
  4. Run your test

The script will create an error_responses.txt file in your test plan directory containing detailed information about failed requests.

The No-Code Alternative

If you do not need a custom format, JMeter can save failed response bodies itself. Add these to user.properties:

jmeter.save.saveservice.output_format=xml
jmeter.save.saveservice.response_data.on_error=true

Response bodies are only written in the XML results format, which is why the first line is needed. The result is larger and slower to write than CSV, so the same caveat applies — use it for debugging runs, not the load test itself.

Further Reading

Tags:

#jmeter #groovy #logging #debugging #performance-testing

The cheat sheets, as printable PDFs

All 52 are free to read on the site — no signup. Want them as A4 PDFs you can actually print? The pack covers JMeter, k6, Gatling, Docker, Kubernetes and observability, and costs nothing but an email address.

Get the PDF pack

Delivered by email. Unsubscribe any time — see our privacy policy.

Stuck on this in your own test suite?

I take on fixed-price, fixed-turnaround performance work — script migrations, HAR-to-script conversion and written performance audits. No calls required.

Get in Touch