Search code examples
javaloggingapache-httpclient-4.x

How can I log data from HttpRequest and HttpResponse at the same time?


I have some custom logging logic that logs information from the request and response. Some log lines contain information from both the request and the response at the same time. Thus, I somehow need to be able to access both at the same time to create the necessary log lines.

When using Feign this was easy to do since you can just set a logger on the builder, and the fact that the response object has the request object in it makes it easy to retrieve data from both.

However, with apache HttpClient, such access does not exist.

I could only find addInterceptorFirst and addInterceptorFirst for each of request and response, but never both.

The only place I was able to access both objects is at the send() method like so:

@Override
public HttpResponse send(String method, String path, Map<String, String> headers, HttpEntity httpEntity) throws IOException {
    HttpUriRequest request = getHttpUriRequest(method, path, headers, httpEntity);
    try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
        HttpResponse httpResponse =  httpClient.execute(request);
        httpClientLogger.logRequestResponse(request, httpResponse); // logging here
        return httpResponse;
    }
}

This works fine except for one problem.

There are interceptors that are adding headers to the request internally (inside the httpClient.execute(request) method) and they seem to be creating a deep copy of the request object since after the request is done, the object in the code snippet is not modified to include the added headers.

Question: How can I log info from the request and the response at the same time, while having the request contain all relevant information that may be added through interceptors?


Solution

  • Create a request interceptor that stores the request in the HttpContext, then create a response interceptor that reads it from the HttpContext, then logs both the request and response.

    If you provide a HttpContext (implementing class: BasicHttpContext) yourself when executing the request, you can populate it with some extra fields like the start date. Otherwise, the HTTP client will create one for each request separately.