Skip to content

Commit bda675b

Browse files
feat: dagster_runs_to_otlp + dagster_runs_to_splunk_hec sensors (v0.10.19)
Fills the gap in the dagster_runs_to_<destination>_sensor family — we had Prometheus (Push Gateway / VM remote_write) + InfluxDB (line protocol), but neither OTLP-direct nor Splunk-HEC-direct. Now all four destinations are covered with the same @run_status_sensor pair shape (SUCCESS + FAILURE). dagster_runs_to_otlp_sensor: - OTLP/HTTP wire (one wire, many backends — Splunk via Splunk OTC, Datadog OTel ingest, Honeycomb, Sumo, Loki via OTC, etc.) - LogRecord per event: body + severityNumber (9 INFO / 17 ERROR) + attributes (dagster.run_id, dagster.job_name, dagster.status, dagster.duration_seconds, dagster.failure_step on failures) - Resource attrs: service.name + service.instance.id - Failures get failure_step + first 500 chars of error in attrs - Parallels the existing dagster_failures_to_otlp_sensor (which is failures-only) — pick whichever fits the destination dagster_runs_to_splunk_hec_sensor: - Splunk-native HEC payload (single-hop direct, no OTel Collector) - One HEC event per run with structured fields: dagster_run_id, dagster_job_name, dagster_status, dagster_duration_seconds, dagster_failure_step - Splunk Web query patterns documented in README (p95 duration, failure rate by job, failure step distribution) - Distinct from compute_log_managers/splunk/ (op stdout/stderr, instance layer) and audit_logs_to_splunk (audit DataFrames, scheduled) Manifest: 834 → 836 components. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 61543c2 commit bda675b

14 files changed

Lines changed: 855 additions & 3 deletions

File tree

manifest.json

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"version": "1.0.0",
33
"repository": "https://github.com/eric-thomas-dagster/dagster-component-templates",
4-
"last_updated": "2026-05-28",
4+
"last_updated": "2026-06-04",
55
"components": [
66
{
77
"id": "ab_controls",
@@ -4472,6 +4472,41 @@
44724472
"last_validated": "2026-05-28"
44734473
}
44744474
},
4475+
{
4476+
"id": "dagster_runs_to_otlp_sensor",
4477+
"name": "Dagster Runs \u2192 OTLP Sensor",
4478+
"category": "sensor",
4479+
"description": "Push Dagster run lifecycle events (success + failure) as OTLP/HTTP log records to any OTel-compatible backend (Splunk via Splunk OTC, Datadog, Honeycomb, Sumo, Loki via OTC).",
4480+
"version": "1.0.0",
4481+
"author": "Dagster Community",
4482+
"path": "sensors/dagster_runs_to_otlp_sensor",
4483+
"tags": [
4484+
"sensor",
4485+
"telemetry",
4486+
"otlp",
4487+
"opentelemetry",
4488+
"honeycomb",
4489+
"datadog",
4490+
"splunk",
4491+
"sumo",
4492+
"observability"
4493+
],
4494+
"vendor": "OpenTelemetry",
4495+
"dependencies": {
4496+
"pip": [
4497+
"requests>=2.28"
4498+
]
4499+
},
4500+
"readme_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_otlp_sensor/README.md",
4501+
"component_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_otlp_sensor/component.py",
4502+
"schema_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_otlp_sensor/schema.json",
4503+
"example_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_otlp_sensor/example.yaml",
4504+
"requirements_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_otlp_sensor/requirements.txt",
4505+
"validation": {
4506+
"level": "code",
4507+
"last_validated": "2026-06-04"
4508+
}
4509+
},
44754510
{
44764511
"id": "dagster_runs_to_prometheus_sensor",
44774512
"name": "Dagster Runs \u2192 Prometheus Sensor",
@@ -4504,6 +4539,37 @@
45044539
"last_validated": "2026-05-28"
45054540
}
45064541
},
4542+
{
4543+
"id": "dagster_runs_to_splunk_hec_sensor",
4544+
"name": "Dagster Runs \u2192 Splunk HEC Sensor",
4545+
"category": "sensor",
4546+
"description": "Push Dagster run lifecycle events (success + failure) directly to Splunk via HTTP Event Collector (HEC). One hop, no OTel Collector required.",
4547+
"version": "1.0.0",
4548+
"author": "Dagster Community",
4549+
"path": "sensors/dagster_runs_to_splunk_hec_sensor",
4550+
"tags": [
4551+
"sensor",
4552+
"telemetry",
4553+
"splunk",
4554+
"hec",
4555+
"observability"
4556+
],
4557+
"vendor": "Splunk",
4558+
"dependencies": {
4559+
"pip": [
4560+
"requests>=2.28"
4561+
]
4562+
},
4563+
"readme_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_splunk_hec_sensor/README.md",
4564+
"component_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_splunk_hec_sensor/component.py",
4565+
"schema_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_splunk_hec_sensor/schema.json",
4566+
"example_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_splunk_hec_sensor/example.yaml",
4567+
"requirements_url": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/sensors/dagster_runs_to_splunk_hec_sensor/requirements.txt",
4568+
"validation": {
4569+
"level": "code",
4570+
"last_validated": "2026-06-04"
4571+
}
4572+
},
45074573
{
45084574
"id": "dagstermill_notebook_asset",
45094575
"name": "DagstermillNotebookAsset",
@@ -24453,5 +24519,5 @@
2445324519
],
2445424520
"schema_spec": "https://raw.githubusercontent.com/eric-thomas-dagster/dagster-component-templates/main/schema-spec.json",
2445524521
"schema_spec_local": "schema-spec.json",
24456-
"total": 834
24522+
"total": 836
2445724523
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "dagster-community-components"
7-
version = "0.10.18"
7+
version = "0.10.19"
88
description = "Community-maintained Dagster components — ingestion, transforms, IO managers, sensors, sinks, resources, and more."
99
readme = "README.md"
1010
requires-python = ">=3.10"
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# dagster_runs_to_otlp_sensor
2+
3+
Push **Dagster run lifecycle events** (success + failure) as OTLP/HTTP log records to any OpenTelemetry-compatible backend — Splunk via Splunk OTel Collector, Datadog OTel ingest, Honeycomb, Sumo Logic OTel, Grafana Loki via OTel Collector, etc.
4+
5+
Operational telemetry — distinct from the data-plane `dataframe_to_otlp_logs` sink. Parallels the existing `dagster_runs_to_prometheus_sensor` (Push Gateway / VM) and `dagster_runs_to_influxdb_sensor` — same `@run_status_sensor` pair (SUCCESS + FAILURE), different wire protocol.
6+
7+
For failure-only OTLP shipment with richer error context, see `dagster_failures_to_otlp_sensor` — both can run side-by-side.
8+
9+
## What lands at the backend per run-status event
10+
11+
One OTLP `LogRecord` per run completion:
12+
13+
| Field | Value |
14+
|---|---|
15+
| `body.stringValue` | `"Dagster run <run_id> for job <job_name> success (Xs)"` (or `failure step=… err=…`) |
16+
| `severityNumber` | 9 (INFO) for success, 17 (ERROR) for failure |
17+
| `severityText` | `INFO` / `ERROR` |
18+
| `timeUnixNano` | run end_time |
19+
| `attributes.dagster.run_id` | run UUID |
20+
| `attributes.dagster.job_name` | job name |
21+
| `attributes.dagster.status` | `success` / `failure` |
22+
| `attributes.dagster.duration_seconds` | double — wall-clock run time |
23+
| `attributes.dagster.failure_step` | step_key (failure only) |
24+
| `resource.service.name` | `dagster` |
25+
| `resource.service.instance.id` | `location_label` (deployment / region) |
26+
27+
[//]: # (FIELDS:START - auto-generated by tools/regen_readme_fields.py)
28+
29+
## Fields
30+
31+
### Required
32+
33+
| Field | Type | Description |
34+
|---|---|---|
35+
| `sensor_name` | `str` | Dagster sensor name. |
36+
| `otlp_endpoint_env_var` | `str` | Env var with OTLP/HTTP endpoint base URL (e.g. https://api.honeycomb.io). The /v1/logs path is appended. |
37+
38+
### Sensor configuration
39+
40+
| Field | Type | Default | Description |
41+
|---|---|---|---|
42+
| `default_status` | `str` | `"STOPPED"` | STOPPED \| RUNNING |
43+
44+
### Other
45+
46+
| Field | Type | Default | Description |
47+
|---|---|---|---|
48+
| `otlp_headers_env_var` | `str` || Env var with comma-separated HTTP headers (OTel convention: `x-honeycomb-team=<key>,x-honeycomb-dataset=dagster`). |
49+
| `service_name` | `str` | `"dagster"` | OTLP resource attribute `service.name`. |
50+
| `location_label` | `str` | `"default"` | OTLP resource attribute `service.instance.id` — usually deployment / region. |
51+
| `monitor_jobs` | `List[str]` || If set, only emit for these Dagster job names. None = all. |
52+
| `request_timeout_seconds` | `int` | `15` ||
53+
54+
[//]: # (FIELDS:END)
55+
56+
## Example — Honeycomb
57+
58+
```yaml
59+
type: dagster_community_components.DagsterRunsToOtlpSensorComponent
60+
attributes:
61+
sensor_name: dagster_runs_to_honeycomb
62+
otlp_endpoint_env_var: HONEYCOMB_OTLP_ENDPOINT
63+
otlp_headers_env_var: HONEYCOMB_OTLP_HEADERS
64+
service_name: dagster
65+
location_label: prod-east
66+
```
67+
68+
Required env:
69+
70+
```
71+
HONEYCOMB_OTLP_ENDPOINT=https://api.honeycomb.io
72+
HONEYCOMB_OTLP_HEADERS=x-honeycomb-team=<api_key>,x-honeycomb-dataset=dagster_runs
73+
```
74+
75+
## Example — Datadog OTel ingest
76+
77+
```yaml
78+
type: dagster_community_components.DagsterRunsToOtlpSensorComponent
79+
attributes:
80+
sensor_name: dagster_runs_to_datadog
81+
otlp_endpoint_env_var: DD_OTLP_ENDPOINT
82+
otlp_headers_env_var: DD_OTLP_HEADERS
83+
service_name: dagster
84+
```
85+
86+
Required env:
87+
88+
```
89+
DD_OTLP_ENDPOINT=https://otlp-intake.logs.datadoghq.com
90+
DD_OTLP_HEADERS=DD-API-KEY=<api_key>
91+
```
92+
93+
## Example — Splunk via Splunk OTel Collector
94+
95+
```yaml
96+
type: dagster_community_components.DagsterRunsToOtlpSensorComponent
97+
attributes:
98+
sensor_name: dagster_runs_to_splunk_otc
99+
otlp_endpoint_env_var: SPLUNK_OTC_ENDPOINT
100+
service_name: dagster
101+
```
102+
103+
Required env:
104+
105+
```
106+
SPLUNK_OTC_ENDPOINT=http://splunk-otc.svc:4318
107+
```
108+
109+
For Splunk HEC direct (no OTel Collector), use `dagster_runs_to_splunk_hec_sensor` — same shape, native HEC payload.
110+
111+
## Why two sensors (SUCCESS + FAILURE)?
112+
113+
Dagster's `@run_status_sensor` decorator filters on a single `run_status`. The component wires up two — one for SUCCESS, one for FAILURE — so both event types push their own LogRecord with the right `severityNumber` (9 vs 17) and `dagster.status` attribute.
114+
115+
## Relationship to other telemetry sensors
116+
117+
| Sensor | Scope | Wire |
118+
|---|---|---|
119+
| **`dagster_runs_to_otlp_sensor`** (this one) | success + failure | OTLP/HTTP |
120+
| `dagster_runs_to_prometheus_sensor` | success + failure | Prometheus Push Gateway / VM remote_write |
121+
| `dagster_runs_to_influxdb_sensor` | success + failure | InfluxDB line protocol |
122+
| `dagster_runs_to_splunk_hec_sensor` | success + failure | Splunk HEC direct |
123+
| `dagster_failures_to_otlp_sensor` | failure only (richer error context) | OTLP/HTTP |
124+
| `dagster_materializations_to_prometheus_sensor` | asset materialization events | Prometheus Push Gateway / VM |
125+
126+
Use whichever combination matches your observability stack. They're independent and can run side-by-side.
127+
128+
## See also
129+
130+
- [OTLP/HTTP logs spec](https://opentelemetry.io/docs/specs/otlp/#otlphttp-logs-binary-protocol)
131+
- `dataframe_to_otlp_logs` (in `assets/sinks/`) — **distinct** — data-plane DataFrame sink, not run events
132+
- `compute_log_managers/otlp/`**distinct** — instance-level CLM shipping op stdout/stderr (not run events)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .component import DagsterRunsToOtlpSensorComponent
2+
3+
__all__ = ["DagsterRunsToOtlpSensorComponent"]

0 commit comments

Comments
 (0)