The client is instrumented natively with System.Diagnostics — an
ActivitySource (traces) and a Meter (metrics) — so an OpenTelemetry pipeline
lights up without the library taking any telemetry-SDK dependency or forcing a
logging framework on you. Both live in System.Diagnostics.DiagnosticSource,
which is in the shared framework on .NET 8+, so there is ~zero added deployed
dependency, and the instrumentation is ~zero-cost when nothing is listening
(StartActivity() returns null; span tags are built only when a listener is
attached, gated by ActivitySource.HasListeners()).
The instrumentation-scope name for both the source and the meter is
Microsoft.AgentHostProtocol (AhpTelemetry.Name). Register them with your
OpenTelemetry provider:
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
builder.Services.AddOpenTelemetry()
.WithTracing(t => t.AddSource("Microsoft.AgentHostProtocol"))
.WithMetrics(m => m.AddMeter("Microsoft.AgentHostProtocol"));The client emits only counts, durations, and outcomes — never message content — so there is no sensitive-data switch to consider.
One span per JSON-RPC request:
| Span name | Kind | Attributes |
|---|---|---|
ahp.request {method} |
Client |
rpc.system=jsonrpc, rpc.method, ahp.outcome (ok | error | cancelled | timeout); status Ok/Error |
The name follows the OpenTelemetry {operation} {target} shape (e.g.
ahp.request initialize), and the rpc.* attributes follow the OTel RPC
semantic conventions.
| Metric name | Instrument | Unit | Attributes |
|---|---|---|---|
ahp.client.messages.sent |
Counter | {message} |
ahp.message.kind (request | notification) |
ahp.client.messages.received |
Counter | {message} |
— |
ahp.client.request.duration |
Histogram | ms |
rpc.method, ahp.outcome |
ahp.client.requests.in_flight |
UpDownCounter | {request} |
— |
ahp.client.subscriptions.active |
UpDownCounter | {subscription} |
— |
ahp.client.reconnects |
Counter | {reconnect} |
ahp.outcome |
ahp.client.events.dropped |
Counter | {event} |
ahp.stream (subscription | event | state | host-*) |
ahp.client.frames.malformed |
Counter | {frame} |
— |
Metric names are lowercase-dotted per OpenTelemetry convention (the C# instrument
fields are PascalCase). A consumer's own ILogger written inside one of the
client's spans auto-correlates to that trace, so no logs are originated here.