We have a spring boot application with REST interface and a web client. We are using spring-security with OAuth 2.0 JWT tokens for authentication. We are using slf4j and sleuth for logging. We want to log the currently logged-in user id in our logs. Technically, we want to add the user id to the Mapped Diagnostic Context (MDC) of our server application.
The goal is to link server side errors resulting from frontend operations to the user who has triggerend the backend operation.
At the moment, we extract the user id on the client side and send the id as HTTP header field to the server where it is extraced from the HTTP header as baggage by sleuth and added to the logs, see following spring.sleuth.baggage
configuration. This is working.
spring.sleuth.baggage.remote-fields=user_id
spring.sleuth.baggage.tag-fields=user_id
spring.sleuth.baggage.correlation-fields=user_id
The user is logged by user=%X{user_id:-}
, see the full log pattern:
logging:
level:
ROOT: WARN
pattern:
console: "[%d] [%t] %highlight(%-5p) %c{10} - %cyan([trace=%X{X-B3-TraceId:-} span=%X{X-B3-SpanId:-} user=%X{user_id:-}]) %m%n"
However, instead of extracting the user id on the client side and sending it to the backend, we want to directly extract the user id from the JWT token on the server side. Since all the information are also directly available on the server side.
I have checked spring-cloud-sleuth documentation how to set baggage fields in Java, but I couldn't figure out how to do it.
- https://cloud.spring.io/spring-cloud-sleuth/reference/html/#java-configuration
- https://docs.spring.io/spring-cloud-sleuth/docs/current-SNAPSHOT/reference/html/project-features.html#features-brave-baggage
- https://docs.spring.io/spring-cloud-sleuth/docs/current-SNAPSHOT/reference/html/appendix.html#appendix
I did not know which classes to use and how to use them. I've tried the following code. The code is not executed at Spring startup. So, it seems some config is missing or the code is completely wrong.
package net.company.common.service;
import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagation;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationCustomizer;
import brave.internal.baggage.BaggageContext;
import net.company.common.service.CommonServiceConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@ComponentScan
@Import({CommonServiceConfig.class})
public class ServiceConfig {
@Bean
BaggagePropagationConfig.SingleBaggageField singleBaggageField() {
BaggagePropagationConfig.SingleBaggageField field = BaggagePropagationConfig.SingleBaggageField.newBuilder(BaggageField.create("user_id")).build();
field.field().updateValue("user_12345"); // set only dummy value for debug
return field;
}
}
It would be possible to implement such an MDC manually, see https://www.baeldung.com/mdc-in-log4j-2-logback. But as this is error prone we want to avoid it, e.g. context cleaning must be done right.
How can the user id from JWT be added to MDC using sleuth/brave for server side logging?