ASP.NET Core中用LoggerMessage实现Serilog解构Exception的方法
我来帮你解决这个LoggerMessage结合Serilog解构Exception的问题——其实核心是要理解LoggerMessage的参数设计和Serilog的结构化日志特性怎么配合,下面分步骤给你讲清楚:
1. 先明确LoggerMessage的参数逻辑
LoggerMessage里的Exception是一个特殊的固定参数(最后一个位置),默认情况下Serilog会自动处理它,但如果你想把它像普通对象一样通过@解构,就得把它作为泛型参数显式加入定义,同时在消息模板里声明。
2. 分别定义不同日志级别的日志操作
你需要区分信息日志和错误日志的级别,所以要分别创建对应的LoggerMessage委托:
信息日志(无Exception)
// 定义信息级别的日志委托,用{@MyObject}让Serilog解构对象 private static readonly Action<ILogger, MyObject, Exception> _logMyObjectInfo = LoggerMessage.Define<MyObject>( LogLevel.Information, new EventId(1, nameof(LogMyObjectInfo)), "Some information about {@MyObject}"); // 扩展方法供外部调用 public static void LogMyObjectInfo(this ILogger logger, MyObject myObject) { // 最后一个参数传null,因为信息日志不需要Exception _logMyObjectInfo(logger, myObject, null); }
错误/警告日志(带Exception解构)
如果你希望Exception也被序列化为JSON对象,有两种方式可选:
方式一:把Exception作为普通参数解构(显式在模板中声明)
这种方式和你直接用logger.LogWarning的写法逻辑一致,把Exception作为泛型参数加入,用{@Exception}触发解构:
// 定义警告级别的日志委托,同时支持MyObject和Exception的解构 private static readonly Action<ILogger, MyObject, Exception, Exception> _logMyObjectError = LoggerMessage.Define<MyObject, Exception>( LogLevel.Warning, new EventId(2, nameof(LogMyObjectError)), "Some error with {@MyObject} {@Exception}"); // 扩展方法 public static void LogMyObjectError(this ILogger logger, MyObject myObject, Exception ex) { // 最后一个参数传null,因为我们已经把Exception作为泛型参数传入并解构了 _logMyObjectError(logger, myObject, ex, null); }
方式二:利用Serilog原生的Exception处理(更规范)
其实Serilog默认会把LoggerMessage最后一个参数传入的Exception序列化为结构化JSON对象,不需要在消息模板里显式声明,这种方式更符合LoggerMessage的设计规范:
// 定义警告级别的日志委托,只声明MyObject的解构 private static readonly Action<ILogger, MyObject, Exception> _logMyObjectError = LoggerMessage.Define<MyObject>( LogLevel.Warning, new EventId(2, nameof(LogMyObjectError)), "Some error with {@MyObject}"); // 扩展方法 public static void LogMyObjectError(this ILogger logger, MyObject myObject, Exception ex) { // 直接把ex传入最后一个Exception参数位置,Serilog会自动结构化它 _logMyObjectError(logger, myObject, ex); }
这种方式下,输出的JSON日志里会自动包含一个Exception字段,里面是结构化的异常信息(包含Message、StackTrace、InnerException等),不需要额外处理。
3. 确保Serilog配置正确
如果用方式二时Exception还是字符串形式,检查你的Serilog配置是否启用了结构化JSON输出,比如:
Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .WriteTo.Console(new JsonFormatter()) // 输出到控制台的JSON格式 .WriteTo.File(new JsonFormatter(), "logs/log-.json", rollingInterval: RollingInterval.Day) // 输出到文件 .CreateLogger();
这样配置后,Serilog会自动把Exception序列化为JSON对象,而不是字符串。
关键总结
- 用
{@Object}语法在消息模板中触发Serilog的对象解构,不管是普通业务对象还是Exception。 - 不同日志级别分别定义对应的LoggerMessage委托,满足你区分日志级别的需求。
- 优先选择方式二的原生Exception处理,既符合LoggerMessage的设计,又能获得结构化的异常日志。
内容的提问来源于stack exchange,提问作者Joshit
相关产品推荐
相关产品推荐

