client_request_id.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. package middleware
  2. import (
  3. "context"
  4. "strings"
  5. "github.com/Wei-Shaw/sub2api/internal/pkg/ctxkey"
  6. "github.com/Wei-Shaw/sub2api/internal/pkg/logger"
  7. "github.com/gin-gonic/gin"
  8. "github.com/google/uuid"
  9. "go.uber.org/zap"
  10. )
  11. const clientRequestIDHeader = "X-Client-Request-ID"
  12. // ClientRequestID ensures every request has a unique client_request_id in request.Context().
  13. //
  14. // This is used by the Ops monitoring module for end-to-end request correlation.
  15. func ClientRequestID() gin.HandlerFunc {
  16. return func(c *gin.Context) {
  17. if c.Request == nil {
  18. c.Next()
  19. return
  20. }
  21. if v, _ := c.Request.Context().Value(ctxkey.ClientRequestID).(string); strings.TrimSpace(v) != "" {
  22. var valid bool
  23. v, valid = normalizeCorrelationID(v)
  24. if !valid {
  25. v = uuid.New().String()
  26. }
  27. c.Header(clientRequestIDHeader, v)
  28. ctx := context.WithValue(c.Request.Context(), ctxkey.ClientRequestID, v)
  29. c.Request = c.Request.WithContext(ctx)
  30. c.Next()
  31. return
  32. }
  33. id := uuid.New().String()
  34. c.Header(clientRequestIDHeader, id)
  35. ctx := context.WithValue(c.Request.Context(), ctxkey.ClientRequestID, id)
  36. requestLogger := logger.FromContext(ctx).With(zap.String("client_request_id", strings.TrimSpace(id)))
  37. ctx = logger.IntoContext(ctx, requestLogger)
  38. c.Request = c.Request.WithContext(ctx)
  39. c.Next()
  40. }
  41. }