# AGENTS.md — obsx Universal guide for AI coding agents working with this codebase. ## Overview `git.codelab.vc/pkg/obsx` is a Go observability library providing Prometheus metrics and OpenTelemetry tracing setup with consistent defaults and isolated registries. ## Package map ``` obsx/ Root — tracing, metrics, config ├── doc.go Package documentation ├── tracer.go SetupTracer, StartSpan, TracerConfig ├── metrics.go Metrics factory, NewMetrics, Counter/Histogram/Gauge, Handler └── config.go (empty — configs are co-located with their components) ``` ## Architecture ``` ┌──────────────────────┐ │ obsx │ └──────────┬───────────┘ │ ┌───────────────┴───────────────┐ │ │ ┌──────┴──────┐ ┌──────┴──────┐ │ Tracing │ │ Metrics │ └──────┬──────┘ └──────┬──────┘ │ │ SetupTracer() NewMetrics() │ │ ▼ ▼ OTLP gRPC exporter prometheus.Registry TracerProvider (process + Go collectors) (global via otel.Set) │ │ Counter / Histogram / Gauge ▼ │ StartSpan() Handler() → /metrics ``` ## Common tasks ### Add a new metric type (e.g., Summary) 1. Add a method to `Metrics` struct in `metrics.go` 2. Create the Prometheus collector with `m.cfg.Namespace` / `m.cfg.Subsystem` 3. Register via `m.registry.MustRegister()` 4. Return the collector ### Change the trace exporter (e.g., HTTP instead of gRPC) 1. Replace `otlptracegrpc.New` in `SetupTracer` with the desired exporter 2. Update `TracerConfig` fields if the new exporter needs different options 3. Keep the same return signature (`shutdown func(context.Context) error`) ### Add custom resource attributes to traces 1. Append additional `resource.WithAttributes(...)` options to the `attrs` slice in `SetupTracer` 2. Use `semconv` constants where possible ## Gotchas - **SetupTracer sets the global provider**: calling it multiple times overwrites the previous provider; the old provider is not shut down automatically - **Isolated registry**: `NewMetrics` creates its own `prometheus.Registry`, not the global default. Metrics registered here will not appear in `promhttp.Handler()` — use `m.Handler()` instead - **Sampler default**: if `TracerConfig.Sampler` is 0 or negative, it defaults to 1.0 (sample everything), not 0 - **Insecure gRPC**: `SetupTracer` always uses `otlptracegrpc.WithInsecure()` — no TLS for the OTLP endpoint - **StartSpan tracer name**: uses the hardcoded tracer name `"obsx"` — all spans created via this helper share the same instrumentation scope ## Commands ```bash go build ./... # compile go test ./... # all tests go test -race ./... # tests with race detector go test -v -run TestName ./... # single test go vet ./... # static analysis ``` ## Conventions - **Struct-based Config** with `defaults()` method for zero-value defaults - **Isolated Prometheus registry** — each `Metrics` instance has its own registry - **stdlib only** testing — no testify, no gomock - **No functional options** — direct struct configuration - **Shutdown function** — `SetupTracer` returns a shutdown callback, caller is responsible for calling it