如何在使用ILogger.BeginScope时让NLog将数据格式化为JSON?
解决ILogger.BeginScope中NLog无法将对象序列化为JSON的问题
我来帮你搞定这个头疼的问题——其实核心是NLog对BeginScope里的对象处理逻辑和日志消息模板的@语法完全是两回事,咱们一步步捋清楚:
问题根源
你之前试着在BeginScope的键名里加@或者{@},但NLog根本不买账——因为@是日志消息模板(比如LogInfo("xxx {@Prop}", value))里的专属语法,用来告诉框架序列化参数对象,但这套逻辑并不适用于BeginScope的字典键名。默认情况下,NLog对BeginScope传递的对象只会调用ToString(),自然就只能看到类名或者默认字符串了。
解决方案
要让BeginScope里的对象变成可检索的结构化JSON,需要两步:调整NLog配置,然后用正确的代码写法。
第一步:修改NLog配置,开启Scope对象的序列化
打开你的nlog.config文件,针对Seq目标做以下配置(确保你用的是最新版的NLog和NLog.Extensions.Logging包):
方式1:用JsonLayout输出完整结构化日志(推荐)
这种方式会把所有日志内容(包括Scope属性)都序列化为JSON,Seq能完美识别:
<target name="seq" xsi:type="Seq" serverUrl="http://你的Seq地址"> <layout xsi:type="JsonLayout"> <attribute name="message" layout="${message}" /> <attribute name="level" layout="${level}" /> <attribute name="timestamp" layout="${date:format=o}" /> <!-- 自动包含所有Scope/MDLC属性,并序列化为JSON --> <attribute name="properties" xsi:type="JsonLayout" includeAllProperties="true" /> </layout> </target>
方式2:单独指定某个Scope属性的序列化
如果你只需要处理CacheValue这一个属性,可以在普通布局里单独配置:
<target name="seq" xsi:type="Seq" serverUrl="http://你的Seq地址"> <layout> ${message} <!-- 把CacheValue序列化为JSON输出 --> ${mdlc:item=CacheValue:format=json} </layout> </target>
第二步:正确使用BeginScope
现在不需要在键名里加任何特殊符号,直接用普通键名或者匿名对象就行:
写法1:字典方式
using (_logger.BeginScope(new Dictionary<string, object> { ["CacheValue"] = value })) { _logger.LogInformation("howdy"); }
写法2:匿名对象(更简洁)
using (_logger.BeginScope(new { CacheValue = value })) { _logger.LogInformation("howdy"); }
验证效果
配置完成后再跑代码,去Seq里看日志:
CacheValue不再是类名字符串,而是完整的JSON对象- 你可以直接用
CacheValue.Success = true或者CacheValue.TraceId = 'xxx'这样的条件检索日志,完全符合你的需求——JSON数据关联到日志但不显示在消息里。
内容的提问来源于stack exchange,提问作者TugboatCaptain
相关产品推荐
相关产品推荐

