无法在Grafana Tempo中获取OpenTelemetry手动日志问题
我按照OpenTelemetry的.NET快速入门指南操作,已通过Docker部署Grafana Tempo,成功捕获所有链路追踪数据(包括HTTP调用、异常及数据库查询),可在Grafana Tempo explorer中查看。为测试,我在Swagger中创建了4个路由,当前遇到的问题:通过_logger.LogInformation("hello")等方式输出的手动日志能在控制台正常显示,但无法在Grafana Tempo中检索到。
相关代码如下:
日志接口代码
// My SendLogs endpoint [HttpGet("SendLogs")] public void SendLogs() { _logger.LogInformation("Info log"); _logger.LogTrace("Trace log"); _logger.LogDebug("Debug log"); _logger.LogWarning("Warning log"); _logger.LogError("Error log"); _logger.LogCritical("Critical log"); }
Program.cs配置代码
//... builder.Services.AddOpenTelemetry() .WithTracing(tracerProviderBuilder => tracerProviderBuilder .AddSource(DiagnosticsConfig.ActivitySource.Name) .ConfigureResource(resource => resource.AddService(DiagnosticsConfig.ServiceName)) .AddAspNetCoreInstrumentation(options => { options.RecordException = true; }) .AddConsoleExporter() .AddOtlpExporter() .AddNpgsql() ) .WithMetrics(metricsProviderBuilder => metricsProviderBuilder .ConfigureResource(resource => resource.AddService(DiagnosticsConfig.ServiceName)) .AddAspNetCoreInstrumentation() //.AddConsoleExporter() .AddOtlpExporter() ); builder.Services.AddEntityFrameworkNpgsql().AddDbContext<ApiDbContext>(opt => { opt.UseNpgsql(builder.Configuration.GetConnectionString("SampleDbConnection")); }); builder.Logging.ClearProviders(); ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault().AddService(DiagnosticsConfig.ServiceName); builder.Logging.AddOpenTelemetry(options => { options .SetResourceBuilder(resourceBuilder) .AddConsoleExporter() .AddOtlpExporter(); }); builder.Services.Configure<OpenTelemetryLoggerOptions>(opt => { opt.IncludeScopes = true; opt.ParseStateValues = true; opt.IncludeFormattedMessage = true; }); //...
1. 明确Grafana Tempo的定位
Tempo是链路追踪存储系统,本身不直接存储日志。日志需要先发送到支持日志存储的系统(比如Loki、Elasticsearch),再通过Grafana关联Tempo的追踪数据进行检索。如果想让日志和链路关联显示,必须确保日志包含Trace ID和Span ID。
2. 配置日志自动注入追踪上下文
修改OpenTelemetry日志配置,让日志自动携带Trace ID和Span ID,同时将日志发送到日志存储系统:
步骤1:安装必要NuGet包
以Loki作为日志存储为例,安装相关包:
Install-Package OpenTelemetry.Exporter.OpenTelemetryProtocol Install-Package Grafana.Loki.LoggerProvider
步骤2:调整Program.cs日志配置
builder.Logging.ClearProviders(); ResourceBuilder resourceBuilder = ResourceBuilder.CreateDefault().AddService(DiagnosticsConfig.ServiceName); builder.Logging.AddOpenTelemetry(options => { options .SetResourceBuilder(resourceBuilder) .AddConsoleExporter() .AddOtlpExporter(opt => { // 配置OTLP端点指向日志存储的OTLP入口(如Loki或OpenTelemetry Collector) opt.Endpoint = new Uri("http://your-log-storage-otlp-endpoint:4317"); }); // 开启日志上下文与追踪关联 options.IncludeScopes = true; options.ParseStateValues = true; options.IncludeFormattedMessage = true; // 手动注入Trace ID和Span ID到日志属性 options.EnrichWithScope((logRecord, scope) => { if (Activity.Current != null) { logRecord.Attributes["trace_id"] = Activity.Current.TraceId.ToString(); logRecord.Attributes["span_id"] = Activity.Current.SpanId.ToString(); } }); }); // 若直接使用Loki Exporter,可替换为以下配置(可选) // builder.Logging.AddLoki(options => // { // options.Uri = new Uri("http://your-loki-instance:3100"); // options.LabelProvider = (logLevel, categoryName) => new List<LokiLabel> // { // new LokiLabel("service", DiagnosticsConfig.ServiceName), // new LokiLabel("trace_id", Activity.Current?.TraceId.ToString() ?? string.Empty), // new LokiLabel("span_id", Activity.Current?.SpanId.ToString() ?? string.Empty) // }; // });
3. 校验OTLP配置一致性
确保日志的OTLP导出配置(端点、协议、认证信息等)和追踪的OTLP配置完全一致。如果使用OpenTelemetry Collector作为中转,需配置Collector同时接收追踪和日志数据,分别转发到Tempo和日志存储系统。
4. 验证日志级别设置
检查appsettings.json中的日志级别,确保能覆盖你输出的所有日志等级:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "YourAppNamespace": "Trace" // 替换为你的项目命名空间,确保能捕获Trace/Debug级日志 } } }
5. 在Grafana中关联日志与追踪
配置Grafana的Loki(或其他日志存储)数据源后,在Tempo explorer中查看追踪时,可通过Trace ID跳转到对应日志;也可在Loki查询中通过{trace_id="目标TraceID"}检索关联的日志内容。
内容的提问来源于stack exchange,提问作者thibsc

