Logging to Disk with REST Assured

A common question that pops up now and again is how to configure REST Assured logs to be written to disk instead of printed to the console. The intention of this blog post is to demonstrate how this can be achieved.

But first let’s look at how to use logging in REST Assured:

Logging to Console

REST Assured has something called a Request- and ResponseSpecification and you log the contents of these individually. This is why you often see code like this:

given().
        log().all().
        queryParam("firstName", "John").
        queryParam("lastName", "Doe").
when().
        get("/greet").
then().
        log().all().
        statusCode(200).
        body("greeting", equalTo("Greetings John Doe"));

The first call to log().all() says that we want to log everything in the request specification and the second call to log().all() instructs REST Assured to log everything in the response specification (after the call has been made). The results can look like this:

Request method:	GET
Request URI:	http://localhost:8080/greet?firstName=John&lastName=Doe
Proxy:			
Request params:	
Query params:	firstName=John
				lastName=Doe
Form params:	
Path params:	
Headers:		Accept=*/*
Cookies:		
Multiparts:		
Body:			
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
Content-Length: 98
Server: Jetty(9.3.2.v20150730)

{
    "greeting": "Greetings John Doe"
}	

We can also decide not to log the request specification at all and only log the response body like this:

given().
        queryParam("firstName", "John").
        queryParam("lastName", "Doe").
when().
        get("/greet").
then().
        log().body().
        statusCode(200).
        body("greeting", equalTo("Greetings John Doe"));

which will log this to the console:

{
    "greeting": "Greetings John Doe"
}

Note that by default the body is pretty-printed if it’s in a format that REST Assured understands (such as XML, JSON or HTML). You can easily disable this though:

given().
        queryParam("firstName", "John").
        queryParam("lastName", "Doe").
when().
        get("/greet").
then().
        log().body(false).
        statusCode(200).
        body("greeting", equalTo("Greetings John Doe"));

which will return the body as is:

{"greeting":"Greetings John Doe"}

This is all fine, but what if you don’t want to log to the console but instead logging to a file?

Logging to a File

REST Assured comes with a lot of configuration options. By default it provides sane defaults but you can customize a lot of things in REST Assured if required. One of the things you can customize is how logging behaves using the LogConfig class. The LogConfig allows you to specify a default java.io.PrintStream that is used for logging when calling e.g. log().all(). If you haven’t specified a PrintStream explicitly then REST Assured will default to the PrintStream defined by System.out, i.e. it’ll print the logs to the console. But let’s see how we can change this to write a file instead:

try (FileWriter fileWriter = new FileWriter("/tmp/logging.txt");
     PrintStream printStream = new PrintStream(new WriterOutputStream(fileWriter), true)) {

    RestAssured.config = RestAssured.config().logConfig(LogConfig.logConfig().defaultStream(printStream));

	given().
	        log().all().
	        queryParam("firstName", "John").
	        queryParam("lastName", "Doe").
	when().
	        get("/greet").
	then().
	        log().all().
	        statusCode(200).
	        body("greeting", equalTo("Greetings John Doe"));
}

This will log everything to the file /tmp/logging.txt. Note that in this example we’re using the WriterOutputStream class from Apache Commons IO.

Using a JUnit Rule

Typically you probably want to configure the use of file logging once and then have it done with. One way to do this would be to create a Rule in JUnit4 or an extension in JUnit 5. Here we’re going to explore the first option and create a custom JUnit rule. It may be defined like this:

package io.restassured.itest.java.support;

import io.restassured.RestAssured;
import io.restassured.config.LogConfig;
import io.restassured.config.RestAssuredConfig;
import org.apache.commons.io.output.WriterOutputStream;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

import java.io.*;

public class WriteLogsToDisk extends TestWatcher {

    private final String logFolder;
    private PrintStream printStream;
    private LogConfig originalLogConfig;

    public WriteLogsToDisk(String logFolder) {
        File dir = new File(logFolder);
        if (!dir.exists()) {
            //noinspection ResultOfMethodCallIgnored
            dir.mkdirs();
        }
        if (logFolder.endsWith("/")) {
            this.logFolder = logFolder.substring(0, logFolder.length() - 1);
        } else {
            this.logFolder = logFolder;
        }
    }

    @Override
    protected void starting(Description description) {
        originalLogConfig = RestAssured.config().getLogConfig();
        FileWriter fileWriter;
        try {
            fileWriter = new FileWriter(logFolder + "/" + description.getMethodName() + ".log");
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
        printStream = new PrintStream(new WriterOutputStream(fileWriter), true);
        RestAssured.config = RestAssured.config().logConfig(LogConfig.logConfig().defaultStream(printStream).enablePrettyPrinting(false));
    }


    @Override
    protected void finished(Description description) {
        if (printStream != null) {
            printStream.close();
        }

        if (originalLogConfig != null) {
            RestAssured.config = RestAssuredConfig.config().logConfig(originalLogConfig);
        }
    }
}

What this rule does is to create a log file for each test case in the given file. Let’s see how it can be used:

public class LoggingToDiskTest {

    @Rule
    public WriteLogsToDisk writeLogsToDisk = new WriteLogsToDisk("/tmp/rest-assured-logs");

    @Test
    public void example1() {
        given().
                queryParam("firstName", "John").
                queryParam("lastName", "Doe").
        when().
                get("/greet").
        then().
                log().all().
                body("greeting", equalTo("Greetings John Doe"));
    }

    @Test
    public void example2() {
        given().
                queryParam("firstName", "Jane").
                queryParam("lastName", "Doe").
        when().
                get("/greet").
        then().
                log().all().
                body("greeting", equalTo("Greetings Jane Doe"));
    }
}

Now all calls to log() will be logged to disk. In this case two files will be generated in the /tmp/rest-assured-logs folder, example1.log and example2.log which contains the response logs for each respective test. It only contains the response logs in this example since we’ve chosen not to add log() to the RequestSpecification. There’s of course room for improvement to the WriteLogsToDisk rule, for example we could automatically remove files which are empty (i.e. no REST Assured logs where recorded for a particular test). You can have a look at an example test here and the code for WriteLogsToDisk here.

Conclusion

As you can see REST Assured is quite flexible and you can configure it to achieve most use cases, logging to disk being one example. If you haven’t done so already, feel free to try it out. Happy testing!

8 thoughts on “Logging to Disk with REST Assured

  1. Surprised to see no comments so far on this most useful necessity for testing ( logging test results) . I used loggging on disk files when testing soap services using SoapUI and definitely going to use this when building my framework on Restapi. Thanks for sharing.

  2. How to configure REST Assured drop all requests and responses with the below format at console when run Junit test cases

    [main] DEBUG org.apache.http.headers – >> Connection: Keep-Alive

  3. Hi friend,
    This is very useful in API testing. Thank you for sharing. I also have a question in rest-assured. Is there a way to add something (like \n) between request and response? Thank you!
    For example:
    Request URI: http://52.74.68.90:9100/advertiser/signup/orm
    Request method: POST
    Headers: Accept=*/*
    Content-Type=application/json; charset=UTF-8
    Request params:
    Query params:
    Form params:
    Path params:
    Multiparts:
    ——I want to add a blank line here to distinguish the request and response
    HTTP/1.1 201 Created
    {“username”:”ellen_autoadvsignup1″}

    BR.
    TavisD

    1. Hi, can you tell me how you decided this problem?
      I want too do this, make line between request and response.

Leave a Reply to Abstract report of October 2018 - LaunchApp Cancel reply

Your email address will not be published. Required fields are marked *