KubeMQ
Client SDKsElixirHow-to guidesObservability

OpenTelemetry Setup

Attach handlers to KubeMQ telemetry events to export tracing and metrics using the Elixir SDK.

Overview

OpenTelemetry integration wires the client's messaging operations into your tracing and metrics pipeline without hand-instrumenting every call site. In a distributed system where a message might be published by one service, queued, and consumed by three others, per-call logging tells you almost nothing — you need spans that correlate across process boundaries and latency/error metrics broken out by operation. The Elixir SDK takes the idiomatic BEAM approach: instead of an OTel-specific API, it emits standard :telemetry events, the same mechanism every well-behaved Elixir library uses for instrumentation.

:telemetry.attach_many/4 registers a handler across multiple event names, each following the pattern [:kubemq, :client, action, phase] (e.g., [:kubemq, :client, :send_event, :stop]), with phase being :start, :stop, or :exception. Handlers receive measurements (duration and similar numeric data) and metadata (operation, channel, client ID). To get this into OpenTelemetry specifically, bridge these events with the opentelemetry_telemetry library rather than consuming them directly. Gotchas: a slow or raising telemetry handler runs inline on the calling process and can measurably impact latency or crash the caller — keep handlers fast and defensive; attach_many silently no-ops if the event name list doesn't exactly match what the SDK emits (typos fail quietly, not loudly); and this raw :telemetry approach only gets you logging by default — actual OTel export requires the separate bridge library, not just the code shown here.

Prerequisites

  • KubeMQ server running on localhost:50000
  • Elixir SDK installed ({:kubemq, "~> 1.0"} in mix.exs)

Code

main.exs
:telemetry.attach_many(
  "kubemq-logger",
  [
    [:kubemq, :client, :ping, :stop],
    [:kubemq, :client, :send_event, :start],
    [:kubemq, :client, :send_event, :stop],
    [:kubemq, :client, :send_event, :exception],
    [:kubemq, :client, :send_command, :stop],
    [:kubemq, :client, :send_query, :stop],
    [:kubemq, :client, :send_queue_message, :stop],
    [:kubemq, :client, :poll_queue, :stop]
  ],
  fn event, measurements, metadata, _config ->
    [_, _, action, phase] = event

    IO.puts("[Telemetry] #{action}:#{phase}")
    IO.puts("  measurements: #{inspect(measurements)}")
    IO.puts("  metadata: #{inspect(Map.take(metadata, [:operation, :channel, :client_id]))}")
  end,
  nil
)

IO.puts("Telemetry handlers attached")

{:ok, client} = KubeMQ.Client.start_link(address: "localhost:50000", client_id: "elixir-telemetry")

IO.puts("\n--- Ping ---")
KubeMQ.Client.ping(client)

IO.puts("\n--- Send Event ---")
KubeMQ.Client.send_event(client,
  KubeMQ.Event.new(channel: "elixir-observability.opentelemetry-setup", body: "traced event"))

Process.sleep(500)
IO.puts("\nTelemetry events logged above.")

KubeMQ.Client.close(client)

How It Works

  • :telemetry.attach_many/4 registers a handler for multiple telemetry events
  • Event names follow the pattern [:kubemq, :client, :action, :phase]
  • Phases include :start, :stop, and :exception
  • Measurements contain duration and metadata contains operation context
  • This integrates with OpenTelemetry via the opentelemetry_telemetry bridge

Was this page helpful?

On this page