- which operations are traced,
- which metadata (attributes/events/exceptions) is captured, and
- which signals are produced and exported.
This lesson uses
ConsoleSpanExporter so spans are visible on your console for demonstration. In production you would normally use an OTLP exporter (via the Collector) or a vendor-specific exporter.
| Component | Purpose | Example / Notes |
|---|---|---|
| OpenTelemetry API | Language-neutral contract you code against (tracing, metrics, logs, context) | trace.get_tracer(...), start_span |
| SDK | Language-specific implementation that records, samples, batches | TracerProvider, SpanProcessor |
| Span export pipeline | Buffers/batches spans and passes to exporters | SimpleSpanProcessor, BatchSpanProcessor |
| Exporter | Sends spans to backends (Console, OTLP, vendor) | ConsoleSpanExporter, OTLPSpanExporter |
| Collector / Backend | Receives, stores, and visualizes telemetry | Jaeger, Tempo, commercial APMs |

- create tracers,
- start and end spans,
- set attributes,
- add events or record exceptions,
- and handle context propagation.

- Configure a TracerProvider (SDK wiring).
- Request a
Tracer. - Create spans (
start_span/start_as_current_span). - Sampling decision — spans are recorded or dropped.
SpanProcessorreceives spans and enforcesSpanLimits, batching/retrying as needed.Exportersends spans to the configured backend (OTLP, Console, vendor exporter).- Backend visualizes traces.
- TracerProvider: provides
Tracerinstances (SDK-managed). - Tracer: used to start spans.
- Span: represents a single timed operation.
- SpanProcessor: processes spans (batching, exporting).
- SpanExporter: converts and sends span data to backends.
- Calling
trace.get_tracer(...)without setting a TracerProvider results in a no-op (non-recording) provider. Calls are safe, maintain context, and do not raise errors, but spans are non-recording and will not be exported.

- Safe: instrumentation calls won’t break an application if telemetry isn’t configured.
- Telemetry-ready: libraries and apps can include instrumentation before choosing a backend.
- Swappable: plug a real SDK and exporter later without changing instrumentation code.
TracerProvider and add a SpanProcessor + Exporter. The demo below uses SimpleSpanProcessor with ConsoleSpanExporter.
- The root span (
main_function_span) will haveparent_id: nullindicating it is the root of the trace. - Resource attributes default to
service.name: "unknown_service"unless you explicitly configure theResourcewhen creating theTracerProvider. - To send spans to a backend, swap
ConsoleSpanExporterfor an OTLP exporter (or another vendor exporter) and configure its endpoint (e.g., point it at your Collector).
- The API defines the contract (
get_tracer,start_span,set_attribute,add_event, etc.). - The SDK defines how spans are recorded, sampled, batched, and exported.
- Without the SDK, your instrumentation code is a safe no-op.
- Python:
tracer.start_as_current_span(...) - Java:
tracer.spanBuilder(...).startSpan() - JavaScript:
tracer.startSpan(...) - .NET: Activity-based starts

get_tracer(module_name): organize telemetry per module.start_span/start_as_current_span: create spans and manage lifecycle.set_attribute: attach key-value metadata to spans.add_event: record transient events (e.g.,"request_received").record_exception: attach exception details to a span.set_status: mark span success/failure.- End spans properly (use context managers /
withblocks) to correctly measure duration. - Context API & Propagators: preserve and propagate trace context across threads/processes and network boundaries.
- Baggage: small key-value pairs propagated across services.

- Instrumentation does not break applications.
- Libraries may safely include instrumentation.
- The same instrumentation starts producing telemetry when an SDK is wired.


- Configure one
TracerProviderper application (global or injected). - Use
get_tracer(__name__)or a per-module name to identify span origins. - End spans properly (prefer context managers /
with). - Name spans after the operation type (e.g.,
FetchUser,DatabaseQuery) — avoid embedding identifiers (FetchUser:alice). - Add attributes and follow semantic conventions whenever possible.
- Use context propagation (Propagators) for distributed tracing across services.
- Prefer configuring sampling and exporters outside application code so backends can be changed without modifying instrumentation.
- OpenTelemetry Documentation: https://opentelemetry.io/docs/
- Tracing specification: https://opentelemetry.io/docs/specs/otel/trace/
- OTLP Protocol: https://github.com/open-telemetry/opentelemetry-proto
- Collector: https://opentelemetry.io/docs/collector/intro/