Distributed Tracing
Export OpenTelemetry traces and metrics over OTLP to Jaeger, Grafana Tempo, or Datadog — samplers, span attributes, and context propagation.
KubeMQ integrates with OpenTelemetry (OTel) for distributed
tracing and metrics export. It is opt-in — off by default and turned on with a single
telemetry.enable flag. When enabled, KubeMQ instruments every messaging operation (Events,
Events Store, Queues, Commands, Queries) with spans and exports them, along with a set of OTel
metric instruments, over the OTLP protocol to any compatible backend (Jaeger, Grafana Tempo,
Datadog, and others).
Tracing is complementary to the always-on Prometheus exporter. Prometheus gives you a pull-based metric series for dashboards and alerting; OpenTelemetry adds distributed traces with context propagation across services, plus a parallel push-based metric stream over OTLP.
Enable it
Telemetry is controlled by the master telemetry.enable switch (off by default). Turn it on,
then tune the traces, metrics, and exporter sub-blocks as needed.
telemetry:
enable: truetelemetry:
enable: trueVersion floor: the spec.telemetry.* fields are present throughout the current GA
chart line — kubemq-crds and kubemq-cluster 3.x (latest 3.2.0) with
kubemq-controller 2.x (operator v2.3.0). Anything older than the 3.0.0 / 2.0.0 GA
release predates this reference and will reject these fields; upgrade to the current line.
On Docker the telemetry.* keys are available regardless of chart version.
The full set of telemetry settings — service name, traces/metrics sub-blocks, exporter options, and the Docker/Helm key and environment-variable mappings — lives in the Configuration reference. This page covers what those settings do and what you get when telemetry is on.
OTLP exporter
Traces and metrics are exported over OTLP to a collector or backend. The exporter is configured
under telemetry.exporter.
| Setting | Default | Description |
|---|---|---|
protocol | grpc | OTLP wire protocol — grpc (default endpoint :4317) or http (default endpoint :4318). |
endpoint | localhost:4317 | OTLP collector endpoint (host:port). |
insecure | true | When true, the connection skips TLS. Set false to use TLS 1.2+ to the collector. |
compression | gzip | Payload compression — gzip or none. |
timeout | 10s | Export request timeout (Go duration). |
headers | {} | Custom headers sent with each export request (a key/value map). config.yaml-only — there is no environment-variable or CRD path for this field. |
| Protocol | Default endpoint | Notes |
|---|---|---|
grpc | localhost:4317 | OTLP over gRPC. Supports TLS and gzip compression. |
http | localhost:4318 | OTLP over HTTP. Supports TLS and gzip compression. |
Samplers
The sampler decides which traces are recorded. It is set with telemetry.traces.sampler; the
ratio-based samplers read telemetry.traces.samplingRatio (a fraction from 0.0 to 1.0).
| Sampler | Description |
|---|---|
always_on | Sample every trace. |
always_off | Sample no traces. |
trace_id_ratio | Sample a fraction of traces based on samplingRatio (e.g. 0.1 = 10% of traces). |
parent_based | Use the parent span's sampling decision; falls back to trace_id_ratio for root spans. The default. |
Environment variable overrides
Standard OTel environment variables are read after the config file loads and override the file values. These are the recommended way to set exporter and sampler options from outside the container.
| Environment variable | Overrides | Notes |
|---|---|---|
OTEL_SERVICE_NAME | Service name | The OTLP service.name resource attribute. |
OTEL_EXPORTER_OTLP_ENDPOINT | Exporter endpoint | |
OTEL_EXPORTER_OTLP_PROTOCOL | Exporter protocol | grpc or http. |
OTEL_EXPORTER_OTLP_INSECURE | Exporter insecure | "true" / "false". |
OTEL_EXPORTER_OTLP_COMPRESSION | Exporter compression | gzip or none. |
OTEL_EXPORTER_OTLP_TIMEOUT | Exporter timeout | Integer milliseconds (e.g. "10000"). |
OTEL_EXPORTER_OTLP_HEADERS | Exporter headers | Comma-separated key=value pairs. |
OTEL_TRACES_SAMPLER | Traces sampler | OTel sampler names: always_on, always_off, traceidratio, parentbased_traceidratio, parentbased_always_on, parentbased_always_off. |
OTEL_TRACES_SAMPLER_ARG | Traces sampling ratio | Float string (e.g. "0.1"). |
KubeMQ also derives its own TELEMETRY_* environment variables from the config keys (for
example TELEMETRY_ENABLE, TELEMETRY_EXPORTER_ENDPOINT). Where both exist, prefer the
standard OTEL_* variables above — they are the conventional way to configure an OTel
exporter and are read after the KubeMQ-specific values.
What gets traced
When tracing is on, every messaging pattern is instrumented. Each operation produces a span whose name encodes the operation and channel.
| Span name | Span kind | Pattern |
|---|---|---|
process events.{channel} | Consumer | Events |
process events-store.{channel} | Consumer | Events Store |
process commands.{channel} | Consumer | Commands |
process queries.{channel} | Consumer | Queries |
process queues.{channel} | Consumer | Queues (single) |
publish-batch queues.{channel} | Consumer | Queues (batch) |
deliver queues.{channel} | Producer | Queues (receive) |
In addition, the shared HTTP server applies automatic transport-level tracing to all
HTTP-based connectors (REST, A2A, MCP, and CloudEvents) under the service name kubemq-http.
When telemetry is enabled, each HTTP request handled by these connectors generates a span with
the standard HTTP attributes:
| Attribute | Description |
|---|---|
http.method | HTTP method (GET, POST, etc.). |
http.route | Matched route pattern. |
http.status_code | Response status code. |
http.target | Request path. |
The A2A and MCP connectors and the agent registry have no application-level OTel instrumentation — they rely on this transport-level tracing for HTTP spans (method, route, status, duration) and on Prometheus metrics for per-operation detail. Per-operation spans (which agent was invoked, tool execution time, JSON-RPC method) are not currently traced.
Span attributes
Every messaging span carries a standard set of attributes:
| Attribute | Description | Example |
|---|---|---|
messaging.system | Always kubemq. | kubemq |
messaging.operation.type | Operation type. | process, receive |
messaging.destination.name | Channel name. | orders |
messaging.message.id | Message, event, or request ID. | abc123 |
messaging.client.id | Client identifier. | my-producer |
messaging.kubemq.channel_type | Channel type. | events, events_store, commands, queries, queues |
Queue spans add these extra attributes:
| Attribute | Description |
|---|---|
messaging.kubemq.expiration | Message expiration (e.g. 30s). |
messaging.kubemq.delay | Message delay (e.g. 10s). |
messaging.kubemq.max_receive | Max receive count before a message is routed to the dead-letter queue. |
messaging.batch.message_count | Number of messages in a batch. |
messaging.kubemq.batch_error_count | Number of failed messages in a batch. |
messaging.kubemq.messages_received | Messages received in a receive operation. |
messaging.kubemq.messages_expired | Messages expired during a receive. |
Context propagation
KubeMQ propagates trace context through message tags using the W3C TraceContext and Baggage propagators:
- Inject — when a message passes through the tracing middleware, the current trace context
is injected into the message's
Tagsmap. - Extract — when the message arrives at the message broker, the trace headers are read back
out of the
Tagsmap to link the consumer span to the producer.
This enables end-to-end tracing across producer → the message broker → consumer, even when the producer and consumer use different SDKs.
Error recording
When a send or receive operation fails, the tracing middleware:
- Records the error on the span.
- Sets the span status to
Error. - Increments the
messaging.kubemq.errors.countmetric (see below).
OTel metrics
In addition to traces, KubeMQ exports a set of OTel metric instruments over OTLP. These are a
parallel push-based path to the pull-based Prometheus series and
are useful when your backend already ingests OTLP metrics (Mimir, Datadog, and others). All
instruments share the labels node, type (channel type), side (send / receive), and
channel.
| Instrument | Type | Unit | Description |
|---|---|---|---|
messaging.kubemq.messages.count | Counter | — | Total messages processed. |
messaging.kubemq.messages.volume | Counter | bytes | Total message volume in bytes. |
messaging.kubemq.errors.count | Counter | — | Total errors. |
messaging.kubemq.messages.pending | UpDownCounter | — | Pending messages. |
messaging.kubemq.messages.delayed | UpDownCounter | — | Delayed queue messages. |
messaging.kubemq.messages.expired | Counter | — | Expired messages. |
messaging.kubemq.messages.waiting | UpDownCounter | — | Queue messages waiting. |
messaging.kubemq.clients.count | UpDownCounter | — | Connected clients. |
messaging.kubemq.messages.last_seen | Gauge | — | Last activity timestamp. |
messaging.kubemq.responses.count | Counter | — | RPC responses. |
messaging.kubemq.operation.duration | Histogram | s | Per-operation latency. |
messaging.kubemq.message.size | Histogram | bytes | Message payload size. |
messaging.kubemq.queue.depth | UpDownCounter | — | Queue depth per channel. |
The OTel messaging.kubemq.operation.duration histogram uses its own bucket boundaries
(in seconds), which are distinct from the Prometheus histogram buckets on the
Metrics page — do not assume they match:
0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10Export to a backend
Point the exporter at any OTLP-compatible collector or backend. The example below runs Jaeger locally and exports traces to it over OTLP gRPC.
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "4317:4317" # OTLP gRPC
- "16686:16686" # Jaeger UI
environment:
- COLLECTOR_OTLP_ENABLED=truetelemetry:
enable: true
serviceName: "kubemq-production"
traces:
enable: true
sampler: "parent_based"
samplingRatio: 0.1 # sample 10% of traces
metrics:
enable: true
exportInterval: "30s"
exporter:
protocol: "grpc"
endpoint: "jaeger:4317"
insecure: true
compression: "gzip"The same exporter block works for Grafana Tempo and Datadog — point endpoint at the
relevant OTLP receiver, switch protocol to http if the backend expects OTLP/HTTP, and supply
any required auth headers via OTEL_EXPORTER_OTLP_HEADERS.
Correlate with logs
When tracing is on, KubeMQ adds trace_id and span_id fields to the log lines emitted during
a traced operation, so you can pivot between a log line and its trace in your backend. See
Structured Logging for the log field set and a Grafana
Loki ↔ Tempo derived-fields setup.
Related
Was this page helpful?
Prometheus Metrics
Scrape KubeMQ's always-on Prometheus endpoint — every metric series for messaging, queues, RPC latency, cluster health, and the agent platform.
Structured Logging
KubeMQ's JSON logs on stdout — levels, runtime level changes, the field set, and correlating log lines with traces via trace and span IDs.