obs

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var LevelVar = &slog.LevelVar{}

LevelVar is the runtime-adjustable log level for the process. External code (e.g. a debug endpoint) may call LevelVar.Set(slog.LevelDebug).

Functions

func HTTPMetricsMiddleware

func HTTPMetricsMiddleware(m *Metrics) func(http.Handler) http.Handler

HTTPMetricsMiddleware records http_requests_total and http_request_duration_seconds for every request. It must run outside PanicMiddleware so that panics are recorded with status 500: PanicMiddleware writes its 500 response through the responseWriter captured here.

It injects a *routeContainer into context; InstrumentedMux fills it with the matched route pattern so the defer can use it as a label value.

func HashToken

func HashToken(key, token string) string

HashToken returns the HMAC-SHA256 of token keyed with key, encoded as hex. Returns "" when key is empty so callers can omit the attr gracefully rather than leak raw tokens when SESSION_HMAC_KEY is not configured.

func Init

func Init(ctx context.Context, serviceName string) (func(), error)

Init configures the global slog logger and OTel TracerProvider:

  • JSON output to stdout, UTC timestamps, PII redaction
  • Log level from LOG_LEVEL env var (DEBUG/INFO/WARN/ERROR; default INFO)
  • "service.name" attr on every log record (OTel semantic convention)
  • OTLP/gRPC TracerProvider reading OTEL_EXPORTER_OTLP_* from env
  • W3C TraceContext propagator

If OTEL_EXPORTER_OTLP_ENDPOINT is not set, tracing is disabled (no-op provider) and a warning is logged. This allows local dev without a collector.

The shutdown func flushes pending spans with a 5-second timeout and must be called before the process exits (wire it to SIGTERM).

func Logger

func Logger(ctx context.Context) *slog.Logger

Logger returns the default slog logger pre-decorated with trace_id, span_id, request_id, and user.id extracted from ctx. Call this in handlers and services instead of bare slog.Info so every log line carries request context.

func NewRedactHandler

func NewRedactHandler(inner slog.Handler) slog.Handler

NewRedactHandler wraps inner with the default deny-list and regex patterns.

func PanicMiddleware

func PanicMiddleware(next http.Handler) http.Handler

PanicMiddleware recovers from panics in downstream handlers, logs the stack trace, marks the active span as an error, and returns 500.

func RequestIDFromContext

func RequestIDFromContext(ctx context.Context) (string, bool)

RequestIDFromContext returns the request ID stored in ctx, if any.

func RequestMiddleware

func RequestMiddleware(skipPaths ...string) func(http.Handler) http.Handler

RequestMiddleware assigns a request ID (trace ID when a span is active, UUIDv7 otherwise), sets X-Request-ID on the response, and logs a canonical request line at completion. It must run inside TraceMiddleware (span active) and after the auth middleware (user in context).

func SecurityEvent

func SecurityEvent(ctx context.Context, event string, attrs ...any)

SecurityEvent logs a security-relevant event at WARN level with log_type=security. It automatically attaches trace_id, span_id, request_id, source_ip, and user.id from ctx (via Logger). Callers supply event-specific attrs as key-value pairs.

Session tokens must be hashed before passing as attr values; use HashToken.

func SourceIPFromContext

func SourceIPFromContext(ctx context.Context) string

SourceIPFromContext returns the client IP injected by SourceIPMiddleware.

func SourceIPMiddleware

func SourceIPMiddleware(next http.Handler) http.Handler

SourceIPMiddleware extracts the client IP and injects it into context. X-Forwarded-For is only trusted when the connecting IP is in trustedCIDRs. Pass nil or empty slice to always use RemoteAddr (safe default, no proxy). Place this inside TraceMiddleware so the span is already active.

func SourceIPMiddlewareWithTrustedCIDRs

func SourceIPMiddlewareWithTrustedCIDRs(trustedCIDRs []*net.IPNet) func(http.Handler) http.Handler

SourceIPMiddlewareWithTrustedCIDRs is like SourceIPMiddleware but only trusts X-Forwarded-For when the connecting IP matches one of the trusted CIDR ranges.

func TraceMiddleware

func TraceMiddleware(next http.Handler) http.Handler

TraceMiddleware wraps next with otelhttp, starting an OTel span for every request and propagating W3C traceparent headers. It must be the outermost middleware so the span is active for all downstream code.

func UserAgentFromContext

func UserAgentFromContext(ctx context.Context) string

UserAgentFromContext returns the User-Agent injected by SourceIPMiddleware.

Types

type DBTracer

type DBTracer struct {
	// contains filtered or unexported fields
}

DBTracer is a composite pgx.QueryTracer that:

  • delegates to otelpgx for OTel span creation (one span per sqlc query)
  • records db_query_duration_seconds Prometheus histogram observations

Wire it into the pgxpool config before creating the pool:

config.ConnConfig.Tracer = obs.NewDBTracer(metrics.DBDuration)

func NewDBTracer

func NewDBTracer(hist *prometheus.HistogramVec) *DBTracer

NewDBTracer creates a DBTracer. Parameter capture is intentionally OFF (otelpgx default): query parameters include session tokens, user IDs, and PII. Enabling capture via otelpgx.WithIncludeQueryParameters() would leak them into the OTLP backend.

func (*DBTracer) TraceQueryEnd

func (t *DBTracer) TraceQueryEnd(ctx context.Context, conn *pgx.Conn, data pgx.TraceQueryEndData)

TraceQueryEnd is called after the query completes (success or error).

func (*DBTracer) TraceQueryStart

func (t *DBTracer) TraceQueryStart(ctx context.Context, conn *pgx.Conn, data pgx.TraceQueryStartData) context.Context

TraceQueryStart is called at the beginning of every Query, QueryRow, and Exec call — including those from sqlc via the database/sql stdlib bridge.

type InstrumentedMux

type InstrumentedMux struct {
	// contains filtered or unexported fields
}

InstrumentedMux wraps *http.ServeMux so that each dispatch uses mux.Handler to resolve the matched pattern and injects it as an otelhttp route tag. otelhttp will then rename the span to "{method} {pattern}" after the handler returns.

No changes to module Register functions are required.

func NewInstrumentedMux

func NewInstrumentedMux(mux *http.ServeMux) *InstrumentedMux

NewInstrumentedMux wraps mux with route-pattern tagging for OTel spans.

func (*InstrumentedMux) ServeHTTP

func (m *InstrumentedMux) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Metrics

type Metrics struct {
	// HTTPRequests counts completed HTTP requests.
	HTTPRequests *prometheus.CounterVec
	// HTTPDuration measures HTTP request latency end-to-end.
	HTTPDuration *prometheus.HistogramVec
	// DBDuration measures individual DB query latency by sqlc method name.
	DBDuration *prometheus.HistogramVec
}

Metrics holds the three core Prometheus instrumentation vectors. All label values must be bounded: use route patterns, HTTP methods, and status codes only. Never use raw URLs, user IDs, or resource IDs as label values — unbounded cardinality will cause Prometheus memory exhaustion.

func NewMetrics

func NewMetrics(reg prometheus.Registerer) *Metrics

NewMetrics creates and registers the three core metric vectors against reg.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL