# 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 0–3) - 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.