Skip to main content

dagster-otel

PyPI Python versions Release CI License: MIT

OpenTelemetry tracing for Dagster ops and assets -- with trace/span IDs correlated into your own log lines -- without giving up ownership of your op/asset definitions to a third-party decorator, and without monkeypatching Dagster internals.

Status: early release, self-tested locally against real Dagster runs (multiprocess, k8s_job_executor, retry-from-failure) + a real trace backend.

Table of Contents

Installation

pip install dagster-otel

Usage

from dagster import asset, job, op

from dagster_otel import traced

@op(...)                # Dagster's own @op still owns op-ness; @traced() is a thin
@traced()                # layer underneath. No @resource/required_resource_keys, no
def upstream_op(context) -> int:  # manual "root" step -- the first @traced() step to
    ...                            # run in a given run just becomes the root.

@op(...)
@traced()
def downstream_op(context, x: int) -> int:
    ...

@asset(...)
@traced()  # same decorator, works for assets too
def downstream_asset(context) -> None:
    ...

@op(...)
@traced  # bare works too, like @op/@asset themselves -- same as @traced()
def another_op(context) -> None:
    ...

@job(...)
def my_job():
    downstream_op(upstream_op())

Works across Dagster's multiprocess and k8s_job_executor executors: each step usually runs in its own process, sometimes on its own node, so trace context is propagated via Dagster's own run storage rather than in-process memory. See docs/design.md for how, and what's verified vs. still assumed.

For @dbt_assets, dagster_otel.dbt.traced_dbt() is a drop-in replacement for @traced() that additionally opens a child span per dbt node (model/seed/test), keyed by the real Dagster asset_key/check_name -- no changes needed to the function body:

from dagster_otel.dbt import traced_dbt

@dbt_assets(manifest=...)
@traced_dbt()
def my_dbt_assets(context, dbt: DbtCliResource):
    yield from dbt.cli(["build"], context=context).stream()

Configuration

Standard OTel environment variables -- nothing bespoke:

Variable Purpose
OTEL_SERVICE_NAME Names your service in the trace backend.
OTEL_EXPORTER_OTLP_ENDPOINT (or ..._TRACES_ENDPOINT) Where to send spans (e.g. http://localhost:4317). Required -- without one of these set, no real exporter is attached at all (see below).
OTEL_EXPORTER_OTLP_TRACES_TIMEOUT / ..._TIMEOUT Per-export timeout. Set this yourself if the default (2s) doesn't fit -- see docs/design.md for why a default exists at all (an unreachable collector otherwise blocked every step for ~7s).
OTEL_SDK_DISABLED Set to true to force no export regardless of the endpoint vars above.

@traced() reads these itself (idempotently) the first time it runs in a process -- there's nothing else to wire up, no @resource/required_resource_keys needed. Call configure() yourself only if you want configuration to happen eagerly (e.g. at Definitions load time) rather than lazily on first use.

Without OTEL_EXPORTER_OTLP_ENDPOINT/..._TRACES_ENDPOINT set, no real OTLP exporter is created at all -- spans are still created (propagation and log correlation keep working), just never sent anywhere, so trying @traced() with zero setup never makes a surprise network call. See docs/design.md for the one deliberate tradeoff this makes.

Nesting a whole run's trace under an external caller's (a CI/CD pipeline, a scheduler, another OTel-instrumented system) is a run tag, not an env var -- set EXTERNAL_TRACE_CONTEXT_TAG_KEY (exported from dagster_otel) at launch time:

from dagster_otel import EXTERNAL_TRACE_CONTEXT_TAG_KEY

carrier: dict[str, str] = {}
TraceContextTextMapPropagator().inject(carrier)  # from your own active span
my_job.execute_in_process(tags={EXTERNAL_TRACE_CONTEXT_TAG_KEY: json.dumps(carrier)})

Every root step in the run (the ones that would otherwise seed a fresh trace) checks for this tag first. See docs/design.md for the full verification.

Compatibility

Built and verified against Dagster 1.13.22 and opentelemetry-sdk 1.44.0 (pyproject.toml/uv.lock) -- this is the combination every behavior described here has actually been checked against, including the multiprocess/k8s_job_executor/ retry-from-failure verification in docs/design.md. pyproject.toml declares a much wider floor (dagster >= 1.5) since nothing here relies on version-specific Dagster internals beyond what's documented as an accepted-risk private-API dependency there -- but that wide range isn't individually spot-checked the way it is for dagster-prometheus-exporter. If you hit an incompatibility on another version, please open an issue.

Requires Python 3.10+ (matches Dagster's own floor).

Why this exists

See docs/design.md for the full rationale, including a comparison against prior art (formenergy-observability, a monkeypatch-based prototype) and the design decisions (no monkeypatching, decorators stack under Dagster's own @op/@asset rather than replacing it, log correlation via a public logging.Filter on context.log).

Contributing

See CONTRIBUTING.md for how to set up your toolchain, run checks locally, and submit a pull request. Bug reports and feature requests go through GitHub issues; a security vulnerability goes to SECURITY.md instead.

License

MIT -- see LICENSE.

Metadata

Release files for dagster-otel 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dagster-otel 0.2.0
File Size Uploaded
dagster_otel-0.2.0.tar.gz 249.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dagster-otel 0.2.0
File Interpreter ABI Platform
dagster_otel-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 275.9 kB

Release files / dagster_otel-0.2.0.tar.gz

Download URL dagster_otel-0.2.0.tar.gz
Size 249.7 kB
Tags Source
SHA-256 checksum
How to use checksums
f9b41b96571313d5369a657baafb5ad254011f265446064f9f18145c795ae9e7
BLAKE2b-256 checksum
How to use checksums
101bfff665c70cc0eeca85c69a2b01254cadb64c60ed62dba16aeb0f5b80b3e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / dagster_otel-0.2.0-py3-none-any.whl

Download URL dagster_otel-0.2.0-py3-none-any.whl
Size 26.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0b0ef32f8e6a60bdb4b8ec49ff34ca0ecdeb7af1eeffd8b4a16c7f7bddedddca
BLAKE2b-256 checksum
How to use checksums
4180407ca525ab111c4f7087e78a9433350cf714f9c5c6e34d3ff14f7b0a7092
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page