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
相关产品推荐
相关产品推荐

