Skip to content

Python OpenTelemetry troubleshooting

Python-specific problems and their fixes. For the generic endpoint, token, and pipeline checks that apply to every language, see the shared checklist at the end.

Confirm the process is actually wrapped. opentelemetry-instrument must prefix the real server command — if it wraps a shell script or a process manager that re-execs your app, instrumentation is lost. Check that the exporter variables are set in the same environment the app runs in.

To isolate whether the problem is instrumentation or export, print spans to the console:

Terminal window
OTEL_TRACES_EXPORTER=console opentelemetry-instrument python app.py

If spans print but nothing reaches Osuite, the problem is export (see Exporter connectivity). If nothing prints, the problem is instrumentation (wrapper not applied, or no instrumentor for your framework).

Gunicorn and uWSGI fork worker processes from a master after startup. A TracerProvider with a BatchSpanProcessor created before the fork keeps its background export thread in the master only, so the workers that serve requests never flush spans.

Initialize the SDK inside a post-fork hook so each worker gets its own provider and export thread.

For Gunicorn, use a post_fork hook in the config file:

def post_fork(server, worker):
from telemetry import configure_telemetry
configure_telemetry()

Start Gunicorn with that config, and register your framework instrumentor inside configure_telemetry() (for example FlaskInstrumentor().instrument()):

Terminal window
opentelemetry-instrument gunicorn -c gunicorn.conf.py app:app --bind 0.0.0.0:8000

For uWSGI, enable threads and run the setup in a postfork decorator:

from uwsgidecorators import postfork
@postfork
def init_telemetry():
from telemetry import configure_telemetry
configure_telemetry()
Terminal window
uwsgi --http :8000 --module app:app --enable-threads --master

The configure_telemetry() function is the programmatic setup shown in the instrumentation overview.

Django development server: use —noreload

Section titled “Django development server: use —noreload”

manage.py runserver runs an autoreloader that forks a child process to serve requests. Under opentelemetry-instrument the parent is instrumented but the child serves traffic, so no traces appear. Run the dev server with --noreload:

Terminal window
opentelemetry-instrument python manage.py runserver --noreload

Production servers (Gunicorn, uWSGI) do not use the autoreloader; for those, see the fork hook above. The same forking behavior affects Uvicorn’s --reload and Flask’s debug reloader — disable them for instrumented runs.

If a library is not traced — no database spans, no framework spans — the instrumentor for it is probably not installed. opentelemetry-bootstrap -a install only adds instrumentors for libraries present when it ran. Rerun it after adding a dependency:

Terminal window
opentelemetry-bootstrap -a install

To confirm what is installed:

Terminal window
pip list | grep opentelemetry-instrumentation

You can also install a single instrumentor directly, for example the Redis one:

Terminal window
pip install opentelemetry-instrumentation-redis

If spans are created but nothing reaches Osuite, the exporter cannot deliver them. Work through these:

  • EndpointOTEL_EXPORTER_OTLP_ENDPOINT must be https://ingest.<region>.osuite.io:443 for your region.
  • TokenOTEL_EXPORTER_OTLP_HEADERS must be x-osuite-ingest-token=<your-ingest-token> with a current token.
  • Protocol — the distro defaults to OTLP over gRPC. If your network only allows HTTP, switch both the protocol and the transport: set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf. Keep the same endpoint.
  • TLS — port 443 uses TLS. Do not set OTEL_EXPORTER_OTLP_INSECURE=true against the Osuite ingest endpoint.

Surface export errors by turning up the SDK log level:

Terminal window
OTEL_LOG_LEVEL=debug opentelemetry-instrument python app.py

Export failures (auth, DNS, TLS, connection refused) are logged by the exporter’s retry loop. A successful export is silent.

No data in Osuite after a few minutes? Work through these checks.

  • Endpoint — confirm the exporter targets exactly ingest.<region>.osuite.io:443 for your region, over TLS.
  • Token — confirm the ingest header carries a valid <your-ingest-token> and has not been rotated.
  • Pipeline — confirm the signal you expect (traces, logs, or metrics) is wired into an active pipeline with the otlp/osuite exporter attached.
  • Export errors — check the application or Collector logs for OTLP export failures (auth, DNS, TLS, connection refused).
  • Network — confirm the host has outbound access to the ingest endpoint on port 443.
  • Timing — allow up to a minute for the first data to appear before assuming a failure.

Still stuck? Ask the Investigation Agent or contact support.