theauth.Config.Observability.
Why an adapter
OpenTelemetry, Prometheus, OpenCensus, Datadog, and friends all want to be the one true client. Picking one inside the library would push a 5+ MB transitive dependency on every consumer, even on the ones who use a different stack or no stack at all. Worse, the OpenTelemetry Go SDK has had multiple breaking 1.x bumps; pinning to one version locks every consumer to the same. The adapter sidesteps that. The library knows the spans it wants to emit and the metrics it wants to record; the consumer knows the backend it wants to send them to. Two narrow interfaces (Tracer, Metrics) bridge the two.
mcpresource/go.mod stays zero-dep. The observability surface lives entirely in the main theauth-go module; the MCP SDK never touches it.
Wiring
Observability get exactly the pre-2026-06-21 behavior.
Span catalog
Every instrumented operation opens a span at its entry point and closes it at return. The span name and the attributes it carries are listed below. On error the span receivesRecordError plus a status="error" attribute and an error_code="<stable code>" attribute matching models.TheAuthError.Code.
Span names are exported as
theauth.SpanOAuthToken etc. so dashboards reference them by symbol.
Metric catalog
LatencyBuckets is [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5] seconds. Consumers pre-registering Prometheus histograms MUST use the exact same slice.
Every metric name is exported as theauth.MetricOAuthTokenRequestsTotal etc.
Cardinality discipline
High-cardinality identifiers (client_id, user_id, session_id, IP) go on spans as attributes, NEVER on metric labels. The library enforces this at the call site by review; the public Labels type does not stop you putting a high-cardinality value in by hand. Prometheus operators should validate label sets via promtool check rules.
The fixed label sets the library uses:
grant_type: one ofauthorization_code,refresh_token,client_credentials,token-exchangestatus:successorerrorrule: one ofip,emailkind: one ofoauth_clienttenant_id: organization ULID or empty string
Adding a new instrument
- Add the name constant to
internal/observability/hooks.go. - Add the matching re-export in
observability.go. - Update this document with the metric / span row.
- Add the emit call at the service surface.
- Update the PR description’s span+metric matrix.
grep theauth.Metric in their config to find every name the library emits.