.NET 8独立进程Azure Functions集成Serilog后AI日志重复问题
问题
我有一个基于.NET 8的独立工作进程Azure Functions项目,已集成ASP.NET Core。为记录范围属性,我希望使用Serilog及Application Insights接收器。
本地配置中已定义APPINSIGHTS_INSTRUMENTATIONKEY和APPLICATIONINSIGHTS_CONNECTION_STRING,Program.cs代码如下:
var host = new HostBuilder() .ConfigureFunctionsWebApplication(worker => {}) .ConfigureAppConfiguration((hostingContext, configBuilder) => { configBuilder.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true); }) .ConfigureServices((hostBuilderContext, services) => { services.AddApplicationInsightsTelemetryWorkerService(); services.ConfigureFunctionsApplicationInsights(); }) .UseSerilog((context, provider, configuration) => { var telemetryClient = provider.GetRequiredService<TelemetryClient>(); configuration .Enrich.WithMachineName() .Enrich.WithEnvironmentName() .Enrich.FromLogContext() .WriteTo.ApplicationInsights(telemetryClient, TelemetryConverter.Traces) .WriteTo.Console(); }) .Build(); await host.RunAsync();
host.json配置如下:
{ "version": "2.0", "extensions": { "durableTask": { "storageProvider": { "type": "mssql", "connectionStringName": "EnterpriseResourcePlanningServicesDbConnection", "taskEventLockTimeout": "00:02:00", "createDatabaseIfNotExists": true, "schemaName": "dt" } } } }
本地运行时出现日志重复:一条带[INF]标识的日志在customDimensions中无范围数据,另一条则包含完整的范围属性。尝试清除HostBuilder的ConfigureLogging提供程序但无效,请问问题原因及解决方法?
重复日志示例:
问题原因
- 双重日志管道冲突:同时启用了两个向Application Insights写入日志的路径:
- 一是通过
services.AddApplicationInsightsTelemetryWorkerService()和services.ConfigureFunctionsApplicationInsights()注册的Azure Functions默认日志提供程序,它会自动发送日志到AI,但不会处理Serilog的LogContext范围属性; - 二是Serilog的
WriteTo.ApplicationInsights接收器,它会携带LogContext中的范围属性,但和默认管道形成重复输出。
- 一是通过
- 默认日志提供程序未彻底移除:仅清除ConfigureLogging的提供程序不足以禁用Azure Functions独立工作进程自动注册的内置日志提供程序,需要显式处理。
解决方法
方案1:禁用默认AI日志提供程序,仅保留Serilog管道
修改Program.cs,调整服务注册逻辑,彻底移除默认日志提供程序:
var host = new HostBuilder() .ConfigureFunctionsWebApplication(worker => {}) .ConfigureAppConfiguration((hostingContext, configBuilder) => { configBuilder.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true); }) .ConfigureServices((hostBuilderContext, services) => { // 注册Application Insights核心服务,禁用默认日志相关配置 services.AddApplicationInsightsTelemetryWorkerService(options => { options.EnableAdaptiveSampling = true; }); // 移除所有默认日志提供程序,避免冲突 services.RemoveAll<ILoggerProvider>(); }) .UseSerilog((context, provider, configuration) => { var telemetryClient = provider.GetRequiredService<TelemetryClient>(); configuration .Enrich.WithMachineName() .Enrich.WithEnvironmentName() .Enrich.FromLogContext() .WriteTo.ApplicationInsights(telemetryClient, TelemetryConverter.Events) // 可选:用Events替代Traces,避免格式冲突 .WriteTo.Console(); }) .Build(); await host.RunAsync();
方案2:让默认日志系统使用Serilog作为底层提供程序
统一日志管道,让Azure Functions默认日志流程基于Serilog运行:
var host = new HostBuilder() .ConfigureFunctionsWebApplication(worker => {}) .ConfigureAppConfiguration((hostingContext, configBuilder) => { configBuilder.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true); }) .ConfigureLogging((context, logging) => { // 清除所有默认日志提供程序 logging.ClearProviders(); // 添加Serilog作为唯一日志提供程序 logging.AddSerilog(dispose: true); }) .ConfigureServices((hostBuilderContext, services) => { services.AddApplicationInsightsTelemetryWorkerService(); services.ConfigureFunctionsApplicationInsights(); }) .UseSerilog((context, provider, configuration) => { configuration .Enrich.WithMachineName() .Enrich.WithEnvironmentName() .Enrich.FromLogContext() .WriteTo.ApplicationInsights(provider.GetRequiredService<TelemetryClient>(), TelemetryConverter.Traces) .WriteTo.Console(); }) .Build(); await host.RunAsync();
额外优化:配置host.json精简日志输出
在host.json中添加日志级别配置,减少冗余日志:
{ "version": "2.0", "logging": { "logLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" }, "applicationInsights": { "enableDependencyTracking": true, "enablePerformanceCountersCollection": true, "enableLiveMetrics": true, "disableTelemetry": false } }, "extensions": { "durableTask": { "storageProvider": { "type": "mssql", "connectionStringName": "EnterpriseResourcePlanningServicesDbConnection", "taskEventLockTimeout": "00:02:00", "createDatabaseIfNotExists": true, "schemaName": "dt" } } } }
内容的提问来源于stack exchange,提问作者321X
相关产品推荐
相关产品推荐

