Skip to main content

pkg/gateway/metrics/registry.go

Source

Overview

What:

Wraps a Prometheus registry with gateway-friendly defaults and small helper methods.

This package is intentionally tiny. It standardizes:

  • how the gateway creates a Prometheus registry
  • whether default Go/process collectors are registered
  • how the /metrics HTTP handler is exposed

Why:

Metrics wiring shows up in multiple places (server startup, tests, local tools).

Having a single constructor avoids subtle issues like:

  • registering default collectors multiple times (panic on duplicate registration)
  • forgetting to expose a handler for the correct registry (accidentally using the global Prometheus registry)
  • inconsistent naming conventions across packages

How:

Call NewRegistry(...) early during runtime wiring. It constructs an isolated prometheus.Registry, optionally registers the standard Go and process collectors, and returns a small wrapper.

Downstream code can then:

  • use Handler() to mount /metrics
  • use Register() to add custom collectors to the same registry
  • use Raw() for advanced Prometheus APIs when needed

Notes:

The namespace field is advisory. This package does not automatically rewrite metric names. If you want namespaced metrics, incorporate Registry.Namespace() when building collectors.

Contents

Imports

import block 1

pkg/gateway/metrics/registry.go#L3
import (
"net/http"
"strings"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

Types

type block 1

pkg/gateway/metrics/registry.go#L13
type Option func(*options)

Option

What: Functional option used to configure NewRegistry.

Why: Keeps the NewRegistry signature stable while allowing future tuning knobs.

How: Each option mutates an internal options struct.

type block 2

pkg/gateway/metrics/registry.go#L15
type options struct {
namespace string
registerDefaultCollectors bool
}

options

What: Internal settings used while constructing a Registry.

Why: Separates construction-time configuration from the exported wrapper type.

How: Populated by Option functions and read by NewRegistry.

type block 3

pkg/gateway/metrics/registry.go#L39
type Registry struct {
namespace string
registry *prometheus.Registry
}

Registry

What: Wrapper that holds the namespace string and the underlying Prometheus registry.

Why: Makes it easy to pass around "the gateway's registry" without exposing all Prometheus types everywhere.

How: Constructed by NewRegistry and consumed by server/runtime wiring and metrics producers.

Functions and Methods

WithNamespace

What: Sets an optional namespace string on the registry wrapper.

Why: Provides a shared convention for metric naming across packages without forcing it on every call site.

How: Trims whitespace and stores the namespace in internal options; later exposed via (*Registry).Namespace().

Notes: This does not automatically prefix metric names; callers must incorporate it when constructing metrics.

pkg/gateway/metrics/registry.go#L23
func WithNamespace(namespace string) Option {
return func(o *options) {
o.namespace = strings.TrimSpace(namespace)
}
}

Walkthrough

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

  • L24: return func(o *options) { o.namespace = strings.TrimSpace(namespace) }
    • 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:
      • L24: func(o *options) { o.namespace = strings.TrimSpace(namespace) }
        • 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:
          • L25: o.namespace = strings.TrimSpace(namespace)
            • What: Assigns o.namespace.
            • 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.

WithoutDefaultCollectors

What: Disables automatic registration of Go/process collectors.

Why: Useful in tests (avoid noisy metrics) and in embeddings where another component already registers collectors.

How: Sets registerDefaultCollectors to false in internal options.

pkg/gateway/metrics/registry.go#L31
func WithoutDefaultCollectors() Option {
return func(o *options) {
o.registerDefaultCollectors = false
}
}

Walkthrough

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

  • L32: return func(o *options) { o.registerDefaultCollectors = 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).
    • Nested steps:
      • L32: func(o *options) { o.registerDefaultCollectors = false }
        • 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:
          • L33: o.registerDefaultCollectors = false
            • What: Assigns o.registerDefaultCollectors.
            • 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.

NewRegistry

What: Constructs a new gateway metrics registry.

Why: Ensures each gateway runtime instance has an isolated Prometheus registry with consistent defaults.

How: Applies provided options, creates a new prometheus.Registry, optionally registers Go/process collectors, and returns a Registry wrapper.

pkg/gateway/metrics/registry.go#L46
func NewRegistry(opts ...Option) *Registry {
settings := options{
registerDefaultCollectors: true,
}
for _, opt := range opts {
if opt != nil {
opt(&settings)
}
}

reg := prometheus.NewRegistry()
if settings.registerDefaultCollectors {
reg.MustRegister(collectors.NewGoCollector())
reg.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
}

return &Registry{
namespace: settings.namespace,
registry: reg,
}
}

Walkthrough

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

  • L47: settings := options{ registerDefaultCollectors: true, }
    • What: Defines settings.
    • 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.
  • L50: for _, opt := range opts { if opt != nil { opt(&settings) } }
    • What: Iterates over a collection.
    • Why: Processes multiple elements with the same logic.
    • How: Executes a for ... range loop.
    • Nested steps:
      • L51: if opt != nil { opt(&settings) }
        • What: Branches conditionally.
        • Why: Handles different execution paths based on runtime state.
        • How: Evaluates the condition and executes the matching branch.
        • Nested steps:
          • L52: opt(&settings)
            • What: Calls opt.
            • Why: Performs side effects or delegates work to a helper.
            • How: Executes the expression statement.
  • L56: reg := prometheus.NewRegistry()
    • What: Defines reg.
    • 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.
  • L57: if settings.registerDefaultCollectors { reg.MustRegister(collectors.NewGoCollector()) reg.MustRegister(collectors.NewProcessCollector(colle…
    • What: Branches conditionally.
    • Why: Handles different execution paths based on runtime state.
    • How: Evaluates the condition and executes the matching branch.
    • Nested steps:
      • L58: reg.MustRegister(collectors.NewGoCollector())
        • What: Calls reg.MustRegister.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
      • L59: reg.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}))
        • What: Calls reg.MustRegister.
        • Why: Performs side effects or delegates work to a helper.
        • How: Executes the expression statement.
  • L62: return &Registry{ namespace: settings.namespace, registry: reg, }
    • 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).

(*Registry).Namespace

What: Returns the configured namespace string (or empty).

Why: Allows metric constructors in other packages to follow a consistent naming convention.

How: Returns r.namespace with nil-safety.

pkg/gateway/metrics/registry.go#L69
func (r *Registry) Namespace() string {
if r == nil {
return ""
}
return r.namespace
}

Walkthrough

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

  • L70: if r == 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:
      • L71: 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).
  • L73: return r.namespace
    • 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).

(*Registry).Handler

What: Returns an HTTP handler that serves Prometheus metrics for this registry.

Why: Keeps /metrics wiring simple and avoids accidentally using the global Prometheus registry.

How: Uses promhttp.HandlerFor(r.registry, ...) and returns http.NotFoundHandler() when the receiver/registry is nil.

pkg/gateway/metrics/registry.go#L78
func (r *Registry) Handler() http.Handler {
if r == nil || r.registry == nil {
return http.NotFoundHandler()
}
return promhttp.HandlerFor(r.registry, promhttp.HandlerOpts{})
}

Walkthrough

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

  • L79: if r == nil || r.registry == nil { return http.NotFoundHandler() }
    • 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:
      • L80: return http.NotFoundHandler()
        • 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).
  • L82: return promhttp.HandlerFor(r.registry, promhttp.HandlerOpts{})
    • 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).

(*Registry).Register

What: Registers a collector with this registry.

Why: Central place to add custom gateway metrics while sharing the same registry instance.

How: Calls MustRegister on the underlying registry when the receiver and collector are non-nil.

Notes: Prometheus MustRegister panics on registration errors (e.g., duplicate descriptors).

pkg/gateway/metrics/registry.go#L88
func (r *Registry) Register(c prometheus.Collector) {
if r == nil || r.registry == nil || c == nil {
return
}
r.registry.MustRegister(c)
}

Walkthrough

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

  • L89: if r == nil || r.registry == nil || c == 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:
      • L90: 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).
  • L92: r.registry.MustRegister(c)
    • What: Calls r.registry.MustRegister.
    • Why: Performs side effects or delegates work to a helper.
    • How: Executes the expression statement.

(*Registry).Raw

What: Exposes the underlying *prometheus.Registry.

Why: Some integrations need Prometheus APIs not covered by this wrapper.

How: Returns r.registry with nil-safety.

pkg/gateway/metrics/registry.go#L96
func (r *Registry) Raw() *prometheus.Registry {
if r == nil {
return nil
}
return r.registry
}

Walkthrough

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

  • L97: if 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:
      • L98: 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).
  • L100: return r.registry
    • 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).

Architecture

Reference

Neighboring source