Files
telemetry/docs/adr/ADR-001-tier5-app-only.md
Rene Nochebuena ed4e9ef161 feat(telemetry): initial stable release v0.9.0
Single-call OTel SDK bootstrap setting all three global providers (traces → Tempo, metrics → Mimir, logs → Loki) over OTLP gRPC.

What's included:
- New(ctx, Config): bootstraps TracerProvider, MeterProvider, and LoggerProvider with OTLP gRPC exporters; sets OTel globals
- W3C TraceContext + Baggage propagation set globally
- Resource tagging: service.name, service.version, deployment.environment merged with SDK defaults
- OTLPInsecure bool for development environments without TLS
- Sequential rollback on partial initialization failure — no dangling exporters on error
- Returns shutdown func(context.Context) error; caller defers in main or wires into launcher BeforeStop
- Tier 5 module: must be imported only by application main packages; zero micro-lib dependencies

Tested-via: todo-api POC integration
Reviewed-against: docs/adr/
2026-03-18 14:13:29 -06:00

34 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-001: Tier 5 — Application Bootstrap Only
**Status:** Accepted
**Date:** 2026-03-18
## Context
OpenTelemetry is structured around a separation between the **API** (stable, zero-cost when no SDK is wired) and the **SDK** (the real implementation, with exporters, batch processors, and gRPC connections). Any package can import the OTel API and call `otel.Tracer(...)`, `otel.Meter(...)`, etc. at zero runtime cost — these calls are no-ops until an SDK TracerProvider is set as the global.
The question is where in the module tier hierarchy the SDK bootstrap belongs. The options are:
1. Include telemetry bootstrap in each micro-lib that produces signals (e.g., httpserver starts its own SDK).
2. Provide a standalone bootstrap module imported only by application `main` packages.
Option 1 would cause multiple SDK initializations, competing global registrations, and make it impossible for the application to control the exporter endpoint or sampling strategy. It would also force all micro-libs to carry the heavy OTel SDK as a dependency even when the application does not use telemetry.
## Decision
The `telemetry` module is **Tier 5** — the same tier as application bootstrap entry points. It must only be imported by application `main` packages (or equivalent wiring code). It must never be imported by:
- Framework libraries (Tier 03)
- Transport modules (Tier 4)
- Other Tier 5 modules that are not themselves `main`
Micro-libs use only the OTel API packages (`go.opentelemetry.io/otel`, `go.opentelemetry.io/otel/metric`, `go.opentelemetry.io/otel/log`) which default to no-op providers. When an application imports `telemetry` and calls `telemetry.New(...)`, the three global providers are replaced with real SDK providers, and all micro-libs that use the global API automatically emit signals without any change to their code.
## Consequences
- No micro-lib needs to import or configure `telemetry`. The OTel no-op default means libraries compile and run correctly in unit tests without any collector present.
- Applications that do not call `telemetry.New(...)` produce no signals. This is correct — telemetry is opt-in at the application level.
- The `telemetry` module carries heavy SDK dependencies (OTLP gRPC exporters, batch processors). These do not appear in any library's dependency graph.
- Code review must reject any PR that imports `telemetry` from a non-`main` package. This is enforced by convention, not by a build tool currently.
- There is no `launcher.Component` wrapper for telemetry. The caller is responsible for deferring the shutdown function, which flushes all exporters before process exit.