.NET Web API:ILogger日志接入OpenTelemetry-Jaeger无显示问题排查
.NET Web API日志无法关联Jaeger链路追踪的问题排查与修复
问题场景
在.NET Web API中,通过ILogger、OpenTelemetry协议向Jaeger Collector上报日志并关联链路追踪时,使用Activity.AddEvent()添加的日志能在Jaeger UI正常显示,但调用logger.LogInformation()输出的日志无法被Jaeger捕获关联。
用户原配置代码:
var serviceName = "some_service_name" + mode.ToString(); var jaegrCollectorUrl = "http://jaeger_collector_url:4317"; builder.Services.AddOpenTelemetry() .ConfigureResource(resource => resource.AddService(serviceName: serviceName)) .WithMetrics() .WithTracing(tracing => tracing .AddJaegerExporter(a => { a.Endpoint = new Uri(jaegrCollectorUrl); }) .AddAspNetCoreInstrumentation(opt => { opt.EnrichWithHttpRequest = (activity, httpRequest) => { activity.DisplayName = httpRequest.Path.Value; }; }) .AddHttpClientInstrumentation() .AddEntityFrameworkCoreInstrumentation(options => { options.EnrichWithIDbCommand = (activity, command) => { activity.DisplayName = $"EFCore DB Command: ({command.CommandType})"; activity.SetTag("command_text", command.CommandText); activity.AddTag("method_name", null); }; }) .AddOtlpExporter(otlpOptions => { otlpOptions.Endpoint = new Uri(jaegrCollectorUrl); otlpOptions.Protocol = OtlpExportProtocol.Grpc; })); builder.Logging.ClearProviders(); Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .WriteTo.Console() .WriteTo.OpenTelemetry(a => { a.Endpoint = jaegrCollectorUrl; a.Protocol = OtlpProtocol.Grpc; }) .CreateLogger(); builder.Logging.AddSerilog(Log.Logger);
问题原因
- Serilog未关联链路上下文:原配置中Serilog的OpenTelemetry输出没有绑定当前的
Activity(链路上下文),导致日志无法关联到对应的Trace/Span。 - 重复Exporter配置:同时添加
JaegerExporter和OtlpExporter,两者功能重叠,可能引发上报逻辑冲突。 - 日志缺少链路标识:日志未注入TraceId和SpanId,Jaeger无法将日志匹配到具体链路。
修复步骤及代码调整
1. 修改Serilog配置,关联链路上下文
添加日志上下文 enrichment,确保链路信息被注入到日志中:
builder.Logging.ClearProviders(); Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .Enrich.FromLogContext() // 从日志上下文获取当前Activity信息 .Enrich.WithTraceIdAndSpanId() // 自动注入TraceId、SpanId到日志属性 .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} TraceId:{TraceId} SpanId:{SpanId}{NewLine}{Exception}") // 控制台输出链路ID方便调试 .WriteTo.OpenTelemetry(options => { options.Endpoint = jaegrCollectorUrl; options.Protocol = OtlpProtocol.Grpc; options.ResourceAttributes = new Dictionary<string, object> { { "service.name", serviceName } // 确保服务名称与OTel配置一致 }; options.IncludeScopes = true; // 包含日志作用域,关联Activity上下文 }) .CreateLogger(); builder.Logging.AddSerilog(Log.Logger);
2. 简化OpenTelemetry Tracing配置
Jaeger原生支持OTLP协议,无需同时配置JaegerExporter,保留OtlpExporter即可:
builder.Services.AddOpenTelemetry() .ConfigureResource(resource => resource.AddService(serviceName: serviceName)) .WithMetrics() .WithTracing(tracing => tracing .AddAspNetCoreInstrumentation(opt => { opt.EnrichWithHttpRequest = (activity, httpRequest) => { activity.DisplayName = httpRequest.Path.Value; }; }) .AddHttpClientInstrumentation() .AddEntityFrameworkCoreInstrumentation(options => { options.EnrichWithIDbCommand = (activity, command) => { activity.DisplayName = $"EFCore DB Command: ({command.CommandType})"; activity.SetTag("command_text", command.CommandText); // 移除null值的tag,避免潜在异常 // activity.AddTag("method_name", null); }; }) .AddOtlpExporter(otlpOptions => { otlpOptions.Endpoint = new Uri(jaegrCollectorUrl); otlpOptions.Protocol = OtlpExportProtocol.Grpc; }));
3. 确保日志在链路上下文内输出
在API请求的Action中,AspNetCoreInstrumentation会自动创建Activity,此时调用ILogger的日志会自动关联链路:
[ApiController] [Route("[controller]")] public class DemoController : ControllerBase { private readonly ILogger<DemoController> _logger; public DemoController(ILogger<DemoController> logger) { _logger = logger; } [HttpGet] public IActionResult Index() { // 此时已存在请求对应的Activity,日志会自动关联链路 _logger.LogInformation("Starting work. 2: "); return Ok(); } }
修改完成后,logger.Log输出的日志会携带TraceId和SpanId,并通过OpenTelemetry上报到Jaeger,即可在对应链路的详情页面中查看这些日志。
内容的提问来源于stack exchange,提问作者Mohamad Lashgarbolok
相关产品推荐
相关产品推荐

