Skip to main content
In this lesson we dive into code-based (manual) instrumentation to understand how telemetry—traces, spans, metrics, and logs—is produced. Once you grasp manual instrumentation with the OpenTelemetry Tracing API, library-based auto-instrumentation becomes straightforward. Instrumentation = explicit telemetry calls in application code (via the OpenTelemetry API) so you can control:
  • 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.
OpenTelemetry architecture (quick recap)
The image is an overview of the OpenTelemetry architecture, illustrating various components such as the OpenTelemetry API, SDK, and Collector, along with integrations for Kubernetes and observability backends.
Key components and responsibilities:
ComponentPurposeExample / Notes
OpenTelemetry APILanguage-neutral contract you code against (tracing, metrics, logs, context)trace.get_tracer(...), start_span
SDKLanguage-specific implementation that records, samples, batchesTracerProvider, SpanProcessor
Span export pipelineBuffers/batches spans and passes to exportersSimpleSpanProcessor, BatchSpanProcessor
ExporterSends spans to backends (Console, OTLP, vendor)ConsoleSpanExporter, OTLPSpanExporter
Collector / BackendReceives, stores, and visualizes telemetryJaeger, Tempo, commercial APMs
What is manual (code-based) instrumentation?
The image explains manual or code-based instrumentation, describing it as a process where developers add telemetry calls using the OpenTelemetry API in their source code to control tracing, metadata capture, and telemetry signal creation.
Manual instrumentation means you explicitly call the OpenTelemetry API in your source:
  • create tracers,
  • start and end spans,
  • set attributes,
  • add events or record exceptions,
  • and handle context propagation.
This approach gives the most control and the most accurate representation of application behavior. Tracing API workflow
The image shows a "Tracing API Workflow" diagram with seven steps: Requesting a Tracer, Creating a Span, Sampling Decision, Span Processor, Applying SpanLimits, Exporting the Span, and Trace Visualization.
High-level flow:
  1. Configure a TracerProvider (SDK wiring).
  2. Request a Tracer.
  3. Create spans (start_span / start_as_current_span).
  4. Sampling decision — spans are recorded or dropped.
  5. SpanProcessor receives spans and enforces SpanLimits, batching/retrying as needed.
  6. Exporter sends spans to the configured backend (OTLP, Console, vendor exporter).
  7. Backend visualizes traces.
TracerProvider is the factory and central access point for tracers. The Context API binds spans into traces and supports propagation across process/network boundaries. Core Tracing API components and definitions
  • TracerProvider: provides Tracer instances (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.
Examples Basic application (no OpenTelemetry calls yet)
Instrumenting with the OpenTelemetry API only (no SDK configured)
  • 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.
Example (API-only; default no-op provider):
Run (no span output because no SDK exporter is configured):
This is the no-op (non-recording) behavior: the API calls work and maintain context, but attributes, events, and spans are not recorded or exported until an SDK is configured. No-op benefits
The image lists the benefits of No-Op in four points, highlighting code safety, telemetry readiness, TracerProvider compatibility, and secure API usage.
Why this design?
  • 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.
Wiring an SDK to produce recording spans To record and export spans you must configure an SDK TracerProvider and add a SpanProcessor + Exporter. The demo below uses SimpleSpanProcessor with ConsoleSpanExporter.
Run the instrumented application (Console exporter prints spans in a JSON-like format):
Notes:
  • The root span (main_function_span) will have parent_id: null indicating it is the root of the trace.
  • Resource attributes default to service.name: "unknown_service" unless you explicitly configure the Resource when creating the TracerProvider.
  • To send spans to a backend, swap ConsoleSpanExporter for an OTLP exporter (or another vendor exporter) and configure its endpoint (e.g., point it at your Collector).
Why the SDK is required
  • 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.
Language idioms
  • Python: tracer.start_as_current_span(...)
  • Java: tracer.spanBuilder(...).startSpan()
  • JavaScript: tracer.startSpan(...)
  • .NET: Activity-based starts
Core Tracing API functions and features
The image is a table describing the core features of a tracing API, including functions like get_tracer(), start_span(), set_attribute(), and add_event(), along with their descriptions and example usages.
Common operations (Python examples):
Key API operations:
  • 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 / with blocks) 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.
No-op, safe defaults, and concurrency
The image illustrates "No-Op Implementation: Safe Defaults" with three features: absence of SDK and NoOp tracers, safe code execution, and secure instrumentation.
OpenTelemetry falls back to no-op providers if no SDK is installed. This guarantees:
  • Instrumentation does not break applications.
  • Libraries may safely include instrumentation.
  • The same instrumentation starts producing telemetry when an SDK is wired.
All OpenTelemetry tracing components are safe for concurrent use.
The image is a diagram showcasing various tracing API components that are safe for concurrent use, including TracerProvider, Tracer, Span, Context, and Events/Links.
Example: a web server handling thousands of concurrent requests can use a single tracer instance; each request receives its own span context without manual locking. Best practices
The image displays a summary of best practices for using tracers, including setting up one TracerProvider globally, naming tracers per module, ending spans properly, setting span names wisely, and using context propagation for distributed tracing.
  • Configure one TracerProvider per 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.
That concludes this lesson on code-based (manual) instrumentation and the OpenTelemetry Tracing API. Links and references

Watch Video