Every observability vendor wants to be the place your traces live, which means every vendor ships its own SDK, its own span format, and its own idea of what an agent's LLM call attribute should be called. Instrument an agent directly against one vendor's SDK and you have coupled your entire agent codebase to that vendor's roadmap, pricing, and outages. Switching later means re-instrumenting every span in every tool call, not swapping a config value.
OpenTelemetry (OTel) exists to break that coupling. It is a CNCF-hosted, vendor-neutral specification plus a set of language SDKs for producing traces, metrics, and logs in a standard shape. You instrument your code once, against the OTel API, and then choose where the data goes — Honeycomb, Datadog, Arize Phoenix, an open-source Jaeger instance, or, as in every example in this lesson, nowhere at all except your own terminal — purely by swapping an exporter. The instrumentation in your agent loop does not change.
This lesson is about the mechanics of producing that data: the tracer/provider/exporter/processor model that every OTel SDK shares, the GenAI semantic conventions that make an LLM call span mean the same thing across every team that emits one, and context propagation, which is how a span created three function calls deep inside a tool handler still ends up correctly nested under the agent turn that triggered it. The shape of a trace as a whole — how spans compose into a tree that represents one agent run end to end — is the next lesson. Here, the concern is narrower: how do you get a span onto the wire at all, correctly, without blocking your agent or leaking data you shouldn't record?