← Recipes

阅读中文版本

Propagate a Correlation ID Across Services

Generate a request identifier at the edge, forward it in headers and logs, and return it to the client so a single trace can be reconstructed later.

~25 minobservabilityloggingdistributed-systems

Task

Carry one correlation id through synchronous calls, queue messages, and logs for cross-service tracing.

When to use this

An error is reported by a user, but no service can join its logs to the upstream request that triggered the failing call.

Prerequisites

  • An edge layer that can set response headers
  • A structured logging library

Steps

1. Accept an incoming correlation header or generate a new one when absent.

curl -H "x-correlation-id: abc123" https://api.example.com/items

Expected output: Every request has a non-empty correlation id at the edge.

2. Attach the id to a per-request logging context and echo it in the response header.

Expected output: Log lines for one request share the same id.

3. Forward the id on outbound HTTP calls and as a message attribute for async work.

Expected output: Downstream services inherit the same id.

4. Bound the id length and reject client-supplied ids that are too long.

Expected output: Ids stay bounded and spoof-resistant.

Troubleshooting

Problem

Id missing in async handlers

Solution

Rebuild the log context inside the consumer from the message attribute; do not rely on thread-local state.

Problem

Id collisions

Solution

Use a cryptographically random UUID rather than timestamps plus counters.

Limitations

  • A correlation id identifies a request, not a user, so it must not be treated as an auth token.
  • Sampling may drop some correlated logs if the pipeline does not keep whole traces.

Context

Carry one correlation id through synchronous calls, queue messages, and logs for cross-service tracing. An error is reported by a user, but no service can join its logs to the upstream request that triggered the failing call.

Steps

  1. Accept an incoming correlation header or generate a new one when absent. Expected: Every request has a non-empty correlation id at the edge.
  2. Attach the id to a per-request logging context and echo it in the response header. Expected: Log lines for one request share the same id.
  3. Forward the id on outbound HTTP calls and as a message attribute for async work. Expected: Downstream services inherit the same id.
  4. Bound the id length and reject client-supplied ids that are too long. Expected: Ids stay bounded and spoof-resistant.
const cid = req.headers['x-correlation-id'] ?? crypto.randomUUID();
logger.child({ correlationId: cid }).info('request.start');
res.setHeader('x-correlation-id', cid);

Verify

  • Every request has a non-empty correlation id at the edge.
  • Log lines for one request share the same id.
  • Downstream services inherit the same id.
  • Ids stay bounded and spoof-resistant.

Limits

  • A correlation id identifies a request, not a user, so it must not be treated as an auth token.
  • Sampling may drop some correlated logs if the pipeline does not keep whole traces.