Logging Result Body

Hello All,

I’m trying to create a filter to log request and response. Is there a way to log result body in the filter?

In Java or in Scala?

Hi, Looking for in Java

I haven’t used Java with Play in a while, but looking at the latest documentation, I would start with

Then you could check wether the request header is an instance of Request. And if so, ask for the request body via Request’s body() method:
https://www.playframework.com/documentation/2.8.x/api/java/play/mvc/Http.Request.html

Sounds like what you need is a custom ActionCreator.

import akka.util.ByteString;
import play.http.DefaultActionCreator;
import play.http.HttpEntity;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;

import javax.inject.Inject;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.CompletionStage;

public class CustomActionCreator extends DefaultActionCreator {

	@Inject
	public CustomActionCreator() {}

	@Override
	public Action.Simple createAction(Http.Request request, Method actionMethod) {
		Optional.ofNullable(request.body())
				.map(Http.RequestBody::asBytes)
				.map(ByteString::toArray)
				.ifPresent(requestBodyBytes -> {
					// Do what you want with it
				});
		return new Action.Simple() {
			@Override
			public CompletionStage<Result> call(Http.Request request) {
				return delegate.call(request).thenApply(result -> {
					final HttpEntity body = result.body();
					if (body instanceof HttpEntity.Strict) {
						final byte[] responseBodyBytes = ((HttpEntity.Strict) body).data().toArray();
						// do what you want with it
					}
					return result;
				});
			}
		};
	}

}

For obvious reasons, this will only works with in-memory bodies.

Thanks @slisaasquatch . I’ve been looking around trying to figure this out. With the HttpEntity body does this work only with Entity strict , how do you if body is instanceof Chunked entity? Is there a way to log result body for other entity types?

The fundamental problem with Chunked is that it’s not in-memory, so there isn’t a good way of logging it. The same restriction applies to the request body as well. If the request body is not in-memory, Http.RequestBody::asBytes will return null.

Thanks for you help @slisaasquatch . I was trying to figure out a way to actually log response body but I suppose like you mentioned there’s no good way

I’d say logging in-memory request and response bodies is already pretty good. If your requests are things like in-memory JSON or byte array, and if your responses are things like ok(String) or ok(JsonNode), then those are all guaranteed to be in-memory, and my solution should work. The problem is only when you handle things like streams or files.

Thank you @slisaasquatch.