OpenTelemetry
These are the v1 docs. They are not maintained.
This page is a verbatim snapshot of the commiq 1.x documentation, kept for people still running 1.x. It is not corrected and not tested against any release. Several pages contain claims that were wrong when written: examples that do not run as printed, sealStore described as read-only when it was not, handledEvent presented as a working subscription pattern when it never matched, and effects described as swallowing only AbortError when they swallowed everything.
Do not treat anything here as a statement about how commiq 2.x behaves.
What changed in 2.0 and how to upgrade · Current documentation
Site search only indexes the current docs. Use the sidebar to browse these pages.
OpenTelemetry
@naikidev/commiq-otel instruments Commiq stores with OpenTelemetry tracing. Each command becomes a span, and events emitted during that command are recorded as span events, giving you end-to-end visibility in any OTel-compatible backend.
Installation
pnpm add @naikidev/commiq-otel @opentelemetry/api npm install @naikidev/commiq-otel @opentelemetry/api yarn add @naikidev/commiq-otel @opentelemetry/api bun add @naikidev/commiq-otel @opentelemetry/api @opentelemetry/api is a peer dependency.
Basic Usage
import { createStore, createCommand, sealStore } from "@naikidev/commiq";
import { instrumentStore } from "@naikidev/commiq-otel";
const store = createStore({ count: 0 });
store.addCommandHandler("increment", (ctx) => {
ctx.setState({ count: ctx.state.count + 1 });
});
const uninstrument = instrumentStore(store, { storeName: "counter" });
const sealed = sealStore(store);
sealed.queue(createCommand("increment", undefined));API
instrumentStore(store, options)
Subscribes to a store's event stream and creates OpenTelemetry spans for command processing.
Returns a cleanup function that ends active spans and unsubscribes the listener.
function instrumentStore(
store: StoreWithStream,
options: InstrumentOptions,
): () => void;Options
| Option | Type | Default | Description |
|---|---|---|---|
storeName | string | (required) | Display name used in span attributes |
tracerName | string | "commiq" | OpenTelemetry tracer name |
tracerVersion | string | — | OpenTelemetry tracer version |
Tracing Model
Spans
Each command creates a span that lives from commandStarted to commandHandled (or commandHandlingError / commandInterrupted):
commiq.command:increment
├─ span event: stateChanged
└─ span event: itemAdded (custom event)State changes and custom events emitted during a command are recorded as span events on the parent command span. Events emitted outside a command create standalone spans.
Span Attributes
Command spans (commiq.command:{name}):
| Attribute | Description |
|---|---|
commiq.store | Store name |
commiq.command.name | Command name |
commiq.command.correlation_id | Unique correlation ID |
commiq.command.caused_by | Parent event ID (if applicable) |
commiq.command.interrupted | true if the command was interrupted |
commiq.command.interrupted_phase | "queued" or "running" (only when interrupted) |
Standalone event spans (commiq.event:{name}):
| Attribute | Description |
|---|---|
commiq.store | Store name |
commiq.event.name | Event name |
commiq.event.correlation_id | Unique correlation ID |
commiq.event.caused_by | Parent event ID (if applicable) |
Interrupted Commands
When an interruptable command is cancelled, the command span is:
- Set to
OKstatus with message"interrupted" - Attributes
commiq.command.interrupted(true) andcommiq.command.interrupted_phase("queued"or"running") are added - The span is ended
This distinguishes intentional cancellation from errors in your tracing backend.
Error Handling
When a command handler throws, the command span is:
- Set to
ERRORstatus with the error message - The exception is recorded on the span via
span.recordException() - The span is ended
Cleanup
Call the returned function to stop instrumentation:
const uninstrument = instrumentStore(store, { storeName: "counter" });
// Later...
uninstrument();This ends any in-flight spans and removes the stream listener.
Full Example
Using the OpenTelemetry Node SDK with a console exporter:
import { NodeSDK } from "@opentelemetry/sdk-node";
import { ConsoleSpanExporter } from "@opentelemetry/sdk-trace-node";
import { createStore, createCommand, sealStore } from "@naikidev/commiq";
import { instrumentStore } from "@naikidev/commiq-otel";
// Set up OTel SDK
const sdk = new NodeSDK({ traceExporter: new ConsoleSpanExporter() });
sdk.start();
// Create and instrument a store
const store = createStore({ count: 0 });
store.addCommandHandler("increment", (ctx) => {
ctx.setState({ count: ctx.state.count + 1 });
});
const uninstrument = instrumentStore(store, {
storeName: "counter",
tracerName: "my-app",
});
const sealed = sealStore(store);
sealed.queue(createCommand("increment", undefined));
// Cleanup
uninstrument();
await sdk.shutdown();Testing Locally
To visualize traces during development, use any OpenTelemetry-compatible backend:
| Backend | Best for | Setup |
|---|---|---|
| Jaeger | Local debugging | docker run -p 16686:16686 jaegertracing/all-in-one |
| Aspire Dashboard | .NET ecosystem | See browser telemetry guide |
| Zipkin | Lightweight tracing | docker run -p 9411:9411 openzipkin/zipkin |
| Grafana Tempo | Production-grade | Requires Grafana stack |
Configure your OTel SDK exporter to point to your chosen backend. The ConsoleSpanExporter in the example above is useful for quick debugging without any backend setup.