Correlation ID
A unique identifier that tracks a single business operation as it flows across services and messages.
A correlation ID is a unique identifier attached to a request that follows it through every service and message in the system. When something goes wrong, you can search logs for that one ID and see every step the operation went through.
The flow works like this: an HTTP request arrives with a Correlation-ID header. Your code reads it and passes it through the context. When you publish a message, the correlation ID goes into the message metadata. When a subscriber picks up the message, middleware extracts the correlation ID from metadata and puts it back in the context. If that handler makes an HTTP call to another service, the correlation ID goes into the request header again.
If no correlation ID is present on an incoming request, generate a new one. Even without the full chain, you can trace at least part of the operation. Some teams add a gen_ prefix to generated IDs so it's obvious the original was missing.
In Go, context.Context is the natural carrier. A middleware sets the correlation ID on the context, and any function that needs it can read it from there. The function should work the same whether the context has a correlation ID or not. It's metadata, not business logic.
Correlation IDs are a simpler alternative to full distributed tracing. They give you enough to follow a request through logs without the overhead of a tracing infrastructure. In practice, you often use both: correlation IDs for quick log searches, traces for understanding timing and dependencies.
References
- Event-Driven Architecture: The Hard Parts — Observability is essential. Debugging async systems without tracing, logs, and correlation IDs is almost impossible. If you are supporting it already for other transports like HTTP or gRPC, adding it for messages shouldn't be hard.