You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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);
        }
    }
}

三、共存问题解决核心

  1. 精准级别过滤:通过AddFilter<CustomSqlServerLoggerProvider>为自定义提供者指定仅处理Error及以上级别,Serilog则通过自身配置的restrictedToMinimumLevel限定为Information及以上,实现日志流的分流。
  2. Serilog正确整合:使用builder.Host.UseSerilog()将Serilog接入宿主原生日志系统,而非独立运行,确保和自定义提供者共享同一日志管道。
  3. 保留默认提供者集合:不要调用ClearProviders(),否则会移除所有已注册的日志提供者,导致仅能启用其一。

内容的提问来源于stack exchange,提问作者user3497702

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:07:26