Skip to content

feat(sdk): 'rocketride otel' — OpenTelemetry bridge exporting pipeline traces/metrics via the documented ingester protocol (zero engine changes) #1609

Description

@nihalnihalani

Problem Statement

RocketRide's traces are closed: observability lives in the VS Code webview and a proprietary WebSocket stream, so ops teams cannot wire pipelines into the dashboards they already run (Grafana/Tempo, Datadog, Jaeger, Langfuse, LangSmith, Phoenix). The engine's own observability doc says it plainly — the stream "is not OpenTelemetry, Prometheus, Sentry, or webhooks" — and invites exactly this work: "This page documents the protocol surface so you can … write your own ingester."

By mid-2026 this is a buyer rejection criterion, not a nice-to-have: OTel's GenAI semantic conventions became the vendor-neutral standard; n8n ships OTel tracing, Windmill EE exports Prometheus/OTel, and Dify offers one-config export to five observability platforms. A July 2026 competitive review of this repo rated OTLP export a P0 enterprise gap ("closed, IDE-only traces are now a buyer rejection criterion").

Prior art in this repo: PR #498 proposed OTel tracing + Prometheus metrics and was archived in tracking issue #616 as "promising … but not ready for merge." #498's approach was engine-invasive (middleware inside packages/ai web server). This proposal is the refinement #616 asked for, with the invasiveness removed entirely.

Proposed Solution

rocketride otel — an OpenTelemetry bridge built on the documented ingester protocol. Zero engine/server changes.

A long-running CLI process that connects to the engine like any SDK client, subscribes via rrext_monitor (token: "*" — the doc's "recommended scope for an ingestion service", types TASK | SUMMARY | FLOW | SSE), and exports standard OTLP:

1. Traces — reconstructed from apaevt_flow:

  • pipeline run → root span (op: beginend, correlated by project_id + source + pipe id);
  • each component execution → child span (enter/leave paired by component identity per the doc);
  • trace.error → span status ERROR + exception event; apaevt_sse messages ("thinking", "tool_call") → span events;
  • attributes: rocketride.project_id, rocketride.source, rocketride.component, lane, counts — plus GenAI semantic conventions (gen_ai.*) on LLM/agent components where event data allows, so Langfuse/Datadog render them natively.
  • Privacy by default: lane payloads/prompt content are excluded from spans unless --include-content is set — telemetry pipelines shouldn't receive document text by accident.

2. Metrics — from apaevt_status_update snapshots: task counts (total/completed/failed), rates, cpu_percent, cpu_memory_mb, gpu_memory_mb (+ peaks) as OTel instruments on the same OTLP endpoint. --no-metrics to disable.

3. Operations: --endpoint / standard OTEL_EXPORTER_OTLP_* env vars (http/protobuf default), reconnect-and-resubscribe (subscriptions are per-connection and not durable, per the doc), graceful shutdown with exporter flush, and clear docs for the three most-wanted backends (Jaeger/Tempo, Datadog, Langfuse).

4. Packaging: opentelemetry-sdk + OTLP exporter as an optional extra (pip install rocketride[otel]) — the base SDK gains no new dependencies; the subcommand fails fast with the install hint when the extra is absent.

Flow spans require runs started with a pipelineTraceLevel (documented); TASK/SUMMARY telemetry works for every run regardless.

Alternatives Considered

  • Engine-native instrumentation (feat(engine): add OpenTelemetry tracing and Prometheus metrics #498's approach) — highest fidelity, but invasive; [Tracking] Observability: OpenTelemetry Tracing & Prometheus Metrics #616 archived it for refinement. The bridge ships value now over a documented, stable protocol, and native instrumentation can follow later without conflicting (the bridge simply becomes optional).
  • Tell users to write their own ingester — the status quo the doc itself acknowledges; every team rebuilds the same mapping and none of them get GenAI semconv right.
  • Prometheus /metrics scrape endpoint — OTLP-first covers metrics too and reaches Prometheus via the standard OTel→Prometheus path; a dedicated scrape endpoint would need to live server-side (engine change) so it's out of scope here.

Affected Modules

  • client-python (new otelbridge module + otel CLI subcommand + optional extra)
  • docs
  • server / engine — no changes (consumes the documented rrext_monitor protocol)

Acceptance Criteria

  • rocketride otel --endpoint http://collector:4318 streams a live pipeline run as OTLP: one root span per run, child spans per component with correct parentage and timing, errors as span status, SSE as span events.
  • GenAI semantic-convention attributes applied where the event data allows; content excluded by default, --include-content to opt in.
  • Metrics from SUMMARY snapshots exported as OTel instruments; --no-metrics supported.
  • Reconnect + resubscribe on socket loss; clean flush on shutdown; clear failure message when the [otel] extra isn't installed.
  • Unit tests (no server): event fixtures → span/metric assertions (parentage, pairing by component identity, error mapping, privacy default). Live verification against a real engine + a real OTLP backend.
  • Docs: setup guide with Jaeger/Tempo, Datadog, and Langfuse examples.

Refs #616 (this is the refined successor to the concept archived from #498). Happy to implement — PR to follow shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions