When an application have deployed to remote server and is going test by QA team, I am as developer, need to trace every bug that reported by QA in remote server and find the root cause through log server. But to find root cause the problem, especially if you have many microservices application, need some a Correlation Id for every request because multiple requests will reach the system at the same time. The same request will get forwarded to multiple systems. Each layer in each system will add some logs to trace the issue.
In this article, i will share you how to create a Correlation Id and will print at log in every microservices Spring Boot application.
First : in logback-spring.xml need print correlation id with append pattern “[%X{traceId}]”, correlation id represented by pattern traceId
<Pattern>
%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{0}.%M - %msg%n
</Pattern>
Second : Make Global Context use ThreadLocal to store correlation id value
public class GlobalContext {
private static final ThreadLocal<GlobalContext> GLOBAL = new ThreadLocal(){
@Override
protected GlobalContext initialValue() {
return new GlobalContext();
}
};
public static GlobalContext getContext() {
return GLOBAL.get();
}
public static void clear() {
GLOBAL.remove();
}
private final Map<String, String> globalMap = new HashMap();
public void put(String key, String val) throws IllegalArgumentException {
if( key == null) {
throw new IllegalArgumentException("Key must be filled");
}
globalMap.put(key, val);
}
public String get(String key) {
return globalMap.get(key);
}
}
Third : Create a request interceptor. This interceptor will get trace id in global context then send trace id to next application through HTTP Header. In this example, i will use intercept RestTemplate to always send trace id as default configuration.
public class HeaderTraceInterceptor
implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
String traceId = GlobalContext.getContext().get("traceId");
request.getHeaders().set("TRACE_ID", traceId);
return execution.execute(request, body);
}
}
@Configuration
public class DefaultConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder()
.interceptors(new HeaderTraceInterceptor())
.build();
}
}
Last : Make Default Filter that will be called for by default for every request. Get trace id through HTTP Header and then put trace id value to Mapped Diagnostic Context (MDC)
@Configuration
public class DefaultFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
try {
String traceId = httpRequest.getHeader("TRACE_ID");
if (StringUtils.isBlank(traceId)) {
traceId = UUID.randomUUID().toString();
}
GlobalContext.getContext().put("traceId", traceId);
MDC.put("traceId", traceId);
filterChain.doFilter(servletRequest, servletResponse);
} finally {
MDC.remove("traceId");
GlobalContext.clear();
}
}
}
You can test and try the application through this download link
DOWNLOAD CORRELATION ID APPLICATION
Requirement : JDK 17.0.6