Jim M.
Jim M.

Reputation: 1009

Add a request ID to slf4j logging in Micronaut

Question

When a request comes into the server I would like to interrogate the headers and see if there is a specific header, if so I want to grab that headers value and add it to the SLF4Js MDC, if it doesn't exist I will generate my own (see code below).

Issue

I'm using Micronaut (v2.5.5) for the first time, been using Spring Boot for a while. With Spring Boot I was able to add a Filter method which would add a request ID to SLF4Js MDC context, so that when elements where logged it would include that in the log message.

example

2021-07-01 19:12:57.104 LogLevel=INFO rid=3568b2d7-d8f1-4d7d-9e8d-49f2be727255, 1 --- [nio-8080-exec-8] .....

This is failing in Micronaut, I presume because requests can be handed off between threads and the MDC is thread specific.

example

2021/01/07 18:50:05.021 INFO [qtp1561347421-43] c.c.dex.css.controllers.MyEndpoint rid= - .....

Is there any mechanism in Micronaut to support this functionality without having to switch to Jaeger etc...? If so what is it?

Here is the code that I tried, which doesn't work

@Slf4j
@Filter("/v1.0/**")
public class RequestId extends OncePerRequestHttpServerFilter {
    public static final String X_REQUEST_ID = "X-REQUEST-ID";
    public static final String RID = "rid";

    @Override
    protected Publisher<MutableHttpResponse<?>> doFilterOnce(HttpRequest<?> request, ServerFilterChain chain) {
        // Was a request ID passed in, if so grab it
        String requestID = request.getHeaders().get(X_REQUEST_ID);
        if (null == requestID) {
            // no create it
            requestID = UUID.randomUUID().toString();
        }
        log.info("Storing RID in MDC and request: " + requestID);
        MDC.put(RID, requestID);
    }

I did try to put the rid in the request object (passed into doFilter), and then use that in my controller, e.g.

@Controller(value = "v1.0/")
public class XmlEndpoint {
    @Post(uri = "request")
    public MyResponse request(@NonNull @Body(value = "MyRequest") MyRequest request) {
        Optional<HttpRequest<Object>> optionalReq = ServerRequestContext.currentRequest();
            if (optionalReq.isPresent()) {
                HttpRequest<Object> curRequest = optionalReq.get();
                // Get the request ID from the request
                MDC.put(RequestId.RID, (String) curRequest.getAttribute(X_REQUEST_ID).orElse(UNKNOWN_RID));
            }
....
    }
}

In this case the log messages contain the RID, but that seems a bit convoluted.

I did a search and saw, what I thought where, several related issues, however; the answers didn't make a lot of sense (Micronaut newbie, sorry) or didn't seem to have a solution that showed what needed to be done.

Thanks in advance

Upvotes: 4

Views: 2454

Answers (1)

johncurrier
johncurrier

Reputation: 493

I finally got something similar to work by including the following dependency in build.gradle. Child threads running in the context of methods annotated with @Async now inherit the MDC properties of the parent thread and are visible by loggers.

implementation "io.micronaut:micronaut-tracing"

Upvotes: 0

Related Questions