KubeMQ
OperateObservability

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.

config.yaml
telemetry:
  enable: true
values.yaml
telemetry:
  enable: true

Version 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.

SettingDefaultDescription
protocolgrpcOTLP wire protocol — grpc (default endpoint :4317) or http (default endpoint :4318).
endpointlocalhost:4317OTLP collector endpoint (host:port).
insecuretrueWhen true, the connection skips TLS. Set false to use TLS 1.2+ to the collector.
compressiongzipPayload compression — gzip or none.
timeout10sExport 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.
ProtocolDefault endpointNotes
grpclocalhost:4317OTLP over gRPC. Supports TLS and gzip compression.
httplocalhost:4318OTLP 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).

SamplerDescription
always_onSample every trace.
always_offSample no traces.
trace_id_ratioSample a fraction of traces based on samplingRatio (e.g. 0.1 = 10% of traces).
parent_basedUse 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 variableOverridesNotes
OTEL_SERVICE_NAMEService nameThe OTLP service.name resource attribute.
OTEL_EXPORTER_OTLP_ENDPOINTExporter endpoint
OTEL_EXPORTER_OTLP_PROTOCOLExporter protocolgrpc or http.
OTEL_EXPORTER_OTLP_INSECUREExporter insecure"true" / "false".
OTEL_EXPORTER_OTLP_COMPRESSIONExporter compressiongzip or none.
OTEL_EXPORTER_OTLP_TIMEOUTExporter timeoutInteger milliseconds (e.g. "10000").
OTEL_EXPORTER_OTLP_HEADERSExporter headersComma-separated key=value pairs.
OTEL_TRACES_SAMPLERTraces samplerOTel sampler names: always_on, always_off, traceidratio, parentbased_traceidratio, parentbased_always_on, parentbased_always_off.
OTEL_TRACES_SAMPLER_ARGTraces sampling ratioFloat 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 nameSpan kindPattern
process events.{channel}ConsumerEvents
process events-store.{channel}ConsumerEvents Store
process commands.{channel}ConsumerCommands
process queries.{channel}ConsumerQueries
process queues.{channel}ConsumerQueues (single)
publish-batch queues.{channel}ConsumerQueues (batch)
deliver queues.{channel}ProducerQueues (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:

AttributeDescription
http.methodHTTP method (GET, POST, etc.).
http.routeMatched route pattern.
http.status_codeResponse status code.
http.targetRequest 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:

AttributeDescriptionExample
messaging.systemAlways kubemq.kubemq
messaging.operation.typeOperation type.process, receive
messaging.destination.nameChannel name.orders
messaging.message.idMessage, event, or request ID.abc123
messaging.client.idClient identifier.my-producer
messaging.kubemq.channel_typeChannel type.events, events_store, commands, queries, queues

Queue spans add these extra attributes:

AttributeDescription
messaging.kubemq.expirationMessage expiration (e.g. 30s).
messaging.kubemq.delayMessage delay (e.g. 10s).
messaging.kubemq.max_receiveMax receive count before a message is routed to the dead-letter queue.
messaging.batch.message_countNumber of messages in a batch.
messaging.kubemq.batch_error_countNumber of failed messages in a batch.
messaging.kubemq.messages_receivedMessages received in a receive operation.
messaging.kubemq.messages_expiredMessages expired during a receive.

Context propagation

KubeMQ propagates trace context through message tags using the W3C TraceContext and Baggage propagators:

  1. Inject — when a message passes through the tracing middleware, the current trace context is injected into the message's Tags map.
  2. Extract — when the message arrives at the message broker, the trace headers are read back out of the Tags map 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:

  1. Records the error on the span.
  2. Sets the span status to Error.
  3. Increments the messaging.kubemq.errors.count metric (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.

InstrumentTypeUnitDescription
messaging.kubemq.messages.countCounterTotal messages processed.
messaging.kubemq.messages.volumeCounterbytesTotal message volume in bytes.
messaging.kubemq.errors.countCounterTotal errors.
messaging.kubemq.messages.pendingUpDownCounterPending messages.
messaging.kubemq.messages.delayedUpDownCounterDelayed queue messages.
messaging.kubemq.messages.expiredCounterExpired messages.
messaging.kubemq.messages.waitingUpDownCounterQueue messages waiting.
messaging.kubemq.clients.countUpDownCounterConnected clients.
messaging.kubemq.messages.last_seenGaugeLast activity timestamp.
messaging.kubemq.responses.countCounterRPC responses.
messaging.kubemq.operation.durationHistogramsPer-operation latency.
messaging.kubemq.message.sizeHistogrambytesMessage payload size.
messaging.kubemq.queue.depthUpDownCounterQueue 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, 10

Export 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.

docker-compose.yml
services:
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "4317:4317"     # OTLP gRPC
      - "16686:16686"   # Jaeger UI
    environment:
      - COLLECTOR_OTLP_ENABLED=true
config.yaml
telemetry:
  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.

Was this page helpful?

On this page