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

.NET 6 WebApi中如何运行时动态增减Serilog日志级别覆盖?

在.NET 6 WebApi中用Serilog实现运行时动态调整日志级别覆盖

可行,以下是具体实现指导:

核心思路

Serilog本身无内置动态配置能力,但可通过自定义LoggingLevelSwitch结合可修改的级别规则集合,配合Serilog过滤器实现运行时添加/移除命名空间的日志级别覆盖。

具体实现步骤

1. 准备依赖与基础配置

确保项目安装必要的Serilog包:

Install-Package Serilog.AspNetCore
Install-Package Serilog.Settings.Configuration
Install-Package Serilog.Expressions

在Program.cs中初始化Serilog时,引入可动态修改的级别开关集合:

// 线程安全集合,存储命名空间与对应级别开关
var dynamicLevelSwitches = new ConcurrentDictionary<string, LoggingLevelSwitch>();

var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

// 初始化Serilog,添加动态过滤规则
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(configuration)
    .Filter.ByIncludingOnly(logEvent =>
    {
        var sourceContext = logEvent.Properties.TryGetValue("SourceContext", out var value) 
            ? value.ToString().Trim('"') 
            : string.Empty;
        
        // 匹配动态规则中的命名空间,应用对应级别
        foreach (var (ns, switcher) in dynamicLevelSwitches)
        {
            if (sourceContext.StartsWith(ns))
            {
                return logEvent.Level >= switcher.MinimumLevel;
            }
        }
        // 无匹配规则时使用默认配置
        return true;
    })
    .CreateLogger();

var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog();

2. 实现动态调整的API接口

添加控制器提供外部调用入口,用于管理日志级别规则:

[ApiController]
[Route("api/logging")]
public class LoggingController : ControllerBase
{
    private readonly ConcurrentDictionary<string, LoggingLevelSwitch> _dynamicLevelSwitches;
    private readonly ILogger<LoggingController> _logger;

    public LoggingController(ConcurrentDictionary<string, LoggingLevelSwitch> dynamicLevelSwitches, ILogger<LoggingController> logger)
    {
        _dynamicLevelSwitches = dynamicLevelSwitches;
        _logger = logger;
    }

    // 添加/更新命名空间日志级别
    [HttpPost("set-level")]
    public IActionResult SetNamespaceLevel([FromBody] LevelConfig config)
    {
        if (string.IsNullOrWhiteSpace(config.Namespace))
            return BadRequest("命名空间不能为空");
        
        if (!Enum.TryParse<LogEventLevel>(config.Level, true, out var targetLevel))
            return BadRequest("无效的日志级别");

        _dynamicLevelSwitches.AddOrUpdate(
            config.Namespace,
            _ => new LoggingLevelSwitch(targetLevel),
            (_, switcher) => { switcher.MinimumLevel = targetLevel; return switcher; }
        );

        _logger.Information("命名空间 {Namespace} 日志级别已设为 {Level}", config.Namespace, targetLevel);
        return Ok();
    }

    // 移除命名空间的级别覆盖
    [HttpDelete("remove-level/{namespace}")]
    public IActionResult RemoveNamespaceLevel(string @namespace)
    {
        if (_dynamicLevelSwitches.TryRemove(@namespace, out _))
        {
            _logger.Information("已移除命名空间 {Namespace} 的日志级别覆盖", @namespace);
            return Ok();
        }
        return NotFound("未找到对应命名空间的级别规则");
    }

    // 查询当前所有动态级别规则
    [HttpGet("current-levels")]
    public IActionResult GetCurrentLevels()
    {
        var result = _dynamicLevelSwitches.ToDictionary(
            kv => kv.Key, 
            kv => kv.Value.MinimumLevel.ToString()
        );
        return Ok(result);
    }
}

// 请求模型
public class LevelConfig
{
    public string Namespace { get; set; }
    public string Level { get; set; } // 可选值:Debug/Information/Warning/Error/Fatal
}

3. 可选优化:规则持久化

若需重启后保留动态规则,可将配置存储到数据库或分布式配置中心,在项目启动时加载:

// Program.cs中启动时加载持久化规则
var persistedRules = /* 从数据库/配置中心读取规则 */;
foreach (var rule in persistedRules)
{
    if (Enum.TryParse<LogEventLevel>(rule.Level, true, out var level))
    {
        dynamicLevelSwitches.TryAdd(rule.Namespace, new LoggingLevelSwitch(level));
    }
}

4. 注意事项

  • 权限控制:动态调整API必须添加身份验证(如JWT),避免未授权访问
  • 性能:若规则数量较多,可自定义ILogEventFilter实现更高效的匹配逻辑
  • 线程安全:必须使用线程安全集合(如ConcurrentDictionary)维护规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:40:24