如何用类Serilog简洁语法实现.NET Core MEL日志事件enrichment?
简化MEL日志上下文属性的几种方案
针对你觉得MEL添加日志上下文属性写法繁琐的问题,这里有几个实用的简化方案:
1. 用匿名类型替代Dictionary
MEL的BeginScope原生支持匿名类型,无需手动创建Dictionary<string, object?>,写法大幅简化:
using (_logger.BeginScope(new { Foo = "abc", Bar = 123, Baz = true })) { _logger.LogInformation("Process returned {Result}", 42); }
这个方案无需额外代码,利用MEL本身特性,是最轻量化的实现方式。
2. 封装扩展方法模拟Serilog链式风格
如果更偏好Serilog那种链式ForContext的写法,可以给ILogger编写扩展方法,实现近似的语法:
public static class LoggerExtensions { // 链式添加上下文,自动处理Scope释放 public static ILogger WithContext(this ILogger logger, string key, object? value) { var scope = logger.BeginScope(new Dictionary<string, object?> { { key, value } }); return new ScopedLogger(logger, scope); } // 内部包装类,确保日志完成后释放Scope private class ScopedLogger : ILogger { private readonly ILogger _innerLogger; private readonly IDisposable? _scope; public ScopedLogger(ILogger innerLogger, IDisposable? scope) { _innerLogger = innerLogger; _scope = scope; } public IDisposable? BeginScope<TState>(TState state) where TState : notnull => _innerLogger.BeginScope(state); public bool IsEnabled(LogLevel logLevel) => _innerLogger.IsEnabled(logLevel); public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { try { _innerLogger.Log(logLevel, eventId, state, exception, formatter); } finally { _scope?.Dispose(); } } } }
调用时就和Serilog的写法几乎一致:
_logger .WithContext("Foo", "abc") .WithContext("Bar", 123) .WithContext("Baz", true) .LogInformation("Process returned {Result}", 42);
3. 利用Serilog的LogContext(需启用)
既然你底层用Serilog作为MEL的提供者,可以直接用Serilog的LogContext添加属性,前提是在Serilog配置中启用FromLogContext:
// Serilog配置时添加 Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() // 启用LogContext .WriteTo.Console() .CreateLogger();
之后就能链式推送属性,写法简洁且贴近你熟悉的Serilog风格:
using (LogContext.PushProperty("Foo", "abc") .PushProperty("Bar", 123) .PushProperty("Baz", true)) { _logger.LogInformation("Process returned {Result}", 42); }
内容的提问来源于stack exchange,提问作者lonix
相关产品推荐
相关产品推荐

