# OpenTelemetry Setup (/sdks/go/how-to/observability/opentelemetry-setup)



## Overview [#overview]

**OpenTelemetry integration** wires the SDK'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 channel and operation. Instrumenting that by hand around every `SendEvent` or `Subscribe` call is tedious and easy to get inconsistent; letting the client do it guarantees uniform coverage.

`kubemq.WithTracerProvider(tp)` and `kubemq.WithMeterProvider(mp)` inject standard OpenTelemetry providers into the client at construction time. Once set, every subsequent operation on that client automatically emits spans and records metrics — you write no tracing code in your business logic. `kubemq.WithCardinalityThreshold(...)` bounds the number of unique label combinations tracked, which matters once channel or client-ID names become dynamic. &#x2A;*Gotchas:** instrumentation is inert until you attach a real exporter (OTLP, Jaeger) to the provider — the providers shown here export nowhere by default; forgetting to shut down the provider on exit drops the last in-flight batch of spans and metrics; and high channel cardinality without a threshold can quietly blow up your metrics backend's storage.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Go SDK installed (`go get github.com/kubemq-io/kubemq-go/v2`)

## Code [#code]

```go title="main.go"
// Example: observability/opentelemetry-setup
//
// Demonstrates setting up OpenTelemetry tracing and metrics with
// the KubeMQ Go SDK. The SDK integrates with OTel via TracerProvider
// and MeterProvider options.
//
// This example uses the OTel SDK providers available in the module.
// In production, you would configure exporters (e.g., OTLP, Jaeger)
// to send telemetry data to your observability backend.
//
// Channel: go-observability.opentelemetry-setup
// Client ID: go-observability-opentelemetry-setup-client
//
// Run with a KubeMQ server on localhost:50000
// (see https://docs.kubemq.io/deploy).
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.opentelemetry.io/otel"
	sdkmetric "go.opentelemetry.io/otel/sdk/metric"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"

	"github.com/kubemq-io/kubemq-go/v2"
)

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Create a TracerProvider. In production, add a real exporter
	// (e.g., sdktrace.WithBatcher(otlpExporter)).
	tp := sdktrace.NewTracerProvider()
	defer func() {
		if err := tp.Shutdown(ctx); err != nil {
			log.Printf("TracerProvider shutdown: %v", err)
		}
	}()
	otel.SetTracerProvider(tp)

	// Create a MeterProvider for metrics instrumentation.
	mp := sdkmetric.NewMeterProvider()
	defer func() {
		if err := mp.Shutdown(ctx); err != nil {
			log.Printf("MeterProvider shutdown: %v", err)
		}
	}()

	// Create a KubeMQ client with OTel providers.
	// The SDK automatically instruments all operations with traces and metrics.
	client, err := kubemq.NewClient(ctx,
		kubemq.WithAddress("localhost", 50000),
		kubemq.WithClientId("go-observability-opentelemetry-setup-client"),
		// Pass the OTel providers to the SDK.
		kubemq.WithTracerProvider(tp),
		kubemq.WithMeterProvider(mp),
		// Optional: control metric cardinality for high-throughput scenarios.
		kubemq.WithCardinalityThreshold(100),
	)
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}
	defer client.Close()

	channel := "go-observability.opentelemetry-setup"

	// Send an event — this operation will be traced and metered by the SDK.
	err = client.SendEvent(ctx, kubemq.NewEvent().
		SetChannel(channel).
		SetBody([]byte("instrumented event")).
		SetMetadata("otel-demo"))
	if err != nil {
		log.Printf("SendEvent: %v", err)
	} else {
		fmt.Println("Event sent with OpenTelemetry instrumentation")
	}

	fmt.Println("OpenTelemetry setup demo complete")
	fmt.Println("In production, traces and metrics would be exported to your backend")
}

```

## How It Works [#how-it-works]

1. A `sdktrace.TracerProvider` and `sdkmetric.MeterProvider` are created from the standard OTel Go SDK (no exporters configured here — add a real OTLP or Jaeger exporter in production).
2. `kubemq.WithTracerProvider(tp)` and `kubemq.WithMeterProvider(mp)` inject both providers into the SDK; all subsequent operations on that client are automatically traced and metered.
3. `kubemq.WithCardinalityThreshold(100)` caps the number of unique label combinations tracked for metrics, preventing cardinality explosions in high-throughput scenarios.
4. Each `defer tp.Shutdown(ctx)` / `mp.Shutdown(ctx)` flushes buffered telemetry before the process exits; omitting this call drops the last batch of spans and metrics.

## Related [#related]

* [Go SDK Reference](/sdks/go/reference)
