rgoussu@goussu: ~/library/platform/observability-and-sre
~/library/platform/observability-and-sre cat opentelemetry.md

OpenTelemetry

# The vendor-neutral telemetry standard — the API/SDK/Collector split, the three signals with their data models, semantic conventions, OTLP and the OTEL_* env vars, and auto vs manual instrumentation per platform.

Conceptsaved 2026-08-11 #observability#opentelemetry#otel#tracing#metrics#otlp#instrumentation

Overview

OpenTelemetry (OTel) is the CNCF standard that ended the era of vendor-proprietary instrumentation: one API to instrument against, one wire protocol (OTLP) to export over, and any backend — Jaeger, Prometheus/Mimir, Tempo, Datadog, Honeycomb — on the receiving end. Its central design decision is the API / SDK / Collector split: libraries and application code depend only on the no-op-by-default API; the SDK, configured once at the composition root, decides sampling, processing, and export; and the Collector moves pipeline concerns (fan-out, filtering, vendor credentials) out of the process entirely. Instrument once, choose backends forever after.

Key points

  • API vs SDK: the API (Tracer, Meter, Logger providers) is a lightweight, dependency-safe facade — a library that instruments against it costs nothing when no SDK is installed. The SDK is the implementation the application wires: resource, samplers, processors, exporters. Never let library code touch SDK classes.
  • Collector = receiver → processor → exporter pipelines: receives OTLP (and Prometheus, Zipkin, …), processes (batching, memory limits, filtering, attribute redaction, tail sampling), exports to one or many backends. Run it as sidecar/daemonset agent or a central gateway; it is the fan-out point that keeps vendor choice out of app config.
  • Traces: a trace is a tree of spans — each with name, kind (server/client/internal/producer/consumer), attributes, timed events, links to other traces, and a status. Head sampling is configured in the SDK (parentbased_traceidratio is the sane default); tail sampling lives in the Collector.
  • Metrics: instruments on a Meter — Counter, UpDownCounter, Histogram, Gauge, plus async/observable variants for pull-style readings. Views rename, re-bucket, or drop attributes at SDK level; temporality (cumulative vs delta) is the exporter-dependent detail that bites when bridging to Prometheus (cumulative) vs some vendors (delta).
  • Logs: deliberately not a new logging API — a bridge from existing frameworks (Logback/Log4j appenders, a slog handler, a tracing layer, a pino transport) into the OTel log data model, so logs share Resource and trace context with the other signals.
  • Resource + semantic conventions: the Resource describes the emitter (service.name, service.version, deployment.environment) and is attached to all signals; semantic conventions standardize attribute names (http.request.method, http.response.status_code, db.system) so dashboards and alerts port across services and vendors.
  • OTLP: one protocol for all three signals — gRPC on 4317, HTTP/protobuf on 4318. Standard env vars configure any SDK without code: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES, OTEL_TRACES_SAMPLER, OTEL_PROPAGATORS, and OTEL_SDK_DISABLED=true as the kill-switch (12-factor telemetry).
  • Auto vs manual: auto-instrumentation (Java agent, Node registrations) gives HTTP/ DB/queue spans for free via bytecode or module patching; manual instrumentation adds the domain-meaningful spans and metrics. Frameworks increasingly ship OTel natively (build-time in Quarkus), replacing the generic agent.
  • The correlation story: propagators carry traceparent/baggage across services; trace_id/span_id stamped into log MDC joins logs to traces; exemplars attach sample trace-ids to histogram buckets, joining metrics to traces. That triangle is the payoff of adopting the standard end-to-end.

Details

Instrumentation per platform

Platform Auto / framework path Manual API entry
Java (generic) opentelemetry-javaagent (bytecode, zero code change) GlobalOpenTelemetry.getTracer(...), @WithSpan
Quarkus quarkus-opentelemetry extension — build-time wiring, traces + metrics + logs, OTLP by default CDI-injected Tracer / Meter
Spring Boot Actuator + micrometer-tracing-bridge-otel + opentelemetry-exporter-otlp (Micrometer API in front of the OTel SDK); alternatively the OTel Spring Boot starter or the agent Micrometer Observation API (one API → metrics + spans)
Micronaut micronaut-tracing-opentelemetry (+ -http for server/client filters) injected Tracer
Go no agent — explicit wiring: otelhttp.NewHandler / otelhttp.NewTransport, per-library contribs (otelgrpc, otelsql) otel.Tracer(...), otel.Meter(...)
Rust tracing-opentelemetry layer: existing tracing spans become OTel spans; opentelemetry_sdk + opentelemetry-otlp for the pipeline tracing macros stay the API
Node / TS NodeSDK (@opentelemetry/sdk-node) + getNodeAutoInstrumentations() (patches http, express, pg, …), loaded before app code (--require) @opentelemetry/api trace.getTracer(...)

Go and Rust have no auto-instrumentation worth the name — middleware wrappers at the edges plus manual spans is the idiom, which fits the hexagonal placement anyway: telemetry wiring belongs at the assembly point (parent note), and the domain never sees the SDK.

Minimal SDK wiring shape

Every language's setup reduces to the same four steps, done once in the composition root:

  1. Build a Resource (service.name at minimum — anonymous services are unfindable).
  2. Create provider(s) — TracerProvider with sampler + BatchSpanProcessor, MeterProvider with a periodic reader — pointing at an OTLP exporter.
  3. Register the propagator (W3C tracecontext + baggage is the default).
  4. Register globally, and flush/shutdown on exit — the batch processor holds data; skipping shutdown silently drops the tail of every process's telemetry.

Choosing what to emit

Semantic-convention attributes for the edges (HTTP, DB, messaging) come free with instrumentation libraries; the manual layer should add domain telemetry: a span per use case (command/query name as span name), business-meaningful attributes, and a small number of domain metrics (histograms cost cardinality — bound your label sets). One custom metric plus one custom span is enough to prove the pipeline end-to-end in a walking skeleton.

Related

Citations

[1] OpenTelemetry documentation [2] OTLP specification [3] OTel semantic conventions [4] SDK environment variables