Skip to main content
This article demonstrates zero-code (auto) instrumentation for Python applications using OpenTelemetry. We’ll:
  • Start with a minimal Flask app that has no OpenTelemetry packages.
  • Install the OpenTelemetry distro and OTLP exporter.
  • Use the auto-instrumentation tooling to capture traces and metrics without modifying application code.
  • Show a slightly more complex example that exercises HTTP and database instrumentation.
Relevant links:

1. Minimal Flask app (products.py)

This tiny Flask application is the whole codebase used for the initial demo.
Run it locally:
Quick verification with curl:
At this point there are no OpenTelemetry packages installed. Example pip freeze output (showing common packages but no OpenTelemetry):
Because this repository contains only products.py and no OpenTelemetry imports, it’s a perfect candidate to demonstrate zero-code (auto) instrumentation: we will add observability without changing application source.

2. Install OpenTelemetry distro and bootstrap instrumentation

Install the OpenTelemetry distro and the OTLP exporter, then let the bootstrapper add matching instrumentation libraries for installed packages:
What the bootstrap command does:
  • Scans installed packages in the environment (e.g., Flask, requests, psycopg).
  • Installs opentelemetry-instrumentation-* packages that correspond to detected libraries (for example opentelemetry-instrumentation-flask, opentelemetry-instrumentation-requests, opentelemetry-instrumentation-psycopg2).
You should see output naming the installed instrumentation packages:

3. Run the app with the OpenTelemetry auto-instrumentation tool

There are two equivalent ways to configure auto-instrumentation:
  • Pass configuration as CLI flags to opentelemetry-instrument.
  • Set OTEL_ environment variables and run opentelemetry-instrument without flags.
Compare the two approaches:
Configuration methodExample usageNotes
CLI flagsopentelemetry-instrument --traces_exporter console,otlp --metrics_exporter console --service_name products-service --exporter_otlp_endpoint http://localhost:4318 python products.pyFlags can be convenient for one-off runs.
Environment variablesexport OTEL_SERVICE_NAME=products-service
export OTEL_TRACES_EXPORTER=console,otlp
export OTEL_METRICS_EXPORTER=console
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
opentelemetry-instrument python products.py
Use env vars for reproducible deployments or containerized apps. See note about OTLP HTTP endpoint below.
When configuring OTLP over HTTP via environment variables, include the full path .../v1/traces (for traces). The CLI flag --exporter_otlp_endpoint may accept a host-only value and append the proper path automatically, but the environment variable OTEL_EXPORTER_OTLP_TRACES_ENDPOINT typically must include the full http://<host>:<port>/v1/traces URL.

Example: instrumenting and generating a trace (products)

Start the instrumented app using CLI flags (console exporter prints spans to stdout and OTLP forwards to the configured endpoint):
Generate a request:
The console exporter will emit JSON representations of spans. Representative (shortened) span output:
This trace shows the route, trace ID, span ID, span kind, start/end times and several automatically-added attributes provided by the Flask instrumentation package. If you export to a backend such as Jaeger (via an OpenTelemetry Collector or an OTLP receiver forwarding to Jaeger), you can view traces in the Jaeger UI:
The image shows a Jaeger trace UI displaying a trace for the "products-service" with a GET request, including details like HTTP method, status code, and various tags related to the operation.
All telemetry above was produced automatically by the Flask instrumentation package that opentelemetry-bootstrap -a install added—no changes to products.py were required.

4. Configure with environment variables (example)

A concise env-var example:
Verify environment variables:
If OTEL_EXPORTER_OTLP_TRACES_ENDPOINT omits /v1/traces, you may observe export failures such as “failed to export span batch” or HTTP 404/400 responses from the OTLP HTTP receiver. Including /v1/traces typically resolves that issue.

5. Demonstration: a slightly more complex app (crypto.py)

Next, we instrument a slightly richer example that uses Flask, requests, and psycopg2. Because instrumentation packages for these libraries are available and were installed by the bootstrap step, the application is auto-instrumented without source changes. Representative excerpts from crypto.py:
Flask route:
Fetch current Bitcoin price (HTTP call via requests):
Store the price in PostgreSQL (psycopg2):
Because Flask, requests, and psycopg2 were instrumented by the bootstrap step, running this application with opentelemetry-instrument captures multiple spans in a single trace:
  • Incoming Flask server span (HTTP server).
  • Outgoing HTTP client span (requests → CoinMarketCap).
  • Database spans for SQL statements (psycopg2) with db.* semantic attributes.
Run the instrumented crypto app:
Trigger the endpoint:
Inspect the trace in Jaeger or another OTLP-compatible backend to see the Flask server span, the outgoing HTTP span to pro-api.coinmarketcap.com, and DB spans showing executed SQL statements.
The image shows a Jaeger UI displaying trace timelines for a "crypto-service" GET request to "/price," with details on service operations and execution times.
Examples of DB statements that appear as spans (captured automatically):
All telemetry was produced automatically by the instrumentation libraries that were added by opentelemetry-bootstrap -a install—no code changes to crypto.py were required.

Summary & best practices

  • Auto-instrumentation enables zero-code observability for supported libraries (Flask, requests, psycopg2, etc.).
  • Install opentelemetry-distro and opentelemetry-exporter-otlp, then run:
    • opentelemetry-bootstrap -a install to add matching opentelemetry-instrumentation-* packages.
  • Run your application with opentelemetry-instrument using CLI flags or OTEL_ environment variables.
  • When using environment variables for OTLP HTTP traces endpoint, include /v1/traces in OTEL_EXPORTER_OTLP_TRACES_ENDPOINT.
  • Exported telemetry can be sent to console for debugging or to OTLP-compatible backends (via OpenTelemetry Collector) such as Jaeger.

Watch Video

Practice Lab