.NET Core 8 Worker Service中Serilog配置及多日志输出问题
.NET Core 8 Worker Service 多日志提供者共存解决方案
一、完整 appsettings.json 配置
{ "Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "File", "Args": { "path": "./logs/log-.txt", "rollingInterval": "Day", "restrictedToMinimumLevel": "Information" } } ] }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "System": "Warning" }, "ConnectionStrings": { "SqlServerLog": "Server=.;Database=LogDb;Trusted_Connection=True;TrustServerCertificate=True;" } } }
二、Program.cs 完整注册代码
using Microsoft.Extensions.Logging; using Serilog; var builder = Host.CreateApplicationBuilder(args); // 1. 配置Serilog并整合到宿主日志体系 builder.Host.UseSerilog((context, config) => { config.ReadFrom.Configuration(context.Configuration); }); // 2. 注册自定义SQL Server日志提供者,并添加级别过滤规则 builder.Logging.AddProvider(new CustomSqlServerLoggerProvider( builder.Configuration.GetConnectionString("SqlServerLog"))) .AddFilter<CustomSqlServerLoggerProvider>(level => level >= LogLevel.Error); builder.Services.AddHostedService<Worker>(); var host = builder.Build(); host.Run(); // ------------------------------ // 自定义SQL Server日志提供者示例实现 // ------------------------------ public class CustomSqlServerLoggerProvider : ILoggerProvider { private readonly string _connectionString; public CustomSqlServerLoggerProvider(string connectionString) { _connectionString = connectionString; } public ILogger CreateLogger(string categoryName) { return new CustomSqlServerLogger(_connectionString, categoryName); } public void Dispose() { } } public class CustomSqlServerLogger : ILogger { private readonly string _connectionString; private readonly string _categoryName; public CustomSqlServerLogger(string connectionString, string categoryName) { _connectionString = connectionString; _categoryName = categoryName; } public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null; public bool IsEnabled(LogLevel logLevel) { return logLevel >= LogLevel.Error; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { if (!IsEnabled(logLevel)) return; // 替换为实际的SQL Server写入逻辑 // 示例:使用SqlConnection插入日志到数据库表 Console.WriteLine($"[SQL Server] [{logLevel}] {_categoryName}: {formatter(state, exception)}"); } } // Worker服务示例 public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; public Worker(ILogger<Worker> logger) { _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation("这条Info日志将由Serilog写入文件"); _logger.LogWarning("这条Warning日志将由Serilog写入文件"); _logger.LogError("这条Error日志将由自定义提供者写入数据库"); _logger.LogCritical("这条Critical日志将由自定义提供者写入数据库"); await Task.Delay(5000, stoppingToken); } } }
三、共存问题解决核心
- 精准级别过滤:通过
AddFilter<CustomSqlServerLoggerProvider>为自定义提供者指定仅处理Error及以上级别,Serilog则通过自身配置的restrictedToMinimumLevel限定为Information及以上,实现日志流的分流。 - Serilog正确整合:使用
builder.Host.UseSerilog()将Serilog接入宿主原生日志系统,而非独立运行,确保和自定义提供者共享同一日志管道。 - 保留默认提供者集合:不要调用
ClearProviders(),否则会移除所有已注册的日志提供者,导致仅能启用其一。
内容的提问来源于stack exchange,提问作者user3497702
相关产品推荐
相关产品推荐

