Serilog写入Application Insights时错误/警告日志严重级别异常
问题描述
- 运行环境:dotnet-isolated模式下的.NET 6.0 Azure Function App,Serilog配置从appsettings.json读取,配置段如下:
"Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.ApplicationInsights" ], "WriteTo": [ { "Name": "Console", "Args": { "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console", "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} <s:{SourceContext}>{NewLine}{Exception}", "restrictedToMinimumLevel": "Information" } }, { "Name": "ApplicationInsights", "Args": { "instrumentationKey": "MASKED-KEY", "telemetryConverter": "MyTelemetryConverter, My", "restrictedToMinimumLevel": "Information" } } ], "Enrich": [ "FromLogContext" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Information", "System": "Information" } } }
- 启动时日志注册逻辑:在Program.cs中通过如下扩展方法加载Serilog配置:
public static IHostBuilder UseLogger(this IHostBuilder hostBuilder) { hostBuilder.ConfigureLogging(loggingBuilder => loggingBuilder.Services.AddSingleton<ILoggerProvider, DefaultLoggerProvider>()); hostBuilder.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration)); return hostBuilder; }
- 异常现象:ILogger可正常注入使用,日志可正常写入Application Insights(简称AI)。执行
_logger.LogError("My fictitious error message here");写入纯文本错误日志时,AI中该条日志的严重级别被标记为Information而非Error,警告级别日志存在相同问题;携带异常对象的日志级别显示正常。 - 佐证信息:
- 控制台输出中可看到
[6:25:36 ERR]标记,证明日志本身以Error级别输出到控制台,符合appsettings.json的格式化配置,且自定义MyTelemetryConverter实现未修改日志级别,对应AI端日志截图:
- 2022年6月17日更新:派生自
TraceTelemetryConverter的自定义转换器中,重写的Convert(...)方法内获取到的日志严重级别是正确的,对应截图:
- 控制台输出中可看到
问题根因
该问题是dotnet-isolated模式下Azure Functions内置日志管道与Serilog.ApplicationInsights Sink冲突导致:
- dotnet-isolated模式的Azure Functions工作进程默认会自动注册内置的Application Insights日志提供程序,该提供程序会拦截所有ILogger写入的日志,按照自身规则向AI发送遥测。其默认逻辑下,未携带异常对象的纯文本日志会被统一标记为Information级别,仅携带异常的日志会按实际级别映射。
- 当前配置未禁用这个内置AI日志提供程序,导致同一条日志被两个独立渠道写入AI:
- Serilog Console Sink直接输出到控制台,级别完全正确,因此控制台能看到ERR标记
- Serilog.ApplicationInsights Sink拿到的日志级别正确,因此自定义TelemetryConverter中读取到的级别符合预期
- 最终在AI中看到的级别错误的日志条目,实际是Functions内置AI日志提供程序写入的,而非Serilog Sink写入的条目,因此出现级别不匹配的问题。
修复方案
按以下步骤修改配置即可解决:
- 在Program.cs配置Functions工作进程时,禁用内置的Application Insights日志收集,避免重复写入和级别覆盖,示例代码:
var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults(builder => { // 禁用内置AI日志收集,切断内置提供程序的写入通道 builder.Services.Configure<FunctionsApplicationInsightsOptions>(opts => { opts.DisableLogCollection = true; }); }) .UseLogger() // 加载原有自定义日志注册逻辑 .Build();
- 修改
UseLogger扩展方法,注册日志前先清除所有默认注册的日志提供程序,同时配置Serilog不向其他日志提供程序路由日志,避免干扰:
public static IHostBuilder UseLogger(this IHostBuilder hostBuilder) { hostBuilder.ConfigureLogging(loggingBuilder => { // 清除所有默认注册的日志提供程序,包括内置AI日志提供程序 loggingBuilder.ClearProviders(); loggingBuilder.Services.AddSingleton<ILoggerProvider, DefaultLoggerProvider>(); }); hostBuilder.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration), preserveStaticLogger: true, writeToProviders: false // 关闭向其他日志提供程序的路由,避免重复日志 ); return hostBuilder; }
- (可选校验)将项目引用的
Serilog.Sinks.ApplicationInsightsNuGet包升级到4.0.0及以上版本,旧版本存在非异常日志级别映射的已知bug,升级后可覆盖边缘场景的异常问题。
修改完成后重新发布应用,纯文本的Error、Warning级别日志即可在AI中显示正确的严重级别。
内容的提问来源于stack exchange,提问作者Arash
相关产品推荐
相关产品推荐

