Skip to main content

OpenTelemetry Support in Teams SDK for .NET 2.1 Preview

Teams SDK for .NET 2.1 Preview now emits OpenTelemetry traces, metrics, and correlated logs. Route them to Azure Monitor / Application Insights, a local OTLP collector, or both โ€” the SDK emits the telemetry; your app decides where it goes.

Why This Mattersโ€‹

A single user message can trigger middleware, handler dispatch, token acquisition, outbound Bot Service calls, and downstream service requests. When something goes wrong โ€” or just runs slow โ€” isolated log lines are not enough. You need to see the full turn, end to end.

The Teams SDK now instruments its pipeline through standard .NET primitives โ€” ActivitySource, Meter, and ILogger. This is not proprietary instrumentation โ€” it is the same OpenTelemetry model that the rest of the .NET ecosystem uses. The SDK follows the .NET library instrumentation guidance: libraries produce telemetry; applications choose collection and export.

End-to-end observability architecture: the Teams SDK emits telemetry via .NET primitives (ActivitySource, Meter, ILogger), the ASP.NET Core host opts into collection and export, and exporters route data to Azure Monitor, OTLP local tooling, or governed backends

Two Lines of Teams-Specific Codeโ€‹

The only Teams-specific wiring is registering the SDK's ActivitySource and Meter names:

tracing.AddSource(new[] { CoreTelemetryNames.ActivitySourceName,
TeamsBotApplicationTelemetry.ActivitySourceName });

metrics.AddMeter(new[] { CoreTelemetryNames.MeterName,
TeamsBotApplicationTelemetry.MeterName });

Everything else โ€” ASP.NET Core and HttpClient auto-instrumentation, exporters, logging โ€” is standard OpenTelemetry .NET setup. With .NET Aspire service defaults, your bot's Program.cs stays minimal:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults(); // configures OpenTelemetry, health checks, service discovery
builder.Services.AddTeamsBotApplication();
WebApplication app = builder.Build();

TeamsBotApplication bot = app.UseTeamsBotApplication();

bot.OnMessage(async (ctx, ct) =>
{
string? message = ctx.Activity.TextWithoutMentions;
await ctx.SendActivityAsync($"Echo: {message}", ct);
});

app.MapDefaultEndpoints();
app.Run();

What You Seeโ€‹

In Application Insights, you can inspect each turn end-to-end โ€” from the inbound request through middleware, handler dispatch, token acquisition, and outbound Bot Service calls:

Application Insights end-to-end transaction view showing the span hierarchy for a bot turn โ€” turn, handler, conversation_client, auth.outbound, and the outbound Bot Service call

The same telemetry works locally with any OTLP-compatible backend. The sample includes an Aspire AppHost โ€” run it and the dashboard opens automatically:

Aspire Dashboard trace view showing the bot turn span hierarchy โ€” POST api/messages, turn, handler, conversation_client, auth.outbound, and the outbound Bot Service POST

For bots that call AI models through Microsoft.Extensions.AI, you get the full chain โ€” from the inbound message, through chat completions and MCP tool calls, and back out through the Bot Service response:

Application Insights end-to-end transaction showing an AI bot turn โ€” handler, orchestrate_tools, two gpt-5.4-mini chat completions, an MCP microsoft_docs_search tool call, and the outbound Bot Service response

Try Itโ€‹

Two samples are available to get started:

SampleWhat it shows
OTelBotWithAspireEcho bot with Aspire service defaults and dashboard
AIBotWithOTelAI bot with Azure OpenAI, MCP tools, and full LLM tracing

For the complete setup guide โ€” including standalone (non-Aspire) configuration, Azure Monitor, Grafana LGTM, resource attributes, metrics reference, and AI instrumentation details โ€” see the OpenTelemetry in-depth guide.

We'd love your feedback on the observability experience. File issues on the GitHub repository.