@use-crux/otel
OpenTelemetry integration, spans for every instrumented Crux event.
import { withTelemetry } from '@use-crux/otel'
import { createUrlExporter, createCallbackExporter } from '@use-crux/otel'For setup and usage, see the Production Telemetry guide.
withTelemetry(options?)
Creates a CruxPlugin that instruments all Crux operations with OpenTelemetry spans or lightweight structured traces.
config({
plugins: [withTelemetry({ serviceName: 'my-app' })],
})Options:
| Field | Type | Default | Description |
|---|---|---|---|
serviceName | string | '@use-crux/otel' | Tracer name for span identification |
attributes | Record<string, string> | n/a | Custom attributes added to every span |
exporter | UrlExporter | CallbackExporter | n/a | Export strategy. Omit for standard OTel TracerProvider path |
captureMessageContent | boolean | false | Export GenAI input/output message attributes |
semconvVersion | 'genai-dev-2026-06' | current table | Forward compatibility knob for semconv names |
baggageAttributeAllowlist | readonly string[] | unset | Baggage keys copied onto resumed root spans as crux.baggage.* |
Payload capture is controlled by the core observability policy:
config({ observability: { recordInputs, recordOutputs, redactRecord } }).
recordInputs and recordOutputs accept inline, reference, or off.
The OTel mapper also drops known payload attribute keys by default, even when
local graph capture is inline.
Returns: CruxPlugin with name 'crux:otel'.
withTelemetry() has a process-level double-install guard. A second active install warns once and becomes a no-op, preventing duplicate exported span trees.
If the standard OTel path is used without a registered TracerProvider, Crux detects the invalid OTel span context, warns once, and falls back to lightweight span tracking. Register a provider before installing the plugin or pass exporter.
Open span registries are bounded. Registry-pressure evictions force-end spans with crux.expired: true and UNSET status.
Crux emits embedding spans as embeddings {model} with attributes for embedding name, kind, input count, chunk count, dense dimensions, token usage, and cost when available.
Generation and stream spans project Crux graph metrics into OTel GenAI and Crux attributes: gen_ai.client.operation.duration, gen_ai.server.time_to_first_token, crux.gen.output_tokens_per_second, and crux.gen.time_per_output_chunk_ms.
Corpus sync emits crux.corpus.sync spans and per-source crux.corpus.source spans. Namespace and source identifiers are exported as hashes so file paths, URLs, and tenant namespaces do not become raw telemetry attributes.
Ingest parsers emit crux.ingest.parse spans. These include parser name, source format, byte length, part count, warning count, and hashed namespace/source identifiers. Parser errors mark the span as ERROR.
Retrieval emits direct crux.retrieval.query spans for retriever calls. Retrieval recipes emit a parent crux.retrieval.recipe span and one crux.retrieval.step span per recipe step. Step spans include recipe id, step id, step kind, input/output query counts, input/output hit counts, warning count, and status. They intentionally do not include raw query text, hit content, metadata, filters, or embeddings.
Quality evaluations export crux.eval.run and crux.eval.case spans. Baseline comparison, case membership, and replay provenance are canonical graph edges for local/devtools read models; OTel export keeps those relationships as aggregate span metadata rather than raw case payloads.
UrlExporter
Configuration for HTTP POST export (ephemeral runtimes).
| Field | Type | Description |
|---|---|---|
url | string | Endpoint to POST span batches to |
headers | Record<string, string>? | Optional headers (API keys, auth) |
CallbackExporter
type CallbackExporter = (
spans: ReadonlyArray<TraceSpan>,
) => void | Promise<void>A function that receives completed span batches. Use for custom handling (Convex actions, PostHog, etc.).
TraceSpan
Structured span data used by the lightweight exporter path.
| Field | Type | Description |
|---|---|---|
spanId | string | W3C span ID for lightweight exports; provider-issued ID on the standard OTel path |
parentSpanId | string? | Parent span ID for nesting |
traceId | string | W3C trace ID grouping related spans |
name | string | Span name (e.g., 'chat gpt-4o') |
startTime | number | Start time (Unix ms) |
endTime | number | End time (Unix ms) |
durationMs | number | Duration in milliseconds |
attributes | Record<string, string | number | boolean | Array<string | number | boolean>> | Key-value attributes |
status | SpanStatus | { code: 'OK' | 'ERROR' | 'UNSET', message?: string } |
events | Array<{ name, time, attributes? }>? | Point-in-time events (e.g., exceptions) |
Propagation helpers
| Export | Purpose |
|---|---|
injectCruxPropagationCarrier(carrier, target) | Write W3C traceparent / tracestate / baggage (+ optional OTel propagator fields) into a header-like carrier with .set |
extractCruxPropagationCarrier(source, options?) | Read a validated carrier + allowlisted baggage attributes from a header-like carrier with .get; never throws |
See the telemetry guide for suspend/resume and queue examples.
createUrlExporter(options)
Creates a SpanExporter that POSTs span batches to a URL. Fire-and-forget with 5-second timeout, failures are silently ignored.
const exporter = createUrlExporter({
url: 'https://collector.example.com/v1/traces',
headers: { 'X-Api-Key': 'key' },
})createCallbackExporter(callback)
Creates a SpanExporter that delivers span batches to a callback function.
const exporter = createCallbackExporter((spans) => {
for (const span of spans) {
console.log(`${span.name}: ${span.durationMs}ms`)
}
})SpanExporter
Interface for span export backends.
| Method | Description |
|---|---|
export(spans) | Export a batch of completed spans |
shutdown() | Flush pending spans and shut down |
Span attribute constants
GenAI semantic convention constants are exported from @use-crux/otel:
| Constant | Value | Convention |
|---|---|---|
SEMCONV_VERSION | genai-dev-2026-06 | Crux |
GEN_AI_OPERATION_NAME | gen_ai.operation.name | OTel GenAI |
GEN_AI_PROVIDER_NAME | gen_ai.provider.name | OTel GenAI |
GEN_AI_REQUEST_MODEL | gen_ai.request.model | OTel GenAI |
GEN_AI_RESPONSE_MODEL | gen_ai.response.model | OTel GenAI |
GEN_AI_CLIENT_OPERATION_DURATION | gen_ai.client.operation.duration | OTel GenAI |
GEN_AI_SERVER_TIME_TO_FIRST_TOKEN | gen_ai.server.time_to_first_token | OTel GenAI |
CRUX_GEN_OUTPUT_TOKENS_PER_SECOND | crux.gen.output_tokens_per_second | Crux |
CRUX_GEN_TIME_PER_OUTPUT_CHUNK_MS | crux.gen.time_per_output_chunk_ms | Crux |
GEN_AI_RESPONSE_FINISH_REASONS | gen_ai.response.finish_reasons | OTel GenAI |
GEN_AI_INPUT_MESSAGES | gen_ai.input.messages | OTel GenAI |
GEN_AI_OUTPUT_MESSAGES | gen_ai.output.messages | OTel GenAI |
GEN_AI_SYSTEM_INSTRUCTIONS | gen_ai.system_instructions | OTel GenAI |
GEN_AI_USAGE_INPUT_TOKENS | gen_ai.usage.input_tokens | OTel GenAI |
GEN_AI_USAGE_OUTPUT_TOKENS | gen_ai.usage.output_tokens | OTel GenAI |
CRUX_PROMPT_ID | crux.prompt.id | Crux |
CRUX_COST | crux.cost | Crux |
CRUX_EMBEDDING_NAME | crux.embedding.name | Crux |
CRUX_EMBEDDING_KIND | crux.embedding.kind | Crux |
CRUX_EMBEDDING_OPERATION | crux.embedding.operation | Crux |
CRUX_CORPUS_ID | crux.corpus.id | Crux |
CRUX_CORPUS_NAMESPACE_HASH | crux.corpus.namespace_hash | Crux |
CRUX_CORPUS_SOURCE_ID_HASH | crux.corpus.source_id_hash | Crux |
CRUX_CORPUS_ACTION | crux.corpus.action | Crux |
CRUX_INGEST_PARSER | crux.ingest.parser | Crux |
CRUX_INGEST_FORMAT | crux.ingest.format | Crux |
CRUX_INGEST_SOURCE_ID_HASH | crux.ingest.source_id_hash | Crux |
CRUX_INGEST_PART_COUNT | crux.ingest.part_count | Crux |
CRUX_RETRIEVAL_RECIPE_ID | crux.retrieval.recipe.id | Crux |
CRUX_RETRIEVAL_STEP_ID | crux.retrieval.step.id | Crux |
CRUX_RETRIEVAL_STEP_KIND | crux.retrieval.step.kind | Crux |
CRUX_RETRIEVAL_STEP_INPUT_QUERY_COUNT | crux.retrieval.step.input_query_count | Crux |
CRUX_RETRIEVAL_STEP_OUTPUT_QUERY_COUNT | crux.retrieval.step.output_query_count | Crux |
CRUX_RETRIEVAL_STEP_INPUT_HIT_COUNT | crux.retrieval.step.input_hit_count | Crux |
CRUX_RETRIEVAL_STEP_OUTPUT_HIT_COUNT | crux.retrieval.step.output_hit_count | Crux |
CRUX_RETRIEVAL_STEP_WARNING_COUNT | crux.retrieval.step.warning_count | Crux |
CRUX_TOOL_NAME | crux.tool.name | Crux |
CRUX_FLOW_ID | crux.flow.id | Crux |
CRUX_FLOW_NAME | crux.flow.name | Crux |
CRUX_FLOW_PARENT_ID | crux.flow.parent_id | Crux |
CRUX_COMPOSITION_KIND | crux.composition.kind | Crux |
Related
- Guide: Telemetry
- Guide: Observability
- Cookbook: Observability stack