添加自定义ActivitySource后.NET API的OpenTelemetry端点追踪失效问题
.NET REST API中OpenTelemetry追踪异常问题
在包含后台服务的.NET REST API项目中配置OpenTelemetry,用于追踪端点调用和服务活动。未添加.AddSource(CustomActivitySources.MessageServiceSource.Name)时,端点追踪正常;添加后所有端点请求的追踪完全停止生成。预期自定义活动源与AspNetCore端点追踪是独立功能,不应互相影响,需解决该问题。
原因分析
问题根源在CustomActivitySources静态构造函数中注册的全局ActivityListener:
- 该监听器设置
ShouldListenTo = _ => true,会监听所有ActivitySource创建的活动 - 它的
Sample方法返回ActivitySamplingResult.AllData,但这个全局监听器的采样逻辑会直接覆盖OpenTelemetry TracerProvider的采样配置(包括你设置的AlwaysOnSampler) - 添加自定义
AddSource后,OpenTelemetry的TracerProvider与全局ActivityListener产生冲突,导致AspNetCore instrumentation生成的活动被错误拦截,最终无法导出
修复方法
方案1:移除全局ActivityListener(推荐)
OpenTelemetry已自带完整的采样和追踪处理逻辑,无需额外注册全局ActivityListener。修改CustomActivitySources类:
internal static class CustomActivitySources { internal static readonly ActivitySource MessageServiceSource = new("MessageService"); // 移除静态构造函数中的全局ActivityListener }
方案2:限制全局ActivityListener的监听范围
若必须保留全局监听器,修改ShouldListenTo仅监听自定义活动源,避免干扰OpenTelemetry内置instrumentation:
static CustomActivitySources() { ActivitySource.AddActivityListener(new ActivityListener() { ShouldListenTo = source => source.Name == MessageServiceSource.Name, Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData, }); }
方案3:调整OpenTelemetry配置顺序(临时规避)
确保AddAspNetCoreInstrumentation()和AddHttpClientInstrumentation()在AddSource()之前调用,仅作为临时解决方式,推荐优先使用前两种方案:
tracerProviderBuilder .SetSampler(new AlwaysOnSampler()) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddSource(CustomActivitySources.MessageServiceSource.Name) .AddProcessor<TracerEndPointsFilterProcessor>();
相关指导
- 避免混用全局
ActivityListener与OpenTelemetry:OpenTelemetry通过TracerProvider统一管理追踪,全局ActivityListener会绕过其逻辑,引发冲突 - 自定义活动源正确用法:只需创建
ActivitySource实例,通过OpenTelemetry的.AddSource()注册,由OpenTelemetry统一处理采样、导出 - 更优雅的端点过滤方式:推荐使用
AspNetCoreInstrumentationOptions的Filter配置替代自定义处理器修改ActivityTraceFlags:.AddAspNetCoreInstrumentation(options => { options.Filter = context => !context.Request.Path.StartsWithSegments("/version") && !context.Request.Path.StartsWithSegments("/health") && !context.Request.Path.StartsWithSegments("/swagger"); }) - 版本升级建议:当前
OpenTelemetry.Instrumentation.AspNetCore版本为1.0.0-rc9.11,建议升级到稳定版(如1.5.1),规避旧版本已知问题
原始代码参考
包引用
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.3.2" /> <PackageReference Include="OpenTelemetry.Exporter.Jaeger" Version="1.3.2" /> <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.0.0-rc9.11" />
初始追踪配置
services.AddOpenTelemetry() .ConfigureResource(resourceBuilder => { resourceBuilder.AddService( serviceName: "main service name", serviceVersion: "1", serviceInstanceId: Environment.MachineName); }) .WithTracing(tracerProviderBuilder => { tracerProviderBuilder .SetSampler(new AlwaysOnSampler()) .AddSource(CustomActivitySources.MessageServiceSource.Name) .AddProcessor<TracerEndPointsFilterProcessor>() .AddHttpClientInstrumentation() .AddAspNetCoreInstrumentation(); });
自定义处理器TracerEndPointsFilterProcessor
internal sealed class TracerEndPointsFilterProcessor : BaseProcessor<Activity> { public override void OnEnd(Activity activity) { if (IsHealthOrMetricsEndpoint(activity.DisplayName)) { activity.ActivityTraceFlags &= ~ActivityTraceFlags.Recorded; } } private static bool IsHealthOrMetricsEndpoint(string displayName) { if (string.IsNullOrEmpty(displayName)) { return false; } return displayName.StartsWith("/version", StringComparison.CurrentCultureIgnoreCase) || displayName.StartsWith("/health", StringComparison.CurrentCultureIgnoreCase) || displayName.StartsWith("/swagger", StringComparison.CurrentCultureIgnoreCase); } }
自定义活动源类CustomActivitySources
internal static class CustomActivitySources { internal static readonly ActivitySource MessageServiceSource = new("MessageService"); static CustomActivitySources() { ActivitySource.AddActivityListener(new ActivityListener() { ShouldListenTo = _ => true, Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData, }); } }
非HTTP服务活动使用示例
var initialTags = new ActivityTagsCollection { // some tags }; const string activityName = "ServiceName"; activity = CustomActivitySources.MessageServiceSource.StartActivity(activityName, ActivityKind.Consumer, "trace id", initialTags);
内容的提问来源于stack exchange,提问作者Katia
相关产品推荐
相关产品推荐

