Skip to main content

pkg/gateway/server/request_metadata.go

Source

Overview

What: Generates and propagates request and trace identifiers through headers and request context.

Why: Stable IDs are required for correlating logs, metrics, and upstream calls across a distributed system.

How: Ensures X-Request-Id and X-Trace-Id are present on the request and stores them in context.Context for middleware/handlers to read.

Contents

Imports

import block 1

pkg/gateway/server/request_metadata.go#L3
import (
"context"
"net/http"

"github.com/google/uuid"
)

Constants

const block 1

pkg/gateway/server/request_metadata.go#L12
const (
requestIDKey contextKey = "requestID"
traceIDKey contextKey = "traceID"
)

requestIDKey

What: Context key used to store the request ID string.

Why: Avoids collisions by using a private typed key.

How: Written by ensureRequestIDs and read by requestIDFromContext.

traceIDKey

What: Context key used to store the trace ID string.

Why: Avoids collisions by using a private typed key.

How: Written by ensureRequestIDs and read by traceIDFromContext.

Types

type block 1

pkg/gateway/server/request_metadata.go#L10
type contextKey string

contextKey

What: Private typed context key for request metadata.

Why: Prevents collisions with other context values by not using raw strings.

How: Used to define requestIDKey and traceIDKey.

Functions and Methods

ensureRequestIDs

What: Ensures a request has both request and trace identifiers and returns a request with an updated context.

Why: Callers and middleware should be able to assume IDs exist for logging and error responses.

How: Reads X-Request-Id and X-Trace-Id, generates a UUID when missing, defaults trace ID to request ID, sets headers, and stores both values in context.

pkg/gateway/server/request_metadata.go#L17
func ensureRequestIDs(r *http.Request) (*http.Request, string, string) {
requestID := r.Header.Get("X-Request-Id")
if requestID == "" {
requestID = uuid.NewString()
r.Header.Set("X-Request-Id", requestID)
}

traceID := r.Header.Get("X-Trace-Id")
if traceID == "" {
traceID = requestID
r.Header.Set("X-Trace-Id", traceID)
}

ctx := context.WithValue(r.Context(), requestIDKey, requestID)
ctx = context.WithValue(ctx, traceIDKey, traceID)

return r.WithContext(ctx), requestID, traceID
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L18: requestID := r.Header.Get("X-Request-Id")
    • What: Defines requestID.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L19: if requestID == "" { requestID = uuid.NewString() r.Header.Set("X-Request-Id", requestID) }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L20: requestID = uuid.NewString()
        • What: Assigns requestID.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L21: r.Header.Set("X-Request-Id", requestID)
        • What: Calls r.Header.Set.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
  • L24: traceID := r.Header.Get("X-Trace-Id")
    • What: Defines traceID.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L25: if traceID == "" { traceID = requestID r.Header.Set("X-Trace-Id", traceID) }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L26: traceID = requestID
        • What: Assigns traceID.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L27: r.Header.Set("X-Trace-Id", traceID)
        • What: Calls r.Header.Set.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
  • L30: ctx := context.WithValue(r.Context(), requestIDKey, requestID)
    • What: Defines ctx.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L31: ctx = context.WithValue(ctx, traceIDKey, traceID)
    • What: Assigns ctx.
    • Why: Keeps intermediate state available for later steps in the function.
    • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
  • L33: return r.WithContext(ctx), requestID, traceID
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

requestIDFromContext

What: Extracts the request ID from context.

Why: Allows middleware to log and emit IDs without re-parsing headers.

How: Looks up requestIDKey and type-asserts to string.

pkg/gateway/server/request_metadata.go#L36
func requestIDFromContext(ctx context.Context) string {
if ctx == nil {
return ""
}
if value, ok := ctx.Value(requestIDKey).(string); ok {
return value
}
return ""
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L37: if ctx == nil { return "" }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L38: return ""
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L40: if value, ok := ctx.Value(requestIDKey).(string); ok { return value }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L40: value, ok := ctx.Value(requestIDKey).(string)
        • What: Defines value, ok.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L41: return value
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L43: return ""
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

traceIDFromContext

What: Extracts the trace ID from context.

Why: Allows middleware and error writers to correlate failures across systems.

How: Looks up traceIDKey and type-asserts to string.

pkg/gateway/server/request_metadata.go#L46
func traceIDFromContext(ctx context.Context) string {
if ctx == nil {
return ""
}
if value, ok := ctx.Value(traceIDKey).(string); ok {
return value
}
return ""
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L47: if ctx == nil { return "" }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L48: return ""
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L50: if value, ok := ctx.Value(traceIDKey).(string); ok { return value }
    • What: Branches conditionally.
    • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L50: value, ok := ctx.Value(traceIDKey).(string)
        • What: Defines value, ok.
        • Why: Keeps intermediate state available for later steps in the function.
        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
      • L51: return value
        • What: Returns from the current function.
        • Why: Ends the current execution path and hands control back to the caller.
        • How: Executes a return statement (possibly returning values).
  • L53: return ""
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).

Start Here

Architecture

Guides

Reference

Neighboring source