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

如何基于LogEventLevel为Serilog实现条件式上下文增强

为Serilog实现按日志级别条件添加上下文属性的流畅API

需求背景

希望在类中集中配置Serilog的上下文增强逻辑,通过流畅API实现按日志级别条件动态添加不同属性——比如不同级别日志自动携带对应专属属性,而非手动维护多个Logger实例或在每个日志调用处做判断。

现有方案的不足

  • 手动编写GetLogger方法切换不同Logger的方式,需要在每个日志调用前指定级别,代码冗余且容易出错;
  • 官方的Enrich.AtLevel仅支持“>=指定级别”的判断,且需要重新创建Logger实例,无法满足更灵活的级别条件(如<=、==),也不符合集中配置的需求。

最优实现方案

通过自定义条件属性增强器和ILogger扩展方法,完全实现你期望的流畅API风格:

1. 实现条件属性增强器

创建一个实现ILogEventEnricher的类,负责在日志事件生成时判断级别并添加属性:

public class ConditionalPropertyEnricher : ILogEventEnricher
{
    private readonly Func<LogEventLevel, bool> _levelCondition;
    private readonly string _propertyName;
    private readonly object _propertyValue;

    public ConditionalPropertyEnricher(Func<LogEventLevel, bool> levelCondition, string propertyName, object propertyValue)
    {
        _levelCondition = levelCondition ?? throw new ArgumentNullException(nameof(levelCondition));
        _propertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
        _propertyValue = propertyValue;
    }

    public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
    {
        // 当日志级别满足条件时,添加属性
        if (_levelCondition(logEvent.Level))
        {
            var property = propertyFactory.CreateProperty(_propertyName, _propertyValue);
            logEvent.AddPropertyIfAbsent(property);
        }
    }
}

2. 扩展ILogger的流畅API

写一个静态扩展方法,让你可以直接在ILogger实例上调用ForConditionalContext:

public static class LoggerConditionalContextExtensions
{
    public static ILogger ForConditionalContext(this ILogger logger, Func<LogEventLevel, bool> levelCondition, string propertyName, object propertyValue)
    {
        return logger.ForContext(new ConditionalPropertyEnricher(levelCondition, propertyName, propertyValue));
    }
}

3. 按期望方式使用

现在你可以像最初设想的那样,在类中集中配置条件属性,调用时无需额外判断:

public class MyClass
{
    ILogger Log => Serilog.Log.Logger
        .ForConditionalContext(lvl => lvl <= LogEventLevel.Information, "prop 1", "仅添加到Information及以下级别")
        .ForConditionalContext(lvl => lvl <= LogEventLevel.Debug, "prop 2", "仅添加到Debug及以下级别")
        .ForConditionalContext(lvl => lvl == LogEventLevel.Verbose, "prop 3", "仅添加到Verbose级别");

    void MyMethod()
    {
        // 这条Verbose日志会包含prop1、prop2、prop3
        Log.ForContext("method-specific ctx", "value")
            .Verbose("这条日志会包含所有符合条件的属性");
        
        // 这条Information日志仅包含prop1
        Log.ForContext("method-specific ctx", "value")
            .Information("这条日志仅包含Information级别对应的属性");
    }
}

方案优势

  • 完全贴合流畅API需求:集中配置类级别的条件属性,调用时无需手动切换Logger;
  • 灵活的级别判断:支持任意自定义级别条件(<=、==、范围判断等),比官方Enrich.AtLevel更强大;
  • 轻量无侵入:无需创建新的Logger实例,仅通过添加增强器实现逻辑,与Serilog原有上下文机制完全兼容;
  • 代码更整洁:避免了冗余的switch判断和重复的Logger初始化逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 10:50:32