Skip to main content

pkg/gateway/server/protocol_metrics.go

Source

Overview

What:

Defines Prometheus metrics that describe gateway traffic by "protocol" and "product".

In this context:

  • protocol is a best-effort classification of the inbound request (http, websocket, sse, grpc)
  • product is a high-level routing bucket (e.g. trade/task) derived from headers or URL prefixes

Why:

The gateway proxies multiple kinds of traffic (regular HTTP, streaming, upgrades). For operations and capacity planning, it is useful to answer questions like:

  • Are we seeing more websocket connections than expected?
  • Is one product experiencing higher error rates or latency?
  • Are we accumulating long-lived SSE/grpc requests?

These metrics are designed to be emitted from middleware without coupling the middleware to Prometheus directly.

How:

newProtocolMetrics() constructs four collectors and registers them with the gateway registry:

  • gateway_protocol_requests_total counter labelled by protocol, product, outcome
  • gateway_protocol_inflight gauge labelled by protocol, product
  • gateway_protocol_request_duration_seconds histogram labelled by protocol, product
  • gateway_protocol_active_connections gauge labelled by protocol, product (for long-lived connections)

The middleware calls:

  • track(r) at request start to increment inflight (and sometimes active connections)
  • the returned closure at request end to record outcome, duration, and decrement gauges
  • hijacked(r) to handle websocket lifetime tracking for hijacked connections

Notes:

Protocol classification is heuristic by design. It uses standard headers and request metadata, but it is not a perfect protocol detector. Prefer stable "product" labels for long-term dashboards.

Contents

Imports

import block 1

pkg/gateway/server/protocol_metrics.go#L3
import (
"net/http"
"strings"
"time"

"github.com/prometheus/client_golang/prometheus"

gatewaymetrics "github.com/theroutercompany/api_router/pkg/gateway/metrics"
)

Types

type block 1

pkg/gateway/server/protocol_metrics.go#L13
type protocolMetrics struct {
requests *prometheus.CounterVec
inflight *prometheus.GaugeVec
duration *prometheus.HistogramVec
connections *prometheus.GaugeVec
}

protocolMetrics

What: Holds the Prometheus collectors used for protocol metrics.

Why: Groups related collectors so middleware can be wired with a single value rather than many globals.

How: Constructed by newProtocolMetrics and used by server middleware to emit metrics.

Notes: All fields are pointers to allow partial construction and nil-safety in the tracking functions.

Functions and Methods

newProtocolMetrics

What: Constructs and registers the protocol/product collectors.

Why: Centralizes metric names, help strings, label sets, and registration in one place.

How: Creates counters/gauges/histograms, registers them via reg.Register, and returns a protocolMetrics wrapper (or nil if the registry is nil).

Notes: Metric names are currently hard-coded (not namespaced) to keep dashboards stable.

pkg/gateway/server/protocol_metrics.go#L20
func newProtocolMetrics(reg *gatewaymetrics.Registry) *protocolMetrics {
if reg == nil {
return nil
}

requests := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "gateway_protocol_requests_total",
Help: "Count of proxied requests labelled by protocol, product, and outcome.",
}, []string{"protocol", "product", "outcome"})

inflight := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "gateway_protocol_inflight",
Help: "Current number of in-flight proxied requests by protocol and product.",
}, []string{"protocol", "product"})

duration := prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: "gateway_protocol_request_duration_seconds",
Help: "Upstream duration for proxied requests segmented by protocol and product.",
Buckets: prometheus.DefBuckets,
}, []string{"protocol", "product"})

connections := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "gateway_protocol_active_connections",
Help: "Current number of active upgraded connections (e.g., websockets) by protocol and product.",
}, []string{"protocol", "product"})

reg.Register(requests)
reg.Register(inflight)
reg.Register(duration)
reg.Register(connections)

return &protocolMetrics{
requests: requests,
inflight: inflight,
duration: duration,
connections: connections,
}
}

Walkthrough

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

  • L21: if reg == nil { return nil }
    • 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:
      • L22: return nil
        • 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).
  • L25: requests := prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "gateway_protocol_requests_total", Help: "Count of proxied requests labe…
    • What: Defines requests.
    • 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.
  • L30: inflight := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "gateway_protocol_inflight", Help: "Current number of in-flight proxied requ…
    • What: Defines inflight.
    • 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.
  • L35: duration := prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: "gateway_protocol_request_duration_seconds", Help: "Upstream duratio…
    • What: Defines duration.
    • 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: connections := prometheus.NewGaugeVec(prometheus.GaugeOpts{ Name: "gateway_protocol_active_connections", Help: "Current number of active up…
    • What: Defines connections.
    • 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.
  • L46: reg.Register(requests)
    • What: Calls reg.Register.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.
  • L47: reg.Register(inflight)
    • What: Calls reg.Register.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.
  • L48: reg.Register(duration)
    • What: Calls reg.Register.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.
  • L49: reg.Register(connections)
    • What: Calls reg.Register.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.
  • L51: return &protocolMetrics{ requests: requests, inflight: inflight, duration: duration, connections: connections, }
    • 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).

(*protocolMetrics).track

What: Produces a per-request tracking function for status/outcome/duration and inflight gauges.

Why: Keeps request lifecycle accounting together and lets middleware defer metric updates to the end of request handling.

How: Classifies protocol/product, increments inflight gauge (and optionally active connection gauge for long-lived protocols), then returns a closure that records outcome/duration and decrements gauges.

Notes: Non-positive status values are treated as 200 OK for metric labeling.

pkg/gateway/server/protocol_metrics.go#L59
func (m *protocolMetrics) track(r *http.Request) func(status int, elapsed time.Duration) {
if m == nil || r == nil {
return func(int, time.Duration) {}
}

protocol := classifyProtocol(r)
product := productFromRequest(r)

if m.inflight != nil {
m.inflight.WithLabelValues(protocol, product).Inc()
}

trackConnection := m.connections != nil && trackConnectionForProtocol(protocol)
if trackConnection {
m.connections.WithLabelValues(protocol, product).Inc()
}

return func(status int, elapsed time.Duration) {
if status <= 0 {
status = http.StatusOK
}

outcome := "success"
if status >= 400 {
outcome = "error"
}

if m.requests != nil {
m.requests.WithLabelValues(protocol, product, outcome).Inc()
}
if m.duration != nil {
m.duration.WithLabelValues(protocol, product).Observe(elapsed.Seconds())
}
if m.inflight != nil {
m.inflight.WithLabelValues(protocol, product).Dec()
}
if trackConnection {
m.connections.WithLabelValues(protocol, product).Dec()
}
}
}

Walkthrough

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

  • L60: if m == nil || r == nil { return func(int, time.Duration) {} }
    • 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:
      • L61: return func(int, time.Duration) {}
        • 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).
        • Nested steps:
          • L61: func(int, time.Duration) {}
            • What: Defines an inline function (closure).
            • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
            • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
  • L64: protocol := classifyProtocol(r)
    • What: Defines protocol.
    • 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.
  • L65: product := productFromRequest(r)
    • What: Defines product.
    • 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.
  • L67: if m.inflight != nil { m.inflight.WithLabelValues(protocol, product).Inc() }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L68: m.inflight.WithLabelValues(protocol, product).Inc()
        • What: Calls m.inflight.WithLabelValues(protocol, product).Inc.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
  • L71: trackConnection := m.connections != nil && trackConnectionForProtocol(protocol)
    • What: Defines trackConnection.
    • 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.
  • L72: if trackConnection { m.connections.WithLabelValues(protocol, product).Inc() }
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L73: m.connections.WithLabelValues(protocol, product).Inc()
        • What: Calls m.connections.WithLabelValues(protocol, product).Inc.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
  • L76: return func(status int, elapsed time.Duration) { if status <= 0 { status = http.StatusOK } outcome := "success" if status >= 400 { outcome …
    • 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).
    • Nested steps:
      • L76: func(status int, elapsed time.Duration) { if status <= 0 { status = http.StatusOK } outcome := "success" if status >= 400 { outcome = "erro…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L77: if status <= 0 { status = http.StatusOK }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L78: status = http.StatusOK
                • What: Assigns status.
                • 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.
          • L81: outcome := "success"
            • What: Defines outcome.
            • 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.
          • L82: if status >= 400 { outcome = "error" }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L83: outcome = "error"
                • What: Assigns outcome.
                • 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.
          • L86: if m.requests != nil { m.requests.WithLabelValues(protocol, product, outcome).Inc() }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L87: m.requests.WithLabelValues(protocol, product, outcome).Inc()
                • What: Calls m.requests.WithLabelValues(protocol, product, outcome).Inc.
                • Why: Performs side effects or delegates work to a helper.
                • How: Executes the expression statement.
          • L89: if m.duration != nil { m.duration.WithLabelValues(protocol, product).Observe(elapsed.Seconds()) }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L90: m.duration.WithLabelValues(protocol, product).Observe(elapsed.Seconds())
                • What: Calls m.duration.WithLabelValues(protocol, product).Observe.
                • Why: Performs side effects or delegates work to a helper.
                • How: Executes the expression statement.
          • L92: if m.inflight != nil { m.inflight.WithLabelValues(protocol, product).Dec() }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L93: m.inflight.WithLabelValues(protocol, product).Dec()
                • What: Calls m.inflight.WithLabelValues(protocol, product).Dec.
                • Why: Performs side effects or delegates work to a helper.
                • How: Executes the expression statement.
          • L95: if trackConnection { m.connections.WithLabelValues(protocol, product).Dec() }
            • What: Branches conditionally.
            • Why: Handles different execution paths based on runtime state.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L96: m.connections.WithLabelValues(protocol, product).Dec()
                • What: Calls m.connections.WithLabelValues(protocol, product).Dec.
                • Why: Performs side effects or delegates work to a helper.
                • How: Executes the expression statement.

(*protocolMetrics).hijacked

What: Returns a closure that decrements the websocket connection gauge when an upgraded connection closes.

Why: Websocket lifetimes outlive the HTTP handler call, so connection tracking must hook into the net.Conn close path.

How: Increments gateway_protocol_active_connections{protocol=\"websocket\"} and returns a function that decrements it; returns nil when the request is not websocket-classified.

Notes: The middleware is responsible for calling the returned closure exactly once on connection close.

pkg/gateway/server/protocol_metrics.go#L101
func (m *protocolMetrics) hijacked(r *http.Request) func() {
if m == nil || m.connections == nil || r == nil {
return nil
}

protocol := classifyProtocol(r)
if protocol != "websocket" {
return nil
}

product := productFromRequest(r)
m.connections.WithLabelValues(protocol, product).Inc()
return func() {
m.connections.WithLabelValues(protocol, product).Dec()
}
}

Walkthrough

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

  • L102: if m == nil || m.connections == nil || r == nil { return nil }
    • 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:
      • L103: return nil
        • 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).
  • L106: protocol := classifyProtocol(r)
    • What: Defines protocol.
    • 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.
  • L107: if protocol != "websocket" { return nil }
    • 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:
      • L108: return nil
        • 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).
  • L111: product := productFromRequest(r)
    • What: Defines product.
    • 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.
  • L112: m.connections.WithLabelValues(protocol, product).Inc()
    • What: Calls m.connections.WithLabelValues(protocol, product).Inc.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.
  • L113: return func() { m.connections.WithLabelValues(protocol, product).Dec() }
    • 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).
    • Nested steps:
      • L113: func() { m.connections.WithLabelValues(protocol, product).Dec() }
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L114: m.connections.WithLabelValues(protocol, product).Dec()
            • What: Calls m.connections.WithLabelValues(protocol, product).Dec.
            • Why: Performs side effects or delegates work to a helper.
            • How: Executes the expression statement.

trackConnectionForProtocol

What: Indicates whether a protocol should be tracked as an "active connection".

Why: Some protocols represent long-lived sessions where concurrency matters more than request count.

How: Returns true for sse and grpc; false for other protocols.

Notes: Websockets are tracked via (*protocolMetrics).hijacked because their lifetime extends beyond ServeHTTP.

pkg/gateway/server/protocol_metrics.go#L118
func trackConnectionForProtocol(protocol string) bool {
switch protocol {
case "sse", "grpc":
return true
default:
return false
}
}

Walkthrough

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

  • L119: switch protocol { case "sse", "grpc": return true default: return false }
    • What: Selects a branch from multiple cases.
    • Why: Keeps multi-case branching readable and explicit.
    • How: Evaluates the switch expression and executes the first matching case.
    • Nested steps:
      • L120: case "sse", "grpc":
        • What: Selects a switch case.
        • Why: Makes multi-branch control flow explicit and readable.
        • How: Runs this case body when the switch value matches (or when default is selected).
        • Nested steps:
          • L121: return true
            • 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).
      • L122: default:
        • What: Selects a switch case.
        • Why: Makes multi-branch control flow explicit and readable.
        • How: Runs this case body when the switch value matches (or when default is selected).
        • Nested steps:
          • L123: return false
            • 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).

classifyProtocol

What: Best-effort classification of a request into a protocol label string.

Why: Enables segmenting metrics by traffic shape without requiring every caller to pass explicit protocol metadata.

How: Checks for SSE (Accept/Content-Type), websocket upgrades (Upgrade/Connection), and gRPC (Content-Type, Grpc-Timeout, HTTP/2+TE trailers), otherwise returns http.

Notes: Returns unknown for a nil request.

pkg/gateway/server/protocol_metrics.go#L127
func classifyProtocol(r *http.Request) string {
if r == nil {
return "unknown"
}

accept := strings.ToLower(r.Header.Get("Accept"))
contentType := strings.ToLower(r.Header.Get("Content-Type"))

if strings.Contains(accept, "text/event-stream") || strings.HasPrefix(contentType, "text/event-stream") {
return "sse"
}

if upgrade := r.Header.Get("Upgrade"); upgrade != "" && strings.EqualFold(upgrade, "websocket") {
return "websocket"
}

if connection := r.Header.Get("Connection"); connection != "" && strings.Contains(strings.ToLower(connection), "upgrade") {
if strings.EqualFold(r.Header.Get("Upgrade"), "websocket") {
return "websocket"
}
}

if strings.HasPrefix(contentType, "application/grpc") {
return "grpc"
}

if r.Header.Get("Grpc-Timeout") != "" {
return "grpc"
}

if r.ProtoMajor == 2 && strings.Contains(strings.ToLower(r.Header.Get("TE")), "trailers") && strings.HasPrefix(contentType, "application/") {
return "grpc"
}

return "http"
}

Walkthrough

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

  • L128: if r == nil { return "unknown" }
    • 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:
      • L129: return "unknown"
        • 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).
  • L132: accept := strings.ToLower(r.Header.Get("Accept"))
    • What: Defines accept.
    • 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.
  • L133: contentType := strings.ToLower(r.Header.Get("Content-Type"))
    • What: Defines contentType.
    • 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.
  • L135: if strings.Contains(accept, "text/event-stream") || strings.HasPrefix(contentType, "text/event-stream") { return "sse" }
    • 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:
      • L136: return "sse"
        • 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).
  • L139: if upgrade := r.Header.Get("Upgrade"); upgrade != "" && strings.EqualFold(upgrade, "websocket") { return "websocket" }
    • 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:
      • L139: upgrade := r.Header.Get("Upgrade")
        • What: Defines upgrade.
        • 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.
      • L140: return "websocket"
        • 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).
  • L143: if connection := r.Header.Get("Connection"); connection != "" && strings.Contains(strings.ToLower(connection), "upgrade") { if strings.Equa…
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L143: connection := r.Header.Get("Connection")
        • What: Defines connection.
        • 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.
      • L144: if strings.EqualFold(r.Header.Get("Upgrade"), "websocket") { return "websocket" }
        • 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:
          • L145: return "websocket"
            • 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).
  • L149: if strings.HasPrefix(contentType, "application/grpc") { return "grpc" }
    • 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:
      • L150: return "grpc"
        • 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).
  • L153: if r.Header.Get("Grpc-Timeout") != "" { return "grpc" }
    • 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:
      • L154: return "grpc"
        • 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).
  • L157: if r.ProtoMajor == 2 && strings.Contains(strings.ToLower(r.Header.Get("TE")), "trailers") && strings.HasPrefix(contentType, "application/")…
    • 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:
      • L158: return "grpc"
        • 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).
  • L161: return "http"
    • 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).

productFromRequest

What: Derives the "product" label for a request.

Why: Product-level segmentation is useful for SLOs and on-call triage when multiple upstreams share the same gateway.

How: Prefers X-Router-Product header; otherwise falls back to URL path prefix heuristics (/v1/trade, /v1/task); returns unknown if nothing matches.

Notes: Header overrides allow callers (or upstream routers) to provide a more authoritative label than URL parsing.

pkg/gateway/server/protocol_metrics.go#L164
func productFromRequest(r *http.Request) string {
if r == nil {
return "unknown"
}

if product := r.Header.Get("X-Router-Product"); product != "" {
return product
}

path := r.URL.Path
switch {
case strings.HasPrefix(path, "/v1/trade"):
return "trade"
case strings.HasPrefix(path, "/v1/task"):
return "task"
default:
return "unknown"
}
}

Walkthrough

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

  • L165: if r == nil { return "unknown" }
    • 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:
      • L166: return "unknown"
        • 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).
  • L169: if product := r.Header.Get("X-Router-Product"); product != "" { return product }
    • 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:
      • L169: product := r.Header.Get("X-Router-Product")
        • What: Defines product.
        • 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.
      • L170: return product
        • 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).
  • L173: path := r.URL.Path
    • What: Defines path.
    • 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.
  • L174: switch { case strings.HasPrefix(path, "/v1/trade"): return "trade" case strings.HasPrefix(path, "/v1/task"): return "task" default: return …
    • What: Selects a branch from multiple cases.
    • Why: Keeps multi-case branching readable and explicit.
    • How: Evaluates the switch expression and executes the first matching case.
    • Nested steps:
      • L175: case strings.HasPrefix(path, "/v1/trade"):
        • What: Selects a switch case.
        • Why: Makes multi-branch control flow explicit and readable.
        • How: Runs this case body when the switch value matches (or when default is selected).
        • Nested steps:
          • L176: return "trade"
            • 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).
      • L177: case strings.HasPrefix(path, "/v1/task"):
        • What: Selects a switch case.
        • Why: Makes multi-branch control flow explicit and readable.
        • How: Runs this case body when the switch value matches (or when default is selected).
        • Nested steps:
          • L178: return "task"
            • 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).
      • L179: default:
        • What: Selects a switch case.
        • Why: Makes multi-branch control flow explicit and readable.
        • How: Runs this case body when the switch value matches (or when default is selected).
        • Nested steps:
          • L180: return "unknown"
            • 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