如何在不依赖Serilog的情况下为ILogger<T>结构化日志添加额外属性?
使用ILogger添加额外日志属性的方法
当然有办法,完全不用依赖Serilog,用.NET原生的ILogger
1. 用BeginScope给日志加全局上下文属性
这是最常用的原生方案,通过BeginScope创建一个日志作用域,作用域内的所有日志条目都会自动带上你指定的额外属性。
示例代码:
// 包裹需要添加额外属性的日志代码块 using (_logger.BeginScope(new Dictionary<string, object> { ["OrderOriginSystem"] = "WebPortal", ["Supervisor"] = "JohnDoe", ["StoreLocationCode"] = "NYC-001" })) { // 这条日志会自动包含上面的三个额外属性 _logger.LogInformation("Order {OrderNumber} was registered.", orderNumber); // 作用域内的其他日志也会带上这些属性 _logger.LogDebug("Order details processed for {OrderNumber}", orderNumber); }
作用域结束后,这些额外属性就不会再被后续日志继承了,非常适合处理一批相关操作的日志上下文。
2. 直接在Log方法中传入匿名类型携带额外属性
ILogger的Log系列方法有重载支持传入自定义状态对象,你可以把需要的所有属性(包括消息模板里用到的)打包成匿名对象,日志提供者会自动解析所有属性作为日志字段。
示例代码:
_logger.LogInformation( new EventId(), // 可以传自定义事件ID,不需要的话传空EventId即可 "Order {OrderNumber} was registered.", new { OrderNumber = orderNumber, OrderOriginSystem = "WebPortal", Supervisor = "JohnDoe", StoreLocationCode = "NYC-001" } );
这种方式适合单条日志需要额外属性的场景,不用创建作用域,直接一次性传入所有信息。
3. 封装自定义扩展方法简化调用
如果经常需要记录这类带固定额外属性的日志,可以封装一个扩展方法,避免重复写匿名对象或作用域代码。
示例代码:
public static class LoggerOrderExtensions { public static void LogOrderRegistered(this ILogger logger, string orderNumber, string originSystem, string supervisor, string storeCode) { var logState = new { OrderNumber = orderNumber, OrderOriginSystem = originSystem, Supervisor = supervisor, StoreLocationCode = storeCode }; logger.LogInformation("Order {OrderNumber} was registered.", logState); } }
调用的时候就非常简洁:
_logger.LogOrderRegistered(orderNumber, "WebPortal", "JohnDoe", "NYC-001");
以上三种方案都是基于.NET原生的ILogger<T>抽象实现的,完全不需要依赖Serilog或其他第三方日志库,只要你的日志提供者(比如控制台日志、NLog等)遵循ILogger规范,就能正确捕获并输出这些额外属性。
内容的提问来源于stack exchange,提问作者Sigurd Garshol
相关产品推荐
相关产品推荐

