OpenTelemetry: A Practical Adoption Guide
OpenTelemetry (OTel) is an open source observability framework that provides a standardized way to instrument applications for metrics, logs, and distributed traces. It includes instrumentation libraries for most languages, a data collector (the OTel Collector), and a common export format (OTLP) that sends data to any compatible observability backend. Adopting OpenTelemetry for instrumentation means the application code does not change when the observability backend changes.
What you need to know
- OpenTelemetry is the instrumentation standard that stays neutral between vendors. Instrument once, export to any backend. New projects should adopt OTel rather than agents tied to one vendor.
- Automatic instrumentation covers the majority of observable operations in a service (HTTP, database, messaging) without code changes. Start there before adding custom spans.
- The OTel Collector is optional for small setups. Services can export directly to a backend via OTLP. Add the Collector when you need to fan out to multiple backends or do processing before export.
- OpenTelemetry traces, metrics, and logs are three separate data types with different levels of OTel maturity. Traces are the most mature and where most teams start. Metrics support is stable enough for production. Logs are the most recently stabilized.
- The hardest part of OpenTelemetry adoption is not instrumentation; it is context propagation: ensuring trace IDs flow correctly through async operations, message queues, and calls across services.
The core argument
OpenTelemetry has reached the maturity point in 2026 where adopting anything else for new service instrumentation is a deliberate decision to accept being locked into one vendor. The automatic instrumentation libraries are stable, the OTLP export format is widely supported, and the operational overhead of the OTel Collector is modest. Teams that instrument with Datadog agent or New Relic agent today will pay the cost of instrumenting everything again when they switch backends; teams that instrument with OpenTelemetry will not.
The practical adoption path for a Node.js service starts with two packages: @opentelemetry/sdk-node for the SDK and @opentelemetry/auto-instrumentations-node for framework coverage. The initialization code runs before the application starts, configures the OTLP exporter to point at the backend, and sets resource attributes (service name, version, environment). From that point, every HTTP request handled by Express, every database query through pg or mysql2, and every HTTP request made by the service with Axios or node-fetch generates a span that appears in the observability backend. This is a meaningful amount of observability before writing a single custom span.
The step after automatic instrumentation is adding custom spans for the operations that matter most to the business and that frameworks do not cover: payment processing, job queue work, complex calculations, file processing. A custom span wraps a business operation and records its duration, success, and relevant attributes (user ID, order ID, file size). The resulting traces show the full picture of a request: the HTTP layer, the database queries, the business logic operations, and the outgoing calls, all linked by the trace ID and organized in a flame graph that makes performance analysis and debugging straightforward.
Common mistakes
Not initializing OpenTelemetry before other imports. The OTel SDK must be initialized before any instrumented libraries are imported, because instrumentation patches are applied when the module is first loaded. An initialization file that is imported at the very top of the entry point, before any other imports, ensures the patches are applied correctly.
Exporting to a backend that does not support OTLP natively. Some older backends require the OTel Collector with a translation layer (OTLP to Prometheus format, for example). Choosing a backend that natively accepts OTLP removes the Collector requirement for simple setups.
Not propagating trace context across message queues. When a service sends a message to a queue, the trace context (trace ID, span ID) must be injected into the message headers. When the consuming service processes the message, it must extract the trace context from the headers and create a child span. Without this, traces break at async boundaries and the distributed trace is fragmented.
Adding too many custom attributes to spans. Spans with hundreds of attributes are expensive to store and export. Add attributes that are genuinely useful for filtering and drilling into traces: user ID, tenant ID, resource type, error code. Avoid adding large payloads (request bodies, response bodies) as span attributes.
Not sampling at the SDK level for services with heavy traffic. At high request volume, exporting 100 percent of traces is prohibitively expensive. Configure sampling in the OTel Collector after a trace completes, or in the SDK as it starts, to reduce export volume while retaining traces for errors and slow requests.
Where to start
Install and initialize the OTel SDK with automatic instrumentation on one service. For Node.js, this is an initialization change contained in a single file. Verify that spans appear in the backend for standard HTTP requests and database queries. This establishes that the instrumentation pipeline works before adding custom spans.
Add custom spans for the three operations most critical to the business. Identify the operations that take the longest, fail the most, or are most important to monitor. Wrap each in a span with relevant attributes. These custom spans immediately make the traces more useful than automatic instrumentation alone.
Add trace context propagation through any async boundaries. If the service puts messages on a queue or calls a background job, ensure the trace context is injected into the message and extracted by the consumer. This produces traces that run start to finish across service and queue boundaries.
- CI/CD Pipeline Design That Scales Past Ten Engineers
FAQ
Frequently asked
- What problem does OpenTelemetry solve?
- What are the three components of OpenTelemetry?
- What is automatic instrumentation and how much does it cover?
- What backends are compatible with OpenTelemetry?
- How long does it take to instrument a service with OpenTelemetry?
Author
The person behind Yashveer Labs
Yashveer Singh, founder of Yashveer Labs. I build full stack systems for clients who care that the thing actually works two years later, not just on launch day. The arc I am on points at machine learning, AI engineering, and cybersecurity. Everything I write here comes from the codebase, not from a content brief. That is the difference and it shows.