无法读取含点的appsettings.json键,NLog配置遇异常
NLog读取appsettings.json中含点的日志级别配置异常
问题背景
在NLog.Config中使用${configsetting}布局渲染器读取appsettings.json的日志级别配置时,普通名称(如Microsoft)能正常读取,但名称包含点的配置项(如Microsoft.Hosting.Lifetime)无法正确读取值。
环境配置示例
appsettings.json
"Logging": { "LogLevel": { "Default": "Error", "Microsoft": "Information", "Microsoft.Hosting.Lifetime": "Error" } }
正常工作的NLog规则(读取普通名称)
<logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft}" writeTo="logfile,Loggly" />
无法工作的NLog规则(读取含点的名称)
<logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft.Hosting.Lifetime}" writeTo="logfile,Loggly" />
已尝试的无效方法
- 使用单引号包裹:
<logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel'.Microsoft.Hosting.Lifetime'}" writeTo="logfile,Loggly" /> <logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.'Microsoft.Hosting.Lifetime'}" writeTo="logfile,Loggly" /> - 使用反斜杠转义点:
<logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft\.Hosting\.Lifetime}" writeTo="logfile,Loggly" /> - 使用斜杠替代点:
<logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft/.Hosting/.Lifetime}" writeTo="logfile,Loggly" /> - 使用方括号包裹:
<logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel'.[Microsoft.Hosting.Lifetime]'}" writeTo="logfile,Loggly" />
编辑1:部分解决但规则不符合预期
尝试转义点(Microsoft\\.Hosting\\.Lifetime)后,配置能读取但日志规则行为不符合预期:
当前NLog.Config配置
<logger name="Microsoft.Hosting.Lifetime*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft\\.Hosting\\.Lifetime}" writeTo="logfile,Loggly" /> <logger name="Microsoft.Hosting.Lifetime*" maxlevel="${configsetting:item=Logging.LogLevel.Microsoft\\.Hosting\\.Lifetime}" writeTo="void" final="true" /> <logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft}" writeTo="logfile,Loggly" /> <logger name="Microsoft*" maxlevel="${configsetting:item=Logging.LogLevel.Microsoft}" writeTo="void" final="true"/> <logger name="*" minlevel="${configsetting:item=Logging.LogLevel.Default}" writeTo="logfile,Loggly" />
当前appsettings.json配置
"Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Error", "Microsoft.Hosting.Lifetime": "Information" } }
预期与实际差异
- 预期:
Microsoft.Hosting.Lifetime的Information及以下级别日志被导向void目标 - 实际:仅
Error及以下级别被导向void,推测读取的是Microsoft的日志级别值
NLog内部日志片段
2022-08-25 13:09:30.7512 Warn Logger: Microsoft.Hosting.Lifetime configured with duplicate output to target: FileTarget(Name=logfile). LoggingRule with NamePattern='Microsoft*' and Level=Error has been skipped. 2022-08-25 13:09:30.7512 Warn Logger: Microsoft.Hosting.Lifetime configured with duplicate output to target: FileTarget(Name=logfile). LoggingRule with NamePattern='*' and Level=Fatal has been skipped. 2022-08-25 13:09:30.7512 Debug Targets configured when LogLevel >= Trace for Logger: Microsoft.Hosting.Lifetime 2022-08-25 13:09:30.7512 Debug Logger Microsoft.Hosting.Lifetime [Trace] => void 2022-08-25 13:09:30.7678 Debug Logger Microsoft.Hosting.Lifetime [Debug] => void 2022-08-25 13:09:30.7678 Debug Logger Microsoft.Hosting.Lifetime [Info] => logfile Loggly void 2022-08-25 13:09:30.7678 Debug Logger Microsoft.Hosting.Lifetime [Warn] => logfile Loggly void 2022-08-25 13:09:30.7678 Debug Logger Microsoft.Hosting.Lifetime [Error] => logfile Loggly void 2022-08-25 13:09:30.7678 Debug Logger Microsoft.Hosting.Lifetime [Fatal] => logfile Loggly
解决方案
核心问题:配置路径解析与规则优先级
正确读取含点的配置项:
NLog的configsetting渲染器在处理带点的键名时,需要明确告知渲染器这是单个键而非嵌套路径。推荐两种写法:- 用单引号包裹完整路径,同时转义键内的点:
${configsetting:item='Logging.LogLevel.Microsoft\.Hosting\.Lifetime'} - 使用
jsonpath参数直接指定JSON路径,逻辑更清晰:${configsetting:jsonpath=Logging.LogLevel.'Microsoft.Hosting.Lifetime'}
- 用单引号包裹完整路径,同时转义键内的点:
修正日志规则逻辑:
原规则的问题在于minlevel和maxlevel的组合逻辑,以及规则执行顺序。要实现“指定级别及以下导向void”,需调整规则顺序和级别匹配方式:<!-- 先处理Microsoft.Hosting.Lifetime:将Information及以下级别导向void,终止后续规则 --> <logger name="Microsoft.Hosting.Lifetime*" maxlevel="${configsetting:jsonpath=Logging.LogLevel.'Microsoft.Hosting.Lifetime'}" writeTo="void" final="true" /> <!-- 允许Microsoft.Hosting.Lifetime高于目标级别的日志输出 --> <logger name="Microsoft.Hosting.Lifetime*" minlevel="${configsetting:jsonpath=Logging.LogLevel.'Microsoft.Hosting.Lifetime'}:above" writeTo="logfile,Loggly" /> <!-- 处理其他Microsoft前缀日志 --> <logger name="Microsoft*" maxlevel="${configsetting:item=Logging.LogLevel.Microsoft}" writeTo="void" final="true" /> <logger name="Microsoft*" minlevel="${configsetting:item=Logging.LogLevel.Microsoft}:above" writeTo="logfile,Loggly" /> <!-- 全局规则 --> <logger name="*" minlevel="${configsetting:item=Logging.LogLevel.Default}" writeTo="logfile,Loggly" />解释:
:above后缀表示“高于指定级别”,例如目标级别是Information时,minlevel=Information:above会匹配Warn及以上级别- 先执行
maxlevel的void规则并标记final,确保符合条件的日志不会进入后续规则
验证配置读取:
开启NLog内部日志确认配置读取状态:<internalLogFile="nlog-internal.log" internalLogLevel="Debug" />查看日志中是否有类似
ConfigSettingParser Found value 'Information' for path 'Logging.LogLevel.Microsoft.Hosting.Lifetime'的条目,确认配置读取正确。
内容的提问来源于stack exchange,提问作者Bala teja
相关产品推荐
相关产品推荐

