skip to content

What is a correlation ID (trace ID) in application logs, and why is it useful?

level: juniorimportance: should knowfreq 55%

answer

  1. one ID per request on every log line
  2. traceId = whole request, spanId = one unit of work
  3. [app,traceId,spanId] pattern
  4. filter logs by one ID
  5. Micrometer Tracing populates it

basics

~20 s

A correlation ID (trace ID) is a unique identifier attached to every log line produced while handling one request. It lets you filter logs and see everything that happened for that single request, even across services.

solid answer

~40 s

A correlation/trace ID is a unique value generated per incoming request and stamped onto every log line emitted while that request is processed. Without it, logs from many concurrent requests interleave and are impossible to untangle. With it, you grep or filter by one ID and reconstruct the full story of a single request. In Spring Boot 3, adding Micrometer Tracing makes this automatic: it creates a traceId (whole request across services) and a spanId (one unit of work), puts them in the logging context (MDC), and the default log pattern prints them as [app-name,traceId,spanId]. The same traceId travels to downstream services via HTTP headers, so you can correlate logs across a distributed system, and tie those logs back to a trace in a tool like Zipkin, Tempo, or Jaeger.

code

java · 15 lines
java
// Just add Micrometer Tracing + a bridge and it becomes automatic.
// build.gradle:
//   implementation 'org.springframework.boot:spring-boot-starter-actuator'
//   implementation 'io.micrometer:micrometer-tracing-bridge-brave'

@RestController
class OrderController {
  private static final Logger log = LoggerFactory.getLogger(OrderController.class);

  @GetMapping("/orders/{id}")
  public String get(@PathVariable String id) {
    log.info("fetching order {}", id); // line prints [orders,<traceId>,<spanId>]
    return "ok";
  }
}

go deeper

for a junior

Should explain the per-request ID concept and that it makes logs filterable.

for a middle

Should name traceId/spanId and know Micrometer Tracing prints them via the default pattern.

for a senior

Should connect it to MDC and cross-service propagation.

for a principal

Should frame it as the linchpin tying logs, traces, and metrics into one observability story (exemplars, backend correlation).

## The problem A server handles many requests concurrently, each on its own thread. All their log lines land in the same file, interleaved. If request A logs `"validating order"` and request B logs `"payment failed"`, you cannot tell which lines belong together. A **correlation ID** solves this: a single unique identifier attached to every log line produced while handling one request. ## Trace ID vs span ID In modern Spring (Spring Boot 3 uses **Micrometer Tracing**, the successor to Spring Cloud Sleuth): - **traceId** — identifies the *entire* request as it flows through one or more services. It is the correlation ID for the whole journey. - **spanId** — identifies *one unit of work* within that trace (e.g., one service call, one DB query). A trace is a tree of spans; every span shares the same traceId but has its own spanId. ## How it appears in logs With a tracing implementation on the classpath, Spring Boot sets a default *correlation* portion of the log pattern (`logging.pattern.correlation`). It expands to roughly: ``` [${spring.application.name:},%X{traceId:-},%X{spanId:-}] ``` A log line then looks like: ``` 2026-07-22 10:15:03.221 INFO [orders,3e2f...a1,7c9b...4d] c.g.OrderService : validating order ``` The `%X{traceId:-}` is Logback's **MDC** converter — it prints the value stored under key `traceId` in the current thread's diagnostic context (or empty `-` if absent). Micrometer Tracing is what *populates* those MDC keys when a span is active. ## Why it matters 1. **Debugging** — filter your log aggregator (Loki, ELK, CloudWatch) by one traceId and see only that request's lines, in order. 2. **Distributed correlation** — the traceId is propagated to downstream services (via a header such as W3C `traceparent`), so one ID ties logs together across service boundaries. 3. **Logs ↔ traces** — the same traceId shown in logs is the ID used by the tracing backend (Zipkin/Tempo/Jaeger), so you can jump from a log line to the visual trace and back. ## When to use Essentially always in a service that handles requests. It costs little (a header + a few MDC keys) and is the single biggest quality-of-life improvement for production debugging. ## Gotcha for a junior The ID is only useful if it's *actually printed*. If you strip the default log pattern or use a custom appender that omits the correlation part, you lose it. And it lives in a thread-local (MDC), so work handed to another thread can lose the ID unless propagation is set up.

  • What is the difference between traceId and spanId?
    traceId identifies the entire request across all services and spans; spanId identifies a single unit of work within that trace. All spans of one request share one traceId but each has a unique spanId.

saying these in an interview costs you the question

  • Thinking a correlation ID is per-user or per-session rather than per-request
  • Believing the ID is stored in the database rather than in the logging context (MDC)
  • Assuming logs are automatically correlated without any tracing library

context