如何使用NLog JsonLayout截断异常Data属性输出且保持JSON格式合法
方案1:优先过滤异常中的大体积属性(推荐)
直接从根源避免大内容生成,完全不会破坏JSON结构,性能最优。NLog的${exception:format=@}原生支持排除指定属性/指定类型的字段,你可以直接把字节数组类型或者特定的大字段排除:
<!-- 排除指定名称的属性 --> <attribute name="Exception" encode="false" layout="${exception:format=@:excludeProperties=Data,FileData}" />
如果要全局排除所有字节数组类型属性,不需要指定属性名,可以用NLog 4.7+版本支持的excludeType参数,还可以搭配maxSerializationDepth限制序列化深度,避免嵌套过深导致内容过大:
<attribute name="Exception" encode="false" layout="${exception:format=@:excludeType=System.Byte[]:maxSerializationDepth=5}" />
方案2:自定义渲染器实现结构化截断
如果你确实需要保留部分异常的结构化内容,必须做截断,就不能用自带的truncate参数直接切割字符串,需要自定义NLog布局渲染器,先解析序列化后的异常JSON,递归裁剪超长的数组、字符串之后再重新序列化,保证输出一定是合法JSON。
示例自定义渲染器代码:
[LayoutRenderer("trimmed-exception")] public class TrimmedExceptionLayoutRenderer : ExceptionLayoutRenderer { public int MaxLength { get; set; } = 500; protected override void Append(StringBuilder builder, LogEventInfo logEvent) { var originalJson = base.GetFormattedMessage(logEvent); if (string.IsNullOrEmpty(originalJson) || originalJson.Length <= MaxLength) { builder.Append(originalJson); return; } try { // 解析JSON后递归裁剪,比如超长数组只保留前10个元素,超长字符串截断后加省略标记 var jsonDoc = JsonDocument.Parse(originalJson); var trimmedNode = TrimJsonNode(jsonDoc.RootElement, MaxLength); builder.Append(JsonSerializer.Serialize(trimmedNode)); } catch { // 解析失败兜底为转义后的纯字符串,保证外层JSON合法 builder.Append(JsonEncodedText.Encode(originalJson.Substring(0, MaxLength) + "...")); } } // TrimJsonNode实现逻辑:递归遍历所有JSON节点,数组、字符串超过长度阈值就截断,可按需调整规则 private JsonElement TrimJsonNode(JsonElement node, int maxLength) { // 省略具体裁剪逻辑 } }
配置时直接使用自定义渲染器即可:
<attribute name="Exception" encode="false" layout="${trimmed-exception:maxLength=500}" />
方案3:轻量场景快速补救
如果不需要异常内容保持结构化,只想最低成本保证外层JSON合法,可以把encode参数改为true,NLog会自动把异常内容转义为合法JSON字符串,此时截断不会破坏整体结构:
<attribute name="Exception" encode="true" layout="${exception:format=@:truncate=500:truncateEllipsis=...}" />
该方案的副作用是Exception字段会变成纯字符串类型,无法直接作为嵌套JSON对象做结构化查询,适合不需要分析异常内部结构的场景。
内容的提问来源于stack exchange,提问作者gunnarst
相关产品推荐
相关产品推荐

