Backend Notes AUG 09, 2024 • 03 MIN READ

HOW TO SHOW TRACEID
IN LOG WHEN USING ASYNC IN SPRING BOOT

Abstract technical background

Sometimes you will face a condition where traceId does not appear in the log when using multi thread or async process.

Sample code

TestAsyncRes.java JAVA
public TestAsyncRes testAsync(TestAsyncReq request, HttpServletRequest servletRequest) {
  log.info("Start test async with request: " + request);
  TestAsyncRes response = TestAsyncRes.builder()
    .responseCode("00")
    .responseMessage("Success")
    .build();

  CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    log.info("Start async process...");
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  });
  log.info("After async process");

  return response;
}

Log

Look at we get empty traceId and spanId

EXAMPLE.LOG TERMINAL
09-08-2024 10:49:27.127 [http-nio-8080-exec-2] [app_name=simulator-service, trace_id=66b591c75b50a7205a87da92d31aee5f, span_id=5a87da92d31aee5f] INFO  c.i.j.l.s.usecase.SimulatorService.testAsync - Start test async with request: TestAsyncReq(customerName=Cah kerjo, phoneNo=088888888)
09-08-2024 10:49:27.131 [http-nio-8080-exec-2] [app_name=simulator-service, trace_id=66b591c75b50a7205a87da92d31aee5f, span_id=5a87da92d31aee5f] INFO  c.i.j.l.s.usecase.SimulatorService.testAsync - After async process
09-08-2024 10:49:27.131 [ForkJoinPool.commonPool-worker-1] [app_name=simulator-service, trace_id=, span_id=] INFO  c.i.j.l.s.usecase.SimulatorService.lambda$testAsync$0 - Start async process...

To show traceId, we need to create util class let say AsyncUtil

CONFIG.JAVA JAVA
public static CompletableFuture<Void> runAsyncWithMDC(Runnable runnable) {
  Map<String, String> previous = MDC.getCopyOfContextMap();
  return CompletableFuture.runAsync(() -> {
    MDC.setContextMap(previous);
    try {
      runnable.run();
    } finally {
      MDC.clear();
    }
  });
}

And then we can use it like this

ASYNCSERVICE.JAVA JAVA
public TestAsyncRes testAsync(TestAsyncReq request, HttpServletRequest servletRequest) {
  log.info("Start test async with request: " + request);
  TestAsyncRes response = TestAsyncRes.builder()
    .responseCode("00")
    .responseMessage("Success")
    .build();

  CompletableFuture<Void> future = runAsyncWithMDC(() -> {
    log.info("Start async process...");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
  });
  log.info("After async process");

  return response;
}

Result

Now traceId and spanId appears

EXAMPLE.LOG TERMINAL
09-08-2024 10:53:52.494 [http-nio-8080-exec-2] [app_name=simulator-service, trace_id=66b592d01a740d0b9527da21746f2f9d, span_id=9527da21746f2f9d] INFO  c.i.j.l.s.usecase.SimulatorService.testAsync - Start test async with request: TestAsyncReq(customerName=Cah kerjo, phoneNo=088888888)
09-08-2024 10:53:52.497 [http-nio-8080-exec-2] [app_name=simulator-service, trace_id=66b592d01a740d0b9527da21746f2f9d, span_id=9527da21746f2f9d] INFO  c.i.j.l.s.usecase.SimulatorService.testAsync - After async process
09-08-2024 10:53:52.497 [ForkJoinPool.commonPool-worker-1] [app_name=simulator-service, trace_id=66b592d01a740d0b9527da21746f2f9d, span_id=9527da21746f2f9d] INFO  c.i.j.l.s.usecase.SimulatorService.lambda$testAsync$0 - Start async process...

READ BEYOND THE VOID

Technical blueprint background
Backend Notes

Exclusion file and duplication check on Sonarqube

Sonarqube is an open source platform developed by SonarSource...

Read Entry
Abstract digital network
Backend Notes

Bash script to auto run java application

Create executable script to auto run java...

Read Entry
Circuit board macro
Backend Notes

Service GRPC with Golang

GRPC using Golang...

Read Entry