Architecture & Signal Flow
Omni does not bundle or require an OpenTelemetry Collector or backend. Traces are sent to whatever endpoint is configured inOTEL_EXPORTER_OTLP_ENDPOINT. The default value is empty, which means instrumentation is active but signals are dropped / not exported or stored. When a non-empty endpoint is set, traces are sent to ${OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces.
Point OTEL_EXPORTER_OTLP_ENDPOINT at any compatible OTLP/HTTP collector or backend. See Production & Privacy Guidance for production recommendations.
Base OTLP Endpoint Semantics
Resource Attributes
Every trace carries:service.name: the logical service name (omni-searcher,omni-indexer,omni-ai,omni-web,omni-connector-manager)service.version: fromSERVICE_VERSIONdeployment.environment: fromOTEL_DEPLOYMENT_ENVIRONMENTdeployment.id: fromOTEL_DEPLOYMENT_ID
Shutdown Behaviour
On graceful shutdown (SIGTERM/SIGINT), each service flushes pending spans before exiting. In Rust services the OTLP exporter timeout is hard-coded at 10 seconds in the opentelemetry-rust SDK;OTEL_EXPORTER_OTLP_TIMEOUT is not honoured. Busy shutdowns that exceed the Rust SDK timeout may lose the final batch. Python (omni-ai) and Node (omni-web) use their SDK defaults.
Trace Continuity
HTTP Request Tracing
Rust services (searcher, indexer, connector-manager) use custom axum middleware. SERVER spans useMETHOD /path names (e.g. GET /v1/search); the trace_id is also propagated as a request id. W3C traceparent / tracestate is propagated in HTTP headers: inbound requests extract the parent context, and outbound HTTP calls inject it via the shared http_client helper.
Node (omni-web) and Python (omni-ai) use auto-instrumentation provided by the respective OpenTelemetry SDKs (Node auto-instrumentations with the filesystem instrumentation disabled; Python FastAPI and HTTPX instrumentation). Span names follow the SDK convention rather than a unified scheme.
Outbound HTTP requests create a CLIENT span, producing parent/child relationships within a single trace (not links) when the web service calls internal APIs. The same traceId is shared across the web→searcher and web→AI call chain.
Queue Processing
The indexer and connector-manager consume events from Postgres-based queues (connector_events_queue, embedding_queue). Queue rows do not currently carry trace context, so consumer processing starts a new root trace independent of the producer.
Logs
Logs are written to the container’s stdout (standarddocker logs), not exported via OTLP. Rust services emit structured JSON logs through tracing-subscriber; Python and Node use their standard logging. No global PII scrubber is applied. Runtime logging call sites are audited to avoid sensitive and high-cardinality fields, but log content is produced by the application as-is.
In Rust services, when an active trace span exists at the log call site, trace_id/span_id are attached to the log record via the tracing–OpenTelemetry layer.
Troubleshooting
Production & Privacy Guidance
When using an external OTLP collector or backend in production:- Use TLS. Enable TLS on the OTLP endpoint, or use gRPC with TLS.
- Authenticate. Use API keys or mTLS to secure the connection.
- Configure sampling. Use a
probabilistic_samplerortail_samplingprocessor in your collector for high-throughput services. - Set resource limits. Configure memory limits and spike limits in the collector or backend.
- Never expose the OTLP endpoint publicly. It has no built-in authentication. Bind to loopback or use a private network.
- Filter sensitive data. Omni applies no PII scrubbing. Redact sensitive fields in the collector or at the application level.