OpenTelemetry: context propagation and semconv update (#262)

This commit is contained in:
Liudmila Molkova 2025-04-12 19:12:11 -07:00 • committed by GitHub
commit d6cc65aced
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 398 additions and 89 deletions

View file

@ -12,4 +12,11 @@
<ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
</ItemGroup>
</Project>

View file

@ -1,10 +1,23 @@
using TestServerWithHosting.Tools;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using OpenTelemetry;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpServer()
.WithTools<EchoTool>()
.WithTools<SampleLlmTool>();
builder.Services.AddOpenTelemetry()
.WithTracing(b => b.AddSource("*")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation())
.WithMetrics(b => b.AddMeter("*")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation())
.WithLogging()
.UseOtlpExporter();
var app = builder.Build();
app.MapMcp();

View file

@ -6,7 +6,8 @@
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:3001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Development",
"OTEL_SERVICE_NAME": "sse-server",
}
},
"https": {
@ -14,7 +15,8 @@
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7133;http://localhost:3001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
"ASPNETCORE_ENVIRONMENT": "Development",
"OTEL_SERVICE_NAME": "sse-server",
}
}
}

View file

@ -15,6 +15,8 @@
<PackageReference Include="Microsoft.Extensions.AI" />
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
<PackageReference Include="Anthropic.SDK" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
</ItemGroup>
<ItemGroup>

View file

@ -3,15 +3,49 @@ using ModelContextProtocol.Protocol.Transport;
using Microsoft.Extensions.AI;
using OpenAI;
using OpenTelemetry;
using OpenTelemetry.Trace;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddHttpClientInstrumentation()
.AddSource("*")
.AddOtlpExporter()
.Build();
using var metricsProvider = Sdk.CreateMeterProviderBuilder()
.AddHttpClientInstrumentation()
.AddMeter("*")
.AddOtlpExporter()
.Build();
using var loggerFactory = LoggerFactory.Create(builder => builder.AddOpenTelemetry(opt => opt.AddOtlpExporter()));
// Connect to an MCP server
Console.WriteLine("Connecting client to MCP 'everything' server");
// Create OpenAI client (or any other compatible with IChatClient)
// Provide your own OPENAI_API_KEY via an environment variable.
var openAIClient = new OpenAIClient(Environment.GetEnvironmentVariable("OPENAI_API_KEY")).GetChatClient("gpt-4o-mini");
// Create a sampling client.
using IChatClient samplingClient = openAIClient.AsIChatClient()
.AsBuilder()
.UseOpenTelemetry(loggerFactory: loggerFactory, configure: o => o.EnableSensitiveData = true)
.Build();
var mcpClient = await McpClientFactory.CreateAsync(
new StdioClientTransport(new()
{
Command = "npx",
Arguments = ["-y", "--verbose", "@modelcontextprotocol/server-everything"],
Name = "Everything",
}));
}),
clientOptions: new()
{
Capabilities = new() { Sampling = new() { SamplingHandler = samplingClient.CreateSamplingHandler() } },
},
loggerFactory: loggerFactory);
// Get all available tools
Console.WriteLine("Tools available:");
@ -20,13 +54,15 @@ foreach (var tool in tools)
{
Console.WriteLine($" {tool}");
}
Console.WriteLine();
// Create an IChatClient. (This shows using OpenAIClient, but it could be any other IChatClient implementation.)
// Provide your own OPENAI_API_KEY via an environment variable.
using IChatClient chatClient =
new OpenAIClient(Environment.GetEnvironmentVariable("OPENAI_API_KEY")).GetChatClient("gpt-4o-mini").AsIChatClient()
.AsBuilder().UseFunctionInvocation().Build();
// Create an IChatClient that can use the tools.
using IChatClient chatClient = openAIClient.AsIChatClient()
.AsBuilder()
.UseFunctionInvocation()
.UseOpenTelemetry(loggerFactory: loggerFactory, configure: o => o.EnableSensitiveData = true)
.Build();
// Have a conversation, making all tools available to the LLM.
List<ChatMessage> messages = [];

View file

@ -9,6 +9,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
</ItemGroup>
<ItemGroup>

View file

@ -8,6 +8,11 @@ using Microsoft.Extensions.Logging;
using ModelContextProtocol;
using ModelContextProtocol.Protocol.Types;
using ModelContextProtocol.Server;
using OpenTelemetry;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
@ -186,6 +191,13 @@ builder.Services
return new EmptyResult();
});
ResourceBuilder resource = ResourceBuilder.CreateDefault().AddService("everything-server");
builder.Services.AddOpenTelemetry()
.WithTracing(b => b.AddSource("*").AddHttpClientInstrumentation().SetResourceBuilder(resource))
.WithMetrics(b => b.AddMeter("*").AddHttpClientInstrumentation().SetResourceBuilder(resource))
.WithLogging(b => b.SetResourceBuilder(resource))
.UseOtlpExporter();
builder.Services.AddSingleton(subscriptions);
builder.Services.AddHostedService<SubscriptionMessageSender>();
builder.Services.AddHostedService<LoggingUpdateMessageSender>();