Documentation
¶
Overview ¶
Package metrics provides shared histogram bucket presets, label-key constants, and emitter-ownership vocabulary for OpenTelemetry metrics across the ToolHive ecosystem.
The section and decision numbers cited throughout this package (e.g. "RFC §3.3", "D8") refer to the internal Stacklok Platform Metrics Standardization RFC, which defines the canonical vocabulary this package pins.
This package is construction helpers and vocabulary only: importing it installs no global providers and emits no metrics of its own. The one exception is RegisterBuildInfo, which registers an observable gauge on the meter the caller passes in — see "Build Info" below; it still constructs no meter or provider itself. Consumers (the ToolHive proxy, vMCP, and the registry) use the rest of this package to build their own instruments consistently.
Bucket Presets ¶
Three histogram bucket presets cover fast HTTP calls, MCP/proxy operations, and long-running operations such as sync, reconcile, or composite-tool execution. This package does not construct meters or instruments; callers import go.opentelemetry.io/otel and go.opentelemetry.io/otel/metric themselves and pass a preset's boundaries when constructing a histogram:
meter := otel.Meter("stacklok.toolhive.proxy")
histogram, err := meter.Float64Histogram(
"stacklok.toolhive.proxy.request.duration",
metric.WithExplicitBucketBoundaries(metrics.BucketsFastHTTP()...),
)
Label Keys ¶
Canonical label-key constants ensure every consumer spells the same concept the same way. As with the bucket presets, callers attach these to their own OTel instruments via go.opentelemetry.io/otel/attribute:
counter.Add(ctx, 1, metric.WithAttributes(
attribute.String(metrics.LabelOutcome, "success"),
))
This package exports only canonical common keys: concepts more than one component emits and that a cross-component dashboard joins or groups on. Component-local keys used by a single emitter are not exported here; they are defined by that component.
Emitter Ownership ¶
AttrStacklokComponent and AttrStacklokProduct are resource attributes (RFC §3.3, D8), not metric labels: a component sets them once on its OTel resource, and the Prometheus exporter promotes them to per-series labels via WithResourceAsConstantLabels. ProductStacklokPlatform is the frozen value every component stamps verbatim; the per-component stacklok.component value is supplied by each component, not enumerated here.
Build Info ¶
RegisterBuildInfo registers the fleet-wide stacklok.build_info observable gauge on a caller-provided meter, for release correlation across components:
err := metrics.RegisterBuildInfo(meter, "toolhive", version, commit)
Stability ¶
This package is Alpha stability. The API may change without notice. See the toolhive-core README for stability level definitions.
Index ¶
Constants ¶
const ( // LabelMCPServer identifies the upstream MCP server. LabelMCPServer = "mcp_server" // LabelOutcome carries the result of an operation. Its value is one of // "success", "error", or "rejected". LabelOutcome = "outcome" // LabelMCPMethod identifies the MCP method invoked. LabelMCPMethod = "mcp_method" // LabelToolName identifies the tool invoked. LabelToolName = "tool_name" // LabelCompositeTool identifies a vMCP composite tool. LabelCompositeTool = "composite_tool" // LabelTransport identifies the transport used (e.g. stdio, sse, http). LabelTransport = "transport" // LabelErrorType carries the failure classification on a Stacklok-authored // metric (coexists with semconv error.type on OTel semconv metrics). LabelErrorType = "error_type" )
Canonical label-key constants for Stacklok-authored metrics (RFC §3.3 label dictionary). One key per concept, snake_case, no boolean-typed keys.
This set is scoped to canonical common keys only: concepts more than one component emits and that a cross-component dashboard joins or groups on. Component-local keys used by only one emitter (e.g. operator reconcile's "phase", the circuit breaker's "from"/"to", the registry's "source") are defined by the emitting component, not exported here.
const ( // OutcomeSuccess marks a successful operation. OutcomeSuccess = "success" // OutcomeError marks a failed operation. OutcomeError = "error" // OutcomeRejected marks an operation refused before execution (e.g. rate // limited, circuit open, admission denied). OutcomeRejected = "rejected" )
Canonical outcome-label values. The LabelOutcome key carries one of these on a Stacklok-authored counter, distinguishing success from failure without a separate _succeed/_failed metric name (RFC §3.4 / D4). A metric may extend this set with a documented, bounded per-metric outcome where the standard three do not capture a distinct terminal state (e.g. the journal lifecycle outcomes, the vMCP optimizer's "not_found"); such extensions are owned by the emitting component, not exported here.
const ( // AttrStacklokComponent is the resource-attribute key naming the emitting // component. Each component supplies its own value. AttrStacklokComponent = "stacklok.component" // AttrStacklokProduct is the resource-attribute key naming the product. // Its value is frozen at ProductStacklokPlatform for every component. AttrStacklokProduct = "stacklok.product" )
Emitter-ownership resource attributes (RFC §3.3 / D8). Each Stacklok component stamps these two attributes on its OpenTelemetry resource; the Prometheus exporter promotes them to per-series labels (stacklok_component, stacklok_product) via WithResourceAsConstantLabels, so a single selector stacklok_product="stacklok-platform" spans the whole fleet, and stacklok_component distinguishes emitters.
These are resource attributes, not metric labels: they are set once on the provider, not per instrument. Do not attach them via attribute.String on an individual Record/Add call — that would collide with the exporter-promoted per-series label of the same name. See buildinfo.go's RegisterBuildInfo for a parallel, deliberately distinct bare-string "component" label attached per data point.
This package defines only the attribute keys, not the per-component value strings: each component supplies its own AttrStacklokComponent value (e.g. "toolhive", "registry", "ai_gateway"). A foundational library names the concept, not the roster of apps that consume it.
const BuildInfoMetricName = "stacklok.build_info"
BuildInfoMetricName is the fleet-wide build/release-correlation gauge. It is the one Stacklok-authored metric with no <service> segment (RFC §3.4), shared verbatim by every component.
const ProductStacklokPlatform = "stacklok-platform"
ProductStacklokPlatform is the frozen stacklok.product value stamped by every component. Unlike the per-component AttrStacklokComponent value, this one string is shared verbatim across the whole fleet: a single selector stacklok_product="stacklok-platform" spans every emitter, so the value must not drift per component. It is deliberately "stacklok-platform" (not "stacklok-enterprise") so it survives the toolhive-enterprise to toolhive-platform rename; the value lands in customer dashboards and must not churn.
Variables ¶
This section is empty.
Functions ¶
func BucketsFastHTTP ¶
func BucketsFastHTTP() []float64
BucketsFastHTTP returns the histogram bucket boundaries, in seconds, for fast HTTP-class measurements (RFC §3.3: 0.005-10).
func BucketsLongRunning ¶
func BucketsLongRunning() []float64
BucketsLongRunning returns the histogram bucket boundaries, in seconds, for long-running measurements such as sync, reconcile, or composite-tool durations (RFC §3.3: 0.1-300).
func BucketsMCPProxy ¶
func BucketsMCPProxy() []float64
BucketsMCPProxy returns the histogram bucket boundaries, in seconds, for MCP/proxy operation measurements (RFC §3.3: 0.01-300).
func RegisterBuildInfo ¶
RegisterBuildInfo registers the stacklok.build_info observable gauge on the given meter. The gauge always observes 1; the identity rides its labels (component, version, commit). Empty version/commit fall back to unknownBuildInfoValue.
The component label uses the bare "component" key, not the dotted stacklok.component resource attribute (AttrStacklokComponent), so it does not collide with the stacklok_component constant label the Prometheus exporter promotes from the resource (D8). Pass the caller's own component value (the same string it stamps as AttrStacklokComponent).
As with the rest of this package, RegisterBuildInfo is a construction helper: the caller supplies the meter (typically otel.Meter(scope) after installing its provider). It registers no global state of its own.
Types ¶
This section is empty.