Working prototype·Go·source →

libo11y

It provides one-call OpenTelemetry setup and enforces a machine-readable specification at runtime.

Why it exists

Service teams repeatedly write the same hundred-plus lines of OpenTelemetry bootstrap for resource composition, exporter wiring, propagator installation, log correlation, and shutdown ordering. Most implementations get at least one part wrong, and these failures are quiet and expensive. They can sever trace propagation, prevent logs from being joined to traces, drop buffered telemetry during shutdown, or allow a telemetry library to terminate its host process. libo11y packages the correct configuration once per language.

A second, broader motivation is that OpenTelemetry's semantic conventions include no machine-readable notion of sensitivity and no concept of required organizational identity. As a result, every service independently implements redaction through string matching. libo11y records those rules once in a versioned registry and enforces them with generated machinery instead of code review.

What it is

libo11y is a multi-language observability monorepo. A single call to o11y.Setup(ctx, o11y.WithServiceName("checkout")) builds tracer, meter, and logger providers over one shared resource. It installs the W3C TraceContext and Baggage propagators, establishes a correlated slog pipeline, enables runtime metrics and trace-based exemplars, and returns an SDK handle with an idempotent, deadline-bounded shutdown that reports per-signal failures through errors.Join. Application code then uses vanilla OTEL and stock slog. The library exports no span, metric, or log wrapper types because it wraps setup rather than instrumentation. Consequently, a consumer's codebase depends on it only through the single setup call.

The distinguishing component is the spec/ directory, which contains a semconv-format YAML registry. The registry defines a tiered resource-attribute taxonomy, including an explicit forbidden tier for attributes such as host.ip and process.command_line. It also defines a registered event catalog, cardinality budgets, and a per-attribute sensitivity class (public, internal, pii, secret) that OpenTelemetry does not provide. A generator validates the registry against a policy suite and produces typed Go constants, internal validation tables, and taxonomy documentation. A drift gate detects and rejects any inconsistency among them. Only the Go implementation currently exists; the Rust, Java, and Zig directories are stubs. A cross-language design contract includes a parity matrix that marks unbuilt items as planned or excluded.

How it works

The generated tables are required at runtime. During initialization, tier-0 identity is enforced with typed errors. Setup returns an error for a blank or unknown_service name or for an unregistered environment. It derives service.instance.id as a UUIDv5 over Kubernetes pod identity, so the value remains stable across restarts within the same pod. On the emit path, a sensitivity layer classifies each attribute by its effective dotted key after any user-supplied replacer runs. This prevents classification from being bypassed by nesting an attribute in a slog.Group or renaming it to a classified key. Secrets are always dropped, PII is hashed by default, and each action increments a self-metric. The same classification is applied at the span exporter boundary.

Three mechanisms implement most of the design.

  • Group resolution is implemented by the fanout slog.Handler. This keeps trace correlation attributes at the top level inside open groups while providing structurally identical records to every sink. The handler passes the stdlib slogtest suite.

  • The startup summary also serves as a canary because it passes through the entire log pipeline before any global is installed. A sink that rejects the summary therefore causes Setup to fail instead of silently dropping records in production. Similarly, a failed shutdown flush emits a registered dropped-telemetry event to the surviving sinks.

  • The capture-time redaction types (Secret[T], Masked, and tag-driven Struct) implement six rendering interfaces. This prevents any printf or JSON path from bypassing them, and unknown tags fail closed.

Why it matters

The design assumes that telemetry policy belongs in a specification rather than in convention. A typed API makes invalid states unrepresentable, initialization-time validation enforces identity, an always-on emit layer enforces sensitivity, and CI conformance tests detect code that bypasses the generated constants. Lock-in is deliberately avoided by supporting only standard OTEL_* variables, using no proprietary configuration, and keeping the pre-1.0 OTEL logs SDK out of the public API so that upstream changes cannot propagate through it. The Go module is complete for its scope, and 45 percent of its lines are tests that run under the race detector. A hermetic test harness allows consumers to assert conformance and correlation in their own builds. The roadmap covers the remaining three languages, which will be generated from the same registry.