go 46 lines · 7 steps

Correlation ID tracing middleware in Gin

A Gin middleware that tags every request with a correlation ID and threads it through the logger and request context.

Explained by highlit
1package middleware
2 
3import (
4 "context"
5 
6 "github.com/gin-gonic/gin"
7 "github.com/google/uuid"
8 "github.com/rs/zerolog"
9 "github.com/rs/zerolog/log"
10)
11 
12const (
13 CorrelationIDKey = "correlation_id"
14 correlationIDHeader = "X-Correlation-ID"
15)
16 
17func CorrelationID() gin.HandlerFunc {
18 return func(c *gin.Context) {
19 cid := c.GetHeader(correlationIDHeader)
20 if cid == "" {
21 cid = uuid.NewString()
22 }
23 
24 c.Set(CorrelationIDKey, cid)
25 c.Header(correlationIDHeader, cid)
26 
27 logger := log.With().Str("correlation_id", cid).Logger()
28 ctx := logger.WithContext(c.Request.Context())
29 c.Request = c.Request.WithContext(ctx)
30 
31 c.Next()
32 }
33}
34 
35func FromContext(ctx context.Context) string {
36 if c, ok := ctx.(*gin.Context); ok {
37 if cid := c.GetString(CorrelationIDKey); cid != "" {
38 return cid
39 }
40 }
41 return zerolog.Ctx(ctx).GetLevel().String()
42}
43 
44func LoggerFrom(c *gin.Context) *zerolog.Logger {
45 return log.Ctx(c.Request.Context())
46}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Reusing an inbound correlation header lets a single ID follow a request across service boundaries.
  2. 2Attaching the ID to a request-scoped logger gives every downstream log line automatic traceability.
  3. 3Storing shared state in both the Gin context and the request context makes it reachable from handlers and plain context.Context consumers alike.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Correlation ID tracing middleware in Gin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code