Documentation
¶
Overview ¶
Package telemetry sets up OpenTelemetry tracing and metrics and structured logs correlated with requests and traces (ADR-0007).
Tracing is always on, so every log line written with a request context carries trace and span IDs. Spans and metrics are exported only when OTLP export is enabled; the exporters read the standard OTEL_EXPORTER_OTLP_* environment variables, as OpenTelemetry specifies. Metrics can also be scraped in the Prometheus format from Telemetry.MetricsHandler (ADR-0063).
By default Setup installs its providers and the W3C trace-context propagator as OpenTelemetry globals, which instrumentation libraries use. Call it once, from the composition root.
Stability: stable (ADR-0015, ADR-0054).
Index ¶
- Constants
- func NewLogHandler(h slog.Handler) slog.Handler
- func RecordRoute(router http.Handler) http.Handler
- type LogFormat
- type Option
- func WithLogFormat(f LogFormat) Option
- func WithLogLevel(l slog.Leveler) Option
- func WithLogTee(h slog.Handler) Option
- func WithLogWriter(w io.Writer) Option
- func WithOTLPExport(enabled bool) Option
- func WithPrometheus(enabled bool) Option
- func WithRuntimeMetrics() Option
- func WithSampleRatio(r float64) Option
- func WithSpanExporter(e sdktrace.SpanExporter) Option
- func WithTraceContextFrom(callers []netip.Prefix) Option
- func WithoutGlobals() Option
- type Telemetry
- func (t *Telemetry) HTTPMiddleware() func(http.Handler) http.Handler
- func (t *Telemetry) Logger() *slog.Logger
- func (t *Telemetry) MeterProvider() metric.MeterProvider
- func (t *Telemetry) MetricsHandler() http.Handler
- func (t *Telemetry) Shutdown(ctx context.Context) error
- func (t *Telemetry) TracerProvider() trace.TracerProvider
Constants ¶
const ( KeyRequestID = "request_id" KeyTraceID = "trace_id" KeySpanID = "span_id" KeyOrgID = "org_id" )
Log attribute keys added from the context.
Variables ¶
This section is empty.
Functions ¶
func NewLogHandler ¶
NewLogHandler wraps h so records logged with a context carry request_id, trace_id, span_id and org_id when available. Keys already present on the record are not added twice.
func RecordRoute ¶
RecordRoute wraps the application's router, normally the http.ServeMux at the end of the middleware chain, so Telemetry.HTTPMiddleware names the span and labels HTTP metrics with the route pattern the router matched, even when middleware between them replaced the request with r.WithContext:
handler := httpx.Chain(telemetry.RecordRoute(mux), tel.HTTPMiddleware(), auth, …)
Routes are the patterns registered in code, so they keep metric series bounded whatever paths clients request. Without HTTPMiddleware, RecordRoute does nothing.
Types ¶
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
An Option configures Setup.
func WithLogFormat ¶
WithLogFormat sets JSON (default, for production) or text (for local development) logs.
func WithLogLevel ¶
WithLogLevel sets the minimum log level. Default: info.
func WithLogTee ¶
WithLogTee also sends every log record to h, such as the development console's buffer of recent records (ADR-0065) or the hourly log archive (ADR-0079). h's Enabled decides which records it receives, independently of WithLogLevel, and it sees the request, trace and organisation attributes the logger adds. Given more than once, every handler receives every record. A nil h adds nothing. Default: none.
func WithLogWriter ¶
WithLogWriter sets where logs are written. Default: os.Stdout.
func WithOTLPExport ¶
WithOTLPExport enables exporting spans and metrics over OTLP/HTTP, configured by the standard OTEL_EXPORTER_OTLP_* environment variables.
func WithPrometheus ¶
WithPrometheus enables a Prometheus exporter, alongside OTLP export when both are on: Telemetry.MetricsHandler then serves every metric of the meter provider in the Prometheus text format (ADR-0063). The exporter uses its own registry, never Prometheus's global one. Default: off.
func WithRuntimeMetrics ¶
func WithRuntimeMetrics() Option
WithRuntimeMetrics records Go runtime metrics (memory, garbage collector goal, goroutines, GOMAXPROCS) with the OpenTelemetry runtime instrumentation. They are read from runtime/metrics when metrics are collected, so they cost nothing while no exporter is on. Default: off.
func WithSampleRatio ¶
WithSampleRatio sets the fraction of new traces sampled, from 0 to 1. Child spans follow their parent's decision. Default: 1.
func WithSpanExporter ¶
func WithSpanExporter(e sdktrace.SpanExporter) Option
WithSpanExporter adds a synchronous span exporter, for tests and custom backends.
func WithTraceContextFrom ¶
WithTraceContextFrom makes Telemetry.HTTPMiddleware continue the trace, and accept the baggage, of requests whose client address is in callers: gateways and internal services that start traces. Match addresses as the middleware sees them, after httpx.TrustedProxies. Requests from other addresses start a new trace linked to the incoming one. Default: none.
func WithoutGlobals ¶
func WithoutGlobals() Option
WithoutGlobals keeps Setup from installing OpenTelemetry globals.
type Telemetry ¶
type Telemetry struct {
// contains filtered or unexported fields
}
Telemetry holds the configured logger and OpenTelemetry providers.
func (*Telemetry) HTTPMiddleware ¶
HTTPMiddleware starts a server span for each request, records standard HTTP server metrics, and names the span after the matched http.ServeMux pattern (for example "GET /v1/projects/{id}") so traces group by route, not by raw path.
Incoming W3C trace context is untrusted by default: each request starts a new trace, sampled by WithSampleRatio, that links to the caller's span, and incoming baggage is ignored. A client can't hide its requests from tracing, force sampling, or join another request's trace. Requests from the callers given to WithTraceContextFrom continue their trace instead.
The span's client.address is the request's RemoteAddr, as resolved by httpx.TrustedProxies when installed before this middleware, never a raw X-Forwarded-For header. Metrics leave out server.address and server.port, which come from the client's Host header, and carry http.route, the matched pattern without its method, instead of the path.
http.ServeMux sets the pattern on the request it routes, which is a copy when a middleware between this one and the mux calls r.WithContext. Wrap the mux with RecordRoute so the route reaches spans and metrics anyway.
func (*Telemetry) MeterProvider ¶
func (t *Telemetry) MeterProvider() metric.MeterProvider
MeterProvider returns the meter provider.
func (*Telemetry) MetricsHandler ¶
MetricsHandler returns the Prometheus scrape handler enabled by WithPrometheus, or a handler answering 404 when it's off. Serve it on a separate listener bound to a private interface, never on the API's public address: it has no authentication, and metrics describe the service's routes and load.
Scrapes collect on demand. At most four run at once (others get 503), each for up to 10 seconds; collection errors are logged and the metrics that could be collected are still served.
func (*Telemetry) Shutdown ¶
Shutdown flushes and stops exporters. Register it first on the cleanup stack so it runs last.
func (*Telemetry) TracerProvider ¶
func (t *Telemetry) TracerProvider() trace.TracerProvider
TracerProvider returns the tracer provider.