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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:17:04