KubeMQ
Client SDKsC++How-to guidesObservability

OpenTelemetry Setup

Configure distributed tracing and metrics with OpenTelemetry

Overview

OpenTelemetry integration is meant to wire the SDK's messaging operations into your tracing and metrics pipeline without hand-instrumenting every call site — in a distributed system where a message is published by one service and consumed by another, per-call logging tells you almost nothing compared to spans that correlate across process boundaries. The C++ SDK's OTel support is designed around that goal: registering a TracerProvider and MeterProvider globally before creating the client is intended to make every gRPC call automatically instrumented.

set_tracer_provider() and set_meter_provider() accept a provider pointer, and SendEvent/SendCommand/queue operations are meant to generate spans against whatever provider is registered. Gotchas: this integration is not yet active in the current release — the SDK ships a no-op stub (otel.cc) where OtelSpan, OtelCounter, and OtelHistogram are empty implementations that compile away, so no spans or metrics are actually emitted regardless of what provider you register; the example demonstrates the intended shape of the API, not working telemetry, and says so explicitly at runtime; and enabling this in the future will require rebuilding with -DKUBEMQ_ENABLE_OTEL=ON plus the opentelemetry-cpp SDK — don't assume it's active just because your build flags are set today.

Prerequisites

  • KubeMQ server running on localhost:50000
  • C++ SDK installed with KUBEMQ_ENABLE_OTEL=ON (see CMake build instructions)
  • C++17 compiler (GCC 9+, Clang 9+, MSVC 2019+)
  • opentelemetry-cpp SDK installed (vcpkg: opentelemetry-cpp)
  • OpenTelemetry collector or compatible backend (Jaeger, Zipkin, OTLP endpoint)

Code

main.cc
// Example: observability/opentelemetry_setup
//
// Demonstrates OpenTelemetry integration for distributed tracing and metrics
// with the KubeMQ C++ SDK. When an OpenTelemetry TracerProvider and
// MeterProvider are globally registered, the SDK instruments gRPC calls
// automatically. This example sends a demo event to generate trace spans.
//
// Channel: cpp-observability.opentelemetry-setup
// Client ID: cpp-observability-opentelemetry-setup-client
//
// Build with: cmake -DKUBEMQ_ENABLE_OTEL=ON ...
// Run with a KubeMQ server and optionally an OpenTelemetry collector
// (e.g., Jaeger, Zipkin) for trace visualization.

#include <kubemq/kubemq.h>

#include <chrono>
#include <iostream>
#include <thread>

// To enable OpenTelemetry tracing, install the opentelemetry-cpp SDK and
// configure a TracerProvider before creating the KubeMQ client:
//
//   #include <opentelemetry/sdk/trace/tracer_provider.h>
//   #include <opentelemetry/exporters/ostream/span_exporter.h>
//   #include <opentelemetry/trace/provider.h>
//
//   auto exporter = std::make_unique<opentelemetry::exporter::trace::OStreamSpanExporter>();
//   auto processor = std::make_unique<opentelemetry::sdk::trace::SimpleSpanProcessor>(
//       std::move(exporter));
//   auto provider = std::make_shared<opentelemetry::sdk::trace::TracerProvider>(
//       std::move(processor));
//   opentelemetry::trace::Provider::SetTracerProvider(provider);

int main() {
    std::cout << "[1] OpenTelemetry providers configured (using default/no-op)" << std::endl;
    std::cout << "[INFO] To see real traces, configure an OpenTelemetry collector and "
              << "replace the no-op provider above." << std::endl;

    kubemq::ClientOptions options;
    options.set_address("localhost", 50000);
    options.set_client_id("cpp-observability-opentelemetry-setup-client");

    auto client_result = kubemq::Client::Create(options);
    if (!client_result.ok()) {
        std::cerr << "[ERROR] Failed to create client: " << client_result.status().message()
                  << std::endl;
        return 1;
    }
    auto& client = *client_result;

    // Send a demo event to generate trace spans
    auto event_result = kubemq::Event::Builder()
                            .SetChannel("cpp-observability.opentelemetry-setup")
                            .SetBody("traced-event")
                            .SetMetadata("otel-demo")
                            .Build();
    if (!event_result.ok()) {
        std::cerr << "[ERROR] Build event: " << event_result.status().message() << std::endl;
        return 1;
    }

    auto send_status = client->SendEvent(*event_result);
    if (!send_status.ok()) {
        std::cerr << "[ERROR] SendEvent: " << send_status.message() << std::endl;
        return 1;
    }
    std::cout << "[2] Event sent with tracing enabled" << std::endl;

    std::this_thread::sleep_for(std::chrono::seconds(1));

    auto close_status = client->Close();
    if (!close_status.ok()) {
        std::cerr << "[ERROR] Close failed: " << close_status.message() << std::endl;
        return 1;
    }
    std::cout << "[3] Client closed" << std::endl;

    return 0;
}

How It Works

  • OpenTelemetry support is opt-in and not yet active in the current release. The SDK ships a no-op stub (otel.cc) for all tracing and metrics types — OtelSpan, OtelCounter, and OtelHistogram are all empty implementations that compile away. set_tracer_provider() and set_meter_provider() accept a provider pointer but the underlying InitOtel() is also a no-op until a real OTel build is wired in.
  • The example runs without a real OTel provider: the [1] output line acknowledges this explicitly ("using default/no-op"). No spans or metrics are emitted.
  • The commented-out block shows the intended setup for when the OTel middleware is implemented: configure an OStreamSpanExporter-backed TracerProvider and call opentelemetry::trace::Provider::SetTracerProvider(provider) before creating the client, then rebuild with -DKUBEMQ_ENABLE_OTEL=ON.
  • A demo event is sent to cpp-observability.opentelemetry-setup so the code path is exercised; the one-second sleep is a placeholder for exporter flush time once real tracing is enabled.

Was this page helpful?

On this page