# OpenTelemetry Setup (/sdks/csharp/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 `SendEventAsync` or subscribe call is tedious and easy to get inconsistent; letting the SDK's built-in diagnostics do it guarantees uniform coverage.

The SDK exposes tracing and metrics through the standard .NET diagnostics primitives: `System.Diagnostics.ActivitySource` (named `"KubeMQ.Sdk"`) for spans and `System.Diagnostics.Metrics.Meter` (same name) for counters — no OpenTelemetry NuGet dependency is required in the core SDK itself. An `ActivityListener` with `ShouldListenTo` matched to `"KubeMQ.Sdk"` and `Sample` set to `AllData` captures every operation's spans and tags as they're created. &#x2A;*Gotchas:** an `ActivityListener` only sees activities created *after* it's registered, so it must be set up before the client is constructed; the console-based listener shown here is for local debugging only — production needs the OpenTelemetry SDK's `AddSource("KubeMQ.Sdk")` wired to a real exporter; and forgetting to keep the listener/provider alive for the process lifetime (e.g., disposing it early) silently stops span capture.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* C# SDK installed (`dotnet add package KubeMQ.SDK.CSharp`)

## Code [#code]

```csharp title="Program.cs"
// KubeMQ .NET SDK — Observability: OpenTelemetry Integration
//
// This example demonstrates how the SDK exposes tracing and metrics via
// System.Diagnostics.ActivitySource and System.Diagnostics.Metrics.Meter.
//
// The SDK uses "KubeMQ.Sdk" as the ActivitySource and Meter name.
// No OpenTelemetry NuGet dependency is required in the core SDK —
// the OTel collector picks up traces/metrics automatically when configured.
//
// Prerequisites:
//   - KubeMQ server running on localhost:50000
//   - dotnet run
//
// To export to an OTel collector, add OpenTelemetry packages to your app:
//   dotnet add package OpenTelemetry.Extensions.Hosting
//   dotnet add package OpenTelemetry.Exporter.Console
//   dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

using KubeMQ.Sdk.Client;
using KubeMQ.Sdk.Events;
using System.Diagnostics;
using System.Text;

// Listen for KubeMQ SDK activities (traces)
using var listener = new ActivityListener
{
    ShouldListenTo = source => source.Name == "KubeMQ.Sdk",
    Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData,
    ActivityStarted = activity =>
    {
        Console.WriteLine($"[Trace] Started: {activity.OperationName}");
        foreach (var tag in activity.Tags)
        {
            Console.WriteLine($"  {tag.Key} = {tag.Value}");
        }
    },
    ActivityStopped = activity =>
    {
        Console.WriteLine($"[Trace] Stopped: {activity.OperationName} ({activity.Duration.TotalMilliseconds:F1}ms)");
    }
};
ActivitySource.AddActivityListener(listener);

// Create and use the client — traces are emitted automatically
await using var client = new KubeMQClient(new KubeMQClientOptions
{
    ClientId = "csharp-observability-open-telemetry-client",
});
await client.ConnectAsync();

Console.WriteLine("\nPublishing events (traces will be logged above)...\n");

for (var i = 1; i <= 3; i++)
{
    await client.SendEventAsync(new EventMessage
    {
        Channel = "csharp-observability.open-telemetry",
        Body = Encoding.UTF8.GetBytes($"Traced event #{i}")
    });
}

Console.WriteLine("\nDone. In production, configure OpenTelemetry SDK to export to your collector.");

```

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

* The SDK instruments every gRPC operation using `System.Diagnostics.ActivitySource` (named `"KubeMQ.Sdk"`) — no OpenTelemetry NuGet package is required in the SDK itself.
* `ActivityListener.ShouldListenTo` is checked per source name; setting `Sample` to `AllData` captures all attributes and child spans on matched activities.
* In production, replace the console listener with the OpenTelemetry SDK wired to your collector: add `OpenTelemetry.Extensions.Hosting` and call `AddSource("KubeMQ.Sdk")` in your `TracerProvider` builder.
* The Meter name is also `"KubeMQ.Sdk"` — subscribe with `MeterListener` or `IMeterFactory` to capture throughput, error rate, and latency counters emitted by the client.

## Related [#related]

* [C# SDK Reference](/sdks/csharp/reference)
