Skip to main content
OTelEventSink turns every action into one OpenTelemetry span, named for the action, with one span event per step: proposed, decided, reserved, executed, recorded. It hands spans to whatever tracer provider your process configured and never blocks. Argument values are not attributes unless you ask, because a trace backend is not the receipt store. Prerequisites: pip install "ctrlrun[otel]", which brings the API, the SDK and the OTLP/HTTP exporter, and a backend that speaks OTLP (or, below, an in-memory exporter to see the spans without one).
1

Attach the sink

runnable
runnable
2

Export for real

Replace the in-memory exporter with the OTLP one your backend expects, or rely on the provider your application already configured and pass nothing: with no tracer_provider the sink uses the global one, and with none configured the API’s no-op provider makes the sink free.
With the gateway, --otel does the same, and --otel-arguments opts argument values in.
3

Read the span

The span’s status is an error for failed and ambiguous, unset for a refusal (a refusal is CTRLRun doing its job, not an error), and ok for committed. Attributes carry the action name, the decision, the effect key, the outcome and the receipt id; the receipt itself stays in the store. Open spans are bounded, so a process that dies mid-action leaves at most a fixed number unended, stated rather than solved.

What the sink is not

It is not the evidence. Receipts live in the store and the JSONL file, are chained, and are what ctrlrun receipts --verify-chain checks; a trace is a view of them for the people who already look at traces. Deleting a trace deletes nothing CTRLRun relies on.

If it didn’t work

  • MissingDependency: pip install "ctrlrun[otel]": the extra is not installed.
  • No spans arrive: no span processor is attached to the provider the sink was given, or the batch processor has not flushed yet; provider.force_flush() before exit.
  • Argument values appear: arguments=True was passed, or --otel-arguments on the gateway.

Next