如何配置Serilog按日志类型输出到不同文件Sink?
ASP.NET Core Serilog按日志类型分Sink输出问题解决
问题场景
在ASP.NET Core项目中使用Serilog,需要实现:
- 标记为
Weather logs的日志输出到logs/weather-.json文件 - 其余所有日志输出到
logs/nin-.json文件
当前两个日志文件内容完全重复,已安装Serilog.AspNetCore和Serilog.Expressions依赖。
现有代码与配置
控制器代码
using Microsoft.AspNetCore.Mvc; using Serilog; namespace LoggerTest.Controllers { [ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private static readonly string[] nins = new[] { "1", "2", "3", "4", "6", "7", "8", "9", "10", "11" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; _logger.LogInformation("WeatherForecast controller called "); } [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { var type = "Weather logs"; var result = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)], }) .ToArray(); _logger.LogInformation("Weather logs: Informantion obtained is {@Result}", result); type = "Nin logs"; var test = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), TemperatureC = Random.Shared.Next(-20, 55), Summary = nins[Random.Shared.Next(Summaries.Length)], }) .ToArray(); _logger.LogInformation("{@Type}: Informantion obtained is {@Test}", type, test[0]); return result; } } }
Program.cs代码
using Serilog; var builder = WebApplication.CreateBuilder(args); builder.Logging.ClearProviders(); builder.Host.UseSerilog((context, configuration) => configuration.ReadFrom.Configuration(context.Configuration)); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseSerilogRequestLogging(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
appsettings.json配置
{ "Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "File", "Args": { "path": "logs/weather-.json", "rollingInterval": "Day", "rollOnFileSizeLimit": true, "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" }, "Filter": [ { "Name": "ByIncludingOnly", "Args": { "expression": "@m like 'Weather logs%'" } } ] }, { "Name": "File", "Args": { "path": "logs/nin-.json", "rollingInterval": "Day", "rollOnFileSizeLimit": true, "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" } } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] }, "AllowedHosts": "*" }
当前重复日志示例
{"@t":"2024-04-01T20:59:11.4950381Z","@mt":"WeatherForecast controller called ","@tr":"4d934bc9bfd6378d3aa8837a233c28ea","@sp":"0b9630cf3e5ed876","SourceContext":"LoggerTest.Controllers.WeatherForecastController","ActionId":"4282424a-3da7-492f-8959-e11bf53f34aa","ActionName":"LoggerTest.Controllers.WeatherForecastController.Get (LoggerTest)","RequestId":"0HN2IHQ4JSE88:00000009","RequestPath":"/WeatherForecast","ConnectionId":"0HN2IHQ4JSE88"} {"@t":"2024-04-01T20:59:11.5670441Z","@mt":"{@Type}: Weather logs: Informantion obtained is {@Result}","@tr":"4d934bc9bfd6378d3aa8837a233c28ea","@sp":"0b9630cf3e5ed876","Type":"Weather logs","Result":[{"Date":"2024-04-02","TemperatureC":7,"TemperatureF":44,"Summary":"Hot","Type":null,"$type":"WeatherForecast"},{"Date":"2024-04-03","TemperatureC":8,"TemperatureF":46,"Summary":"Chilly","Type":null,"$type":"WeatherForecast"},{"Date":"2024-04-04","TemperatureC":25,"TemperatureF":76,"Summary":"Mild","Type":null,"$type":"WeatherForecast"},{"Date":"2024-04-05","TemperatureC":-16,"TemperatureF":4,"Summary":"Bracing","Type":null,"$type":"WeatherForecast"},{"Date":"2024-04-06","TemperatureC":37,"TemperatureF":98,"Summary":"Sweltering","Type":null,"$type":"WeatherForecast"}],"SourceContext":"LoggerTest.Controllers.WeatherForecastController","ActionId":"4282424a-3da7-492f-8959-e11bf53f34aa","ActionName":"LoggerTest.Controllers.WeatherForecastController.Get (LoggerTest)","RequestId":"0HN2IHQ4JSE88:00000009","RequestPath":"/WeatherForecast","ConnectionId":"0HN2IHQ4JSE88"} {"@t":"2024-04-01T20:59:11.5855717Z","@mt":"{@Type}: Informantion obtained is {@Test}","@tr":"4d934bc9bfd6378d3aa8837a233c28ea","@sp":"0b9630cf3e5ed876","Type":"Nin logs","Test":{"Date":"2024-04-02","TemperatureC":9,"TemperatureF":48,"Summary":"11","Type":null,"$type":"WeatherForecast"},"SourceContext":"LoggerTest.Controllers.WeatherForecastController","ActionId":"4282424a-3da7-492f-8959-e11bf53f34aa","ActionName":"LoggerTest.Controllers.WeatherForecastController.Get (LoggerTest)","RequestId":"0HN2IHQ4JSE88:00000009","RequestPath":"/WeatherForecast","ConnectionId":"0HN2IHQ4JSE88"} {"@t":"2024-04-01T20:59:11.6216513Z","@mt":"HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms","@r":["184.2060"],"@tr":"4d934bc9bfd6378d3aa8837a233c28ea","@sp":"0b9630cf3e5ed876","RequestMethod":"GET","RequestPath":"/WeatherForecast","StatusCode":200,"Elapsed":184.206,"SourceContext":"Serilog.AspNetCore.RequestLoggingMiddleware","RequestId":"0HN2IHQ4JSE88:00000009","ConnectionId":"0HN2IHQ4JSE88"}
问题原因
- Nin日志Sink无过滤规则:当前仅Weather日志Sink配置了
ByIncludingOnly过滤,但Nin日志Sink未设置任何过滤,导致所有日志都会写入该文件。 - 过滤规则不可靠:现有Weather日志过滤依赖
@m like 'Weather logs%'匹配消息文本,但部分Weather日志的模板包含动态参数,实际渲染后的消息可能不满足前缀匹配,导致过滤逻辑失效。
解决方案
1. 更新appsettings.json配置
给Nin日志Sink添加ByExcluding过滤,排除Type为Weather logs的日志;同时优化Weather日志的过滤规则,直接匹配日志的Type属性,避免依赖消息文本:
{ "Serilog": { "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Expressions" ], "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "File", "Args": { "path": "logs/weather-.json", "rollingInterval": "Day", "rollOnFileSizeLimit": true, "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" }, "Filter": [ { "Name": "ByIncludingOnly", "Args": { "expression": "Type = 'Weather logs'" } } ] }, { "Name": "File", "Args": { "path": "logs/nin-.json", "rollingInterval": "Day", "rollOnFileSizeLimit": true, "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" }, "Filter": [ { "Name": "ByExcluding", "Args": { "expression": "Type = 'Weather logs'" } } ] } ], "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ] }, "AllowedHosts": "*" }
2. 统一日志写入方式
确保所有需要分类的日志都明确传递Type属性,让过滤规则能准确匹配:
修改控制器中的日志代码:
// Weather日志写法,明确传递Type参数 _logger.LogInformation("{@Type}: Informantion obtained is {@Result}", "Weather logs", result); // Nin日志保持原有写法即可 _logger.LogInformation("{@Type}: Informantion obtained is {@Test}", "Nin logs", test[0]);
对于控制器初始化的日志,因为不需要归类到Weather,会自动写入Nin日志文件,无需修改。
3. 验证结果
修改后:
logs/weather-.json仅包含Type为Weather logs的日志logs/nin-.json包含所有非Weather logs的日志,包括控制器初始化日志、Nin类型日志、请求日志等
内容的提问来源于stack exchange,提问作者Andrew Efurhievwe
相关产品推荐
相关产品推荐

