Azure Function中Serilog日志流依赖hosts.json配置的原因解析及无该配置的实现方案
首先来解释你遇到的这个现象:
Azure Functions的宿主环境自带了一套独立的日志过滤机制,这套机制完全由host.json里的logging配置说了算,和Serilog自己的日志级别配置是分开的。当你把Serilog注册成日志提供者后,Serilog输出的日志会先经过Functions宿主的过滤管道——哪怕Serilog已经允许Information级别的日志输出,只要host.json里的logging.logLevel.default没设到Information或更低,宿主就会把这些日志拦下来,所以日志流里看不到。
而App Insights的日志是Serilog通过WriteTo.ApplicationInsights直接写进去的,完全绕开了Functions宿主的过滤管道,所以不管host.json怎么配置,App Insights都能收到符合Serilog规则的日志。
接下来给你两个不用修改host.json就能解决问题的方案:
方案1:用Serilog的Azure Functions专用Sink
这是最推荐的方案,Serilog专门做了适配Azure Functions的Sink(Serilog.Sinks.AzureFunctions),它能直接和Functions的日志系统交互,完全尊重Serilog的配置优先级,不用依赖host.json的设置。
步骤很简单:
- 先安装对应的NuGet包:
Serilog.Sinks.AzureFunctions - 修改你的
CreateLogger方法,把WriteTo.Console()替换成WriteTo.AzureFunctions()就行:
public static Logger CreateLogger(string applicationName) { var instrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY"); return new LoggerConfiguration() .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .Enrich.FromLogContext() .Enrich.WithProperty("Application", applicationName) .Enrich.WithCorrelationIdHeader(Constants.CorrelationIdHeader) .WriteTo.AzureFunctions() // 替换原有的Console输出 .WriteTo.ApplicationInsights(new TelemetryConfiguration(instrumentationKey), TelemetryConverter.Traces) .CreateLogger(); }
方案2:禁用宿主的日志过滤(适合坚持用Console输出的场景)
如果你不想换Sink,可以通过配置让Functions宿主不对Serilog的日志做过滤。修改你的SetupLogging方法:
public static void SetupLogging(this IServiceCollection services, string applicationName) { var logger = CreateLogger(applicationName); services.AddLogging(lb => { lb.ClearProviders(); // 清除宿主默认的日志提供者 lb.AddSerilog(logger); // 手动添加过滤规则,和Serilog的配置对齐 lb.AddFilter("default", LogLevel.Information); lb.AddFilter("Microsoft", LogLevel.Warning); }); }
不过要注意,清除默认提供者可能会影响Functions原生的一些系统日志输出,所以还是方案1更稳妥。
内容的提问来源于stack exchange,提问作者Jon

