Romain Lefebvre
12/17/2025, 3:12 PMMarvin
12/17/2025, 3:12 PMMarvin
12/17/2025, 3:16 PMpip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
- Start the worker under the auto-instrumentation shim so it configures a global TracerProvider:
opentelemetry-instrument --traces_exporter otlp --service_name prefect-worker \
prefect worker start -p <your-pool>
- Set OTEL env vars in the worker Deployment (and in any custom flow-run image, if you use one):
OTEL_EXPORTER_OTLP_ENDPOINT=<http://otel-collector:4317>
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_TRACES_SAMPLER=parentbased_always_on
OTEL_RESOURCE_ATTRIBUTES=service.name=prefect-worker,service.namespace=prefect
- Result: Prefect’s built-in flow/task spans will be picked up and exported by the global SDK initialized by the shim.
2) Use the OpenTelemetry Operator (no entrypoint changes)
- Install the operator and an OTEL Collector in your cluster.
- Create an Instrumentation resource pointing at your collector and set desired sampler/propagators.
- Annotate your Prefect worker Deployment (and flow-run Jobs if desired) to inject Python auto-instrumentation. The operator will inject the SDK and set up the exporter automatically.
- Docs: OpenTelemetry Operator
3) Instrument Prefect Server (optional, for API/HTTP spans)
- If you also want traces from the Prefect Server API (FastAPI), run the server under opentelemetry-instrument or use the Operator to inject into the server pod. Add the same OTEL_* env vars and the FastAPI/ASGI instrumentation will export request spans.
A few notes
- Prefect’s orchestration tracing is enabled by default in 3.x; if you previously disabled it, re-enable it:
PREFECT_CLOUD_ENABLE_ORCHESTRATION_TELEMETRY=true
- There are no OTEL-specific Helm values today. You’ll either:
- Override container command/args and add env vars in your Helm values, or
- Use the OpenTelemetry Operator and add annotations.
- Prefect’s spans will “just work” once there is a global TracerProvider/exporter in the process.
References
- Prefect Helm chart: prefect-helm
- Prefect Server Helm guide: Server on Helm (docs)
- OTEL Python auto-instrumentation: OpenTelemetry Python automatic instrumentation
Questions to tailor the setup
- Which parts do you want traced: flow/task runs, worker processes, server API, or all of the above?
- Are you using the stock Prefect images or custom images for workers/flow runs?
- Which OTEL collector/backend are you targeting (endpoint/protocol)?Romain Lefebvre
12/17/2025, 3:19 PMMarvin
12/17/2025, 3:19 PMMarvin
12/17/2025, 3:21 PMjob_variables:
pod:
metadata:
annotations:
<http://instrumentation.opentelemetry.io/inject-python|instrumentation.opentelemetry.io/inject-python>: "true"
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: <http://otel-collector:4317>
- name: OTEL_EXPORTER_OTLP_PROTOCOL
value: grpc
- name: OTEL_RESOURCE_ATTRIBUTES
value: service.name=prefect-flow-run,service.namespace=prefect
- Docs: OpenTelemetry Operator
- Auto-instrumentation in your flow-run image (very low code)
- Bake the SDK into the image used for flow runs:
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
- Set OTEL_* env vars on the flow-run pods.
- Run the flow-run process under the shim (via your pod template/entrypoint), e.g.:
opentelemetry-instrument --traces_exporter otlp <your flow run command>
- If you can’t change the command, a tiny sitecustomize.py that sets a global TracerProvider + OTLP exporter on import also works, with no changes to your flow code.
Recommendations
- Instrument both: worker pods and flow-run pods. That ensures worker-side and flow/task spans all get exported and can be correlated.
- If you want server API traces as well, run the Prefect Server pod under opentelemetry-instrument or use the Operator to inject there too.
Helpful links
- Prefect Helm: prefect-helm
- Prefect Server on Helm: Server on Helm (docs)
- Kubernetes work pools (pod/job overrides/job variables): Kubernetes work pool docs
- OTEL Python auto-instrumentation: OpenTelemetry Python automatic instrumentation
If you can share:
- Whether your flow runs use a custom image
- If you’re open to using the OpenTelemetry Operator
- Your collector endpoint/protocol
…I can give you a concrete values.yaml/pod spec snippet for your setup.Romain Lefebvre
12/17/2025, 3:28 PMprefect[otel] isn't in it ?Marvin
12/17/2025, 3:28 PMMarvin
12/17/2025, 3:30 PMprefect[otel] only installs the OpenTelemetry packages. It does not automatically configure an OTLP exporter or initialize a TracerProvider.
What changes with prefect[otel]
- You now have the OTEL SDK, OTLP exporter, and auto-instrumentation tooling available in the environment.
- Prefect’s built-in flow/task spans are still created (that’s on by default), but they will remain no-op unless a global TracerProvider/exporter is initialized.
To actually export spans, you still need to initialize the OTEL SDK somewhere in the process. Easiest low/no-code options:
- Use the auto-instrumentation shim to start the process:
opentelemetry-instrument --traces_exporter otlp --service_name prefect-worker \
prefect worker start -p <your-pool>
And set env vars like:
OTEL_EXPORTER_OTLP_ENDPOINT=<http://otel-collector:4317>
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
OTEL_TRACES_SAMPLER=parentbased_always_on
OTEL_RESOURCE_ATTRIBUTES=service.name=prefect-worker
- Or use the OpenTelemetry Operator to inject the SDK/exporter into your worker and flow-run pods via annotations.
Key point: Prefect won’t start an exporter for you; once a TracerProvider is present (from auto-instrumentation or Operator injection), Prefect’s spans will be exported automatically.Nate
12/17/2025, 4:42 PMNate
12/17/2025, 4:42 PM