Skip to content

feat(observability): default-on OTLP beat export (spec 08 §4) - #88

Closed
divo12 wants to merge 3 commits into
mainfrom
feat/otel-architecture
Closed

divo12 wants to merge 3 commits into
mainfrom
feat/otel-architecture

Conversation

@divo12

@divo12 divo12 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements chorus spec 08 §4, and default-on rather than opt-in: the OTel SDK is a core dependency and Chorus wires with_otel_export unless you disable it.

load_otel_config()           # enabled unless OTEL_SDK_DISABLED is truthy
  endpoint = OTEL_EXPORTER_OTLP_ENDPOINT or "http://localhost:4318"

OtelSpanSink maps run.* / llm.call / subagent events onto a nested beat span tree, with the eval verdict landing on the root as chorus.eval.*. Wired through CLI beats, role chat and the Chorus facade. Plain OTLP/HTTP — works with Langfuse / Tempo / Jaeger, no vendor SDK lock-in. Opt out with OTEL_SDK_DISABLED=true.

Note the default-on tradeoff measured on the dream side (dream#93): span creation is sub-millisecond, but with no collector on :4318 the exporter retries and adds ~6 s at process shutdown. Set OTEL_SDK_DISABLED=true in environments without a collector.

This is chorus's own provider/exporter/event-mapping surface, not a duplicate of dream's: dream exposes generic tracing primitives (Tracer, JsonlTracer, TraceWriter), not an OTLP provider API, so there is nothing to reuse yet. If a shared OTLP seam is wanted, it should land as an explicit dream public API first and chorus should migrate to it in a separate change.

Also included: the Postgres test fixture started pg_ctl without overriding unix_socket_directories, so it tried to create its socket lock under /var/run/postgresql and failed in any unprivileged environment; it now allocates a writable temp socket dir.

Companion dream PR: Arceus-Inc/dream#93

Test plan

  • uv sync --all-extras --dev
  • CHORUS_PG_BIN=... uv run pytest tests/observability/test_otel_export.py -q — 7 passed
  • uv run python evals/otel/eval_step1_chorus_otlp.py
  • uv run ruff check src tests / uv run mypy — clean (60 files)
  • Point OTEL_EXPORTER_OTLP_ENDPOINT at a local collector and run one beat

Link to Devin session: https://app.devin.ai/sessions/4f7deb4af0914056a24a4d660a661713
Requested by: @divo12

divo12 and others added 3 commits August 7, 2026 15:28
Wire EventBus fan-out to a real OpenTelemetry OTLP sink when
OTEL_EXPORTER_OTLP_ENDPOINT is set, with zero SDK cost when unset and
graceful degradation if chorus[otel] is missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Always fan the EventBus to an OTLP sink (default localhost:4318).
Opt out with OTEL_SDK_DISABLED=true; OTel packages are core deps.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration devin-ai-integration Bot changed the title feat(observability): opt-in OTLP beat export (spec 08 §4) feat(observability): default-on OTLP beat export (spec 08 §4) Aug 7, 2026
@divo12

divo12 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Closing: implements OTLP export as default-on (OTEL_SDK_DISABLED opt-out, localhost:4318 fallback), contradicting merged spec 08 §4 which mandates opt-in with zero cost when unset (no OTel import unless OTEL_EXPORTER_OTLP_ENDPOINT is set). Exporter/instrumentation code is salvageable — please resubmit flipped to opt-in gating. Resolves the docs/intervention.md entry.

@divo12 divo12 closed this Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant