akka-http
akka-http copied to clipboard
Describe on how a logger can be customised in the Route-Chain (Java) / modify MDC
I need to customise the logger that gets returned by extractLog( log -> () ) so I can attach the current correlationId / userId / other fields into the MDC. However, I'm unable to accomplish this with the documentation I found. This is what I got so far:
public static RouteAdapter extractCorrelationId(Function<String, Route> inner) {
return optionalHeaderValueByName("X-CorrelationId", (corr) -> extractLog(log -> {
String correlationId = corr.orElseGet(() -> {
String c = UUID.randomUUID().toString();
log.debug("request does not have a upstream correlationId, assigning " + c);
return c;
});
return provide(correlationId, inner);
}));
}
and I was planning to decorate my root-route as follows:
public Route createRoute() {
return extractCorrelationId(corr -> extractLog(log -> {
LoggingAdapter newLog = log;
var newMDC = newLog.mdc().$plus(Tuple2.apply("correlationId", corr)); // this is a MDC and not a LoggingAdapter :(
// how to bring the newMDC into the newLog ? because AFAIK the MDC is a immutable list, thus I cannot simply change its values
return withLog(newLog, () -> allRoutes());
}));
}
Please provide a way on how a valid "LoggingAdapter" can be constructed from Java.
You will have to create a new LoggingAdapter in the first place because at least that part of LoggingAdapters is not thread-safe and use log.setMdc or log.mdc(map) to set the mdc.
The other option is to use the slf4j APIs directly but then you'll have to make to set the MDC whenever you run a chunk of code in a new thread (or use the automatic MDC propagation in commercial Lightbend Telemetry).
I keep this ticket open to create documentation around this particular pattern.
I recently found a way to do this using the existing loggers. There are basically three directives:
- a directive that takes the RouteContext and provides it with a new DiagnosticMarkerBusLoggingAdapter
- a directive that extracts the DiagnosticMarkerBusLoggingAdapter from the RouteContext
- a directive that takes a key/value pair and appends it to the MDC map on the DiagnosticMarkerBusLoggingAdapter.
As far as I can tell, this is enough to make it thread-safe: each request gets a new logger, and, AFAIK, each request's directives are executed serially, so the map updates must be serialized. In any case I also have tests that hit the routes in parallel to test the thread-safety.
We currently have this in our internal utilities. Would there be interest in making a PR with these directives? LMK what you think @jrudolph or anyone else in the akka team.