DEV Community

Cover image for OpenTelemetry API vs. SDK: Why the Difference (and Your Instrumentation) Matters
Ahmed Zidan for AWS Community Builders

Posted on • Originally published at relnx.io

OpenTelemetry API vs. SDK: Why the Difference (and Your Instrumentation) Matters

OpenTelemetry API vs. SDK: Why the Difference (and Your Instrumentation) Matters

Ask a team if they've "installed OpenTelemetry" and most will say yes without hesitation. Ask them to explain what, specifically, they installed, and the answers get vague fast. That vagueness isn't a knowledge gap you can shrug off — OpenTelemetry is not one thing. It's at least three distinct pieces working together, and mixing them up is one of the most common reasons teams end up with confidently configured pipelines that quietly emit almost nothing useful.

This post is about making that distinction concrete: the API, the SDK, and instrumentation libraries — what each one actually does, why the difference matters, and why instrumentation coverage deserves the same attention as SDK configuration, not an afterthought bolted on at the end.

The Three Pieces You're Actually Installing

1. The API — the vendor-neutral contract

The OpenTelemetry API defines the interfaces: Tracer, TracerProvider, Meter, MeterProvider, Logger, LoggerProvider, Span, context propagation. This is what libraries and application code call when they want to create a span or record a metric.

The crucial, and often surprising, detail: the API does nothing on its own. If no SDK has been registered, calling tracer.startSpan() is a safe no-op. That's deliberate design, not a bug. It's exactly what lets any library depend on the API without forcing a specific telemetry backend, exporter, or SDK version on every consumer of that library. A logging library, an HTTP client, a database driver — none of them should care where your spans end up. They should only care that they can create one if something is listening.

2. The SDK — the concrete implementation

The SDK is what turns API calls into actual telemetry. It's where samplers (deciding what to keep), processors (batching, transforming), exporters (shipping data via OTLP, to Jaeger, to Prometheus, to your vendor of choice), and resource detection (service.name, deployment environment, Kubernetes attributes) all live.

This is the piece that should only ever be installed and configured by the application — the final, deployable thing — never by a library. Only the application knows where its telemetry should actually go. A library that depends on the SDK instead of the API breaks the entire point of the API/SDK split: it silently forces its own SDK version and its own opinions about exporters onto everyone who depends on it.

3. Instrumentation libraries — the part that actually does the work

This is the piece that's easiest to forget, and the one this post is really about. Instrumentation libraries are what call the API on your behalf for a specific piece of code: your web framework, your database driver, your HTTP client, your message queue consumer, your gRPC layer. They're what turns "a request came in" into an actual span with the right attributes, the right parent/child relationships, and the right timing.

Without them, your SDK can be perfectly configured — correct exporter, correct endpoint, correct batching — and still export nothing meaningful, because nothing in your application is calling the API to create spans in the first place.

Instrumentation Is Critical

It's easy, when you think about installing OpenTelemetry in your application, to think only about installing the SDK. Pick your exporters, wire up a processor, point it at a collector, ship it. But the SDK on its own has no idea anything is happening inside your application — it only exports what actually gets handed to it. If nothing calls the API, there is nothing to export.

That's why instrumentation deserves the same deliberate attention as SDK configuration, not an afterthought. As part of any OpenTelemetry rollout, audit your application and confirm that the necessary library instrumentation is available and installed correctly for every dependency that actually matters to your request path — your web framework, your database client, your outbound HTTP client, your cache client, your queue library. It's common to instrument the top-level framework and call it done, while the database driver making the actual slow query, or the outbound call to a third-party API, quietly goes untraced.

A few concrete ways this bites teams:

  • The framework is instrumented, the HTTP client isn't. You get a clean span for the inbound request, and no visibility at all into the outbound call to a third-party API that's actually adding 600ms — usually the first thing anyone wants to see when debugging latency.
  • The endpoint is instrumented, the database driver isn't. You can see "this endpoint took 800ms" and have no idea it's a single unindexed query, because the query itself never became a span.
  • Auto-instrumentation covers the common cases and stops there. Agent-based auto-instrumentation is genuinely good at the popular frameworks and drivers, but internal RPC layers, less common ORMs, or a library on a version just outside the supported range often need manual instrumentation — or aren't covered at all, and nobody notices until someone goes looking for a trace that isn't there.

None of these failure modes throw an error. Your pipeline reports healthy. Your exporter reports successful sends. The gap is silent, which is exactly what makes it dangerous — it doesn't look broken, it just looks unusually quiet.

A Simple Audit Checklist

  • List every direct dependency your service actually calls at runtime: HTTP clients, database drivers, cache clients, queue clients, RPC frameworks.
  • For each one, check whether an OpenTelemetry instrumentation package exists and is installed — the OpenTelemetry registry is the canonical place to check.
  • Confirm the instrumentation package version actually matches the version of the library it instruments. Instrumentation packages track their target library closely, and compatibility can quietly break after a major version bump on either side.
  • Verify spans are actually showing up for each dependency, not just that the exporter reports success — an empty-but-successful pipeline looks identical to a healthy one in most dashboards.
  • Repeat the audit after upgrading the SDK, your instrumentation libraries, or the libraries they instrument. Compatibility ranges shift with every release.

Putting It Together

The flow, end to end, looks like this: your instrumentation libraries call the API as your code runs; the API hands that off to whatever SDK you've registered; the SDK's samplers, processors, and exporters decide what to keep and where to send it; and it lands in whatever backend you're running — an OpenTelemetry Collector, a vendor, or both.

If any one link in that chain is missing — no instrumentation for a dependency that matters, a forgotten SDK registration, a version mismatch — nothing fails loudly. That's exactly why this needs to be a deliberate audit, not an assumption you make because "OpenTelemetry is installed."

Why We're Building Relnx

Getting this right once isn't the end of the story — it's ongoing maintenance. New instrumentation packages ship, existing ones get compatibility fixes for the libraries they wrap, and the OpenTelemetry Collector itself ships new receivers, exporters, and breaking changes on a fast release cadence. Missing one of those updates is exactly how a working instrumentation setup quietly stops working after a routine dependency bump.

That's the problem we built Relnx to solve: tracking release notes, breaking changes, and new features across the tools your stack actually depends on — OpenTelemetry, its SDKs and instrumentation libraries, and the OpenTelemetry Collector included — so you find out about a breaking change from us, not from a silent gap in your traces.

You can see the current list of tools Relnx tracks at relnx.io/tools.

Top comments (0)