ASP.NET Core 7 Web API集成OpenTelemetry报错:AspNetCoreInstrumentationOptions无Enrich定义
已配置Jaeger/OpenTelemetry链路追踪且能正常生成数据,但尝试手动访问追踪上下文并赋值到自定义变量时,触发错误:
'AspNetCoreInstrumentationOptions' does not contain a definition for 'Enrich' and no accessible extension method 'Enrich' accepting a first argument of type 'AspNetCoreInstrumentationOptions' could be found (are you missing a using directive or an assembly reference?)
目标是从接口调用的追踪数据中提取Activity.TraceId和Activity.SpanId,赋值到以下自定义静态List:
namespace CustomerAPI.Helpers { public static class CorrelationData { public static List<KeyValuePair<string, string>> Correlation { get; set; } = new List<KeyValuePair<string, string>>(); } }
尝试修改.AddAspNetCoreInstrumentation()配置时触发上述错误,代码如下:
using OpenTelemetry; using OpenTelemetry.Trace; using OpenTelemetry.Resources; using OpenTelemetry.Metrics; using OpenTelemetry.Instrumentation.Http; using OpenTelemetry.Exporter.Jaeger; using OpenTelemetry.Exporter; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; var appBuilder = WebApplication.CreateBuilder(args); appBuilder.Services.AddOpenTelemetry() .ConfigureResource(builder => builder.AddService(serviceName: "CustomerAPI")) .WithTracing(builder => builder .AddAspNetCoreInstrumentation(options => { options.Filter = httpContext => true; options.Enrich = activity => { // Extract trace information var traceId = activity.TraceId; var spanId = activity.SpanId; // Add trace information to the Correlation list CorrelationData.Correlation.Add(new KeyValuePair<string, string>("Activity.TraceId", traceId.ToHexString())); CorrelationData.Correlation.Add(new KeyValuePair<string, string>("Activity.SpanId", spanId.ToHexString())); return; }; }) .AddHttpClientInstrumentation() .AddConsoleExporter() .AddJaegerExporter(o => { o.AgentHost = "localhost"; o.AgentPort = 6831; o.Endpoint = new Uri("localhost:14268"); o.Protocol = JaegerExportProtocol.UdpCompactThrift; })) .WithMetrics(builder => builder.AddConsoleExporter()); appBuilder.Services.AddControllers(); appBuilder.Services.AddHttpClient(); appBuilder.Services.AddEndpointsApiExplorer();
解决方案
1. 补全缺失的依赖与命名空间
Enrich方法属于OpenTelemetry.Instrumentation.AspNetCore包的扩展功能,你需要:
- 安装NuGet包:
OpenTelemetry.Instrumentation.AspNetCore(确保版本与其他OpenTelemetry包一致) - 在代码顶部添加命名空间引用:
using OpenTelemetry.Instrumentation.AspNetCore;
2. 修正Enrich的方法签名
AspNetCoreInstrumentationOptions的Enrich委托并非仅接收Activity参数,正确签名包含三个参数:Activity、事件名称string、原始对象object。修正后的配置代码如下:
.AddAspNetCoreInstrumentation(options => { options.Filter = httpContext => true; options.Enrich = (activity, eventName, rawObject) => { // 建议只在Span启动时处理,避免重复添加 if (eventName == "OnStartActivity") { var traceId = activity.TraceId.ToHexString(); var spanId = activity.SpanId.ToHexString(); // 注意:静态List存在线程安全问题,多请求并发会导致异常,建议改用AsyncLocal存储 CorrelationData.Correlation.Add(new KeyValuePair<string, string>("Activity.TraceId", traceId)); CorrelationData.Correlation.Add(new KeyValuePair<string, string>("Activity.SpanId", spanId)); } }; })
3. 更直接的访问方式:使用Activity.Current
无需通过Enrich,在请求处理的任意阶段(控制器、中间件、服务中),都可以直接通过Activity.Current获取当前追踪上下文:
// 在控制器Action中示例 [ApiController] [Route("api/customers")] public class CustomerController : ControllerBase { [HttpGet] public IActionResult Get() { var traceId = Activity.Current?.TraceId.ToHexString(); var spanId = Activity.Current?.SpanId.ToHexString(); // 赋值到自定义变量 if (traceId != null && spanId != null) { CorrelationData.Correlation.Add(new KeyValuePair<string, string>("Activity.TraceId", traceId)); CorrelationData.Correlation.Add(new KeyValuePair<string, string>("Activity.SpanId", spanId)); } return Ok(); } }
注意事项
- 静态
List<KeyValuePair<string, string>>存在严重线程安全问题,多请求并发时会引发InvalidOperationException,建议改用AsyncLocal<T>来存储请求级别的关联数据:namespace CustomerAPI.Helpers { public static class CorrelationData { private static readonly AsyncLocal<Dictionary<string, string>> _correlation = new(); public static Dictionary<string, string> Correlation { get => _correlation.Value ??= new Dictionary<string, string>(); set => _correlation.Value = value; } } }
内容的提问来源于stack exchange,提问作者Golide

