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

log4net自定义布局序列化日志为JSON时出现畸形JSON及堆栈跟踪问题求助

解决log4net自定义JSON布局记录异常时的畸形JSON问题

我之前刚好碰到过一模一样的坑——用log4net自定义布局做日志JSON序列化,结果一记录异常,输出的JSON就变畸形,末尾多出来一堆不属于JSON结构的堆栈跟踪信息。而且我也确认过直接用Json.NET序列化Exception完全正常,所以问题肯定出在log4net的自定义实现上。

问题根源

大概率是你的自定义布局没有完全接管log4net的异常输出逻辑。log4net的默认布局处理异常时,会自动追加堆栈跟踪到日志末尾;如果你的自定义布局只序列化了日志的常规字段,却没覆盖异常的处理逻辑,就会导致序列化后的JSON后面被额外加上默认输出的堆栈,直接破坏了JSON格式。

修复后的实现代码

我调整后的自定义布局是这样的,核心是主动处理LoggingEvent里的ExceptionObject,用Json.NET单独序列化后嵌入JSON结构,完全屏蔽log4net的默认异常输出:

public class JsonLayout : LayoutBase
{
    public override void Format(TextWriter writer, LoggingEvent loggingEvent)
    {
        // 构建要序列化的日志对象
        var logPayload = new
        {
            UserSessionId = loggingEvent.Properties["UserSessionId"],
            ProcessSessionId = loggingEvent.Properties["ProcessSessionId"],
            Message = loggingEvent.RenderedMessage,
            Timestamp = loggingEvent.TimeStamp,
            // 主动处理异常,避免log4net默认输出
            Exception = loggingEvent.ExceptionObject != null 
                ? JsonConvert.SerializeObject(loggingEvent.ExceptionObject, new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                })
                : null
        };

        // 序列化并写入
        writer.Write(JsonConvert.SerializeObject(logPayload));
        writer.WriteLine(); // 每条日志单独一行,方便后续解析
    }
}

关键注意点

  • 一定要从loggingEvent.ExceptionObject获取异常对象,不要依赖log4net的默认异常渲染逻辑
  • 如果异常对象有循环引用,记得在Json.NET的序列化设置里加上ReferenceLoopHandling.Ignore,避免序列化失败
  • 确保你的log4net Appender配置里只使用这个自定义布局,不要额外配置和异常输出相关的参数(比如不要加%exception这样的模式)

这样处理后,输出的JSON就是完整合法的格式,不会再出现末尾额外的堆栈信息了。

内容的提问来源于stack exchange,提问作者Eric Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:42:53