NLog中internalLogFile路径如何使用GDC自定义变量
问题说明
是否可以在nlog.config文件的internalLogFile属性中添加自定义变量?例如在internalLogFile="c:\logs\${gdc:ProjectName}\internal-nlog.txt"配置中使用ProjectName变量。
尝试的配置如下:
nlog.config配置:
<nlog internalLogFile="c:\logs\${gdc:ProjectName}\internal-nlog.txt"> ... </nlog>
对应配置代码:
private static void ConfigureLogging(IServiceCollection services) { GlobalDiagnosticsContext.Set("ProjectName", "some-project-name"); LogManager.LoadConfiguration("nlog.config"); services.AddLogging(loggingBuilder => { loggingBuilder.AddConfiguration(Config.GetSection("Logging")); loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug); loggingBuilder.AddNLog(); }); }
执行LoadConfiguration时抛出IOException,提示目录名无效,路径为未解析的c:\logs\${gdc:ServiceRunnerFolder}。调试NLog源码确认,框架设置internalLogFile文件名前,仅会调用ExpandFilePathVariables方法展开部分已知环境变量,不会解析GDC变量,需求是不创建环境变量实现internalLogFile的自定义变量配置。
解决方案
不需要创建系统环境变量,有两种可落地的方案,核心注意点是:NLog内部日志路径的解析时机早于普通日志规则加载,且GDC这类和日志事件上下文绑定的渲染器无法用于内部日志路径(内部日志是NLog框架自身输出的调试信息,无绑定的日志事件对象)。
方案1:代码动态赋值(全版本兼容,最稳定)
这是兼容性最好的方案,不受NLog版本限制,不会出现解析时机问题。
- 先删除nlog.config根节点上的
internalLogFile属性配置,避免加载配置时提前解析报错 - 调整代码执行顺序,加载完配置后手动给内部日志路径赋值,提前创建日志目录:
private static void ConfigureLogging(IServiceCollection services) { // 提前设置全局变量 GlobalDiagnosticsContext.Set("ProjectName", "some-project-name"); // 加载NLog配置 LogManager.LoadConfiguration("nlog.config"); // 手动拼接内部日志路径,赋值给NLog内部日志组件 var projectName = GlobalDiagnosticsContext.Get("ProjectName")?.ToString() ?? "default-project"; var internalLogDir = System.IO.Path.Combine("c:\\logs", projectName); // 提前创建目录避免IO报错 System.IO.Directory.CreateDirectory(internalLogDir); InternalLogger.LogFile = System.IO.Path.Combine(internalLogDir, "internal-nlog.txt"); // 按需配置内部日志参数 InternalLogger.LogLevel = LogLevel.Debug; InternalLogger.IncludeTimestamp = true; services.AddLogging(loggingBuilder => { loggingBuilder.AddConfiguration(Config.GetSection("Logging")); loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug); loggingBuilder.AddNLog(); }); }
方案2:开启配置文件变量展开(适用于NLog 4.7+版本)
NLog 4.7及以上版本新增了内部日志路径的变量展开支持,注意不要用GDC变量,改用NLog全局配置变量${var:xxx}:
- 修改nlog.config根节点配置,打开变量展开开关:
<nlog internalLogFile="c:\logs\${var:ProjectName}\internal-nlog.txt" internalLogFileExpandVariables="true" internalLogLevel="Debug"> <!-- 其余原有配置保持不变 --> </nlog>
- 调整代码,在加载配置前设置NLog全局配置变量:
private static void ConfigureLogging(IServiceCollection services) { // 初始化NLog配置,提前设置全局var变量 LogManager.Configuration ??= new NLog.Config.LoggingConfiguration(); LogManager.Configuration.Variables["ProjectName"] = "some-project-name"; // 再加载配置文件 LogManager.LoadConfiguration("nlog.config"); services.AddLogging(loggingBuilder => { loggingBuilder.AddConfiguration(Config.GetSection("Logging")); loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Debug); loggingBuilder.AddNLog(); }); }
注意事项
- 不要在internalLogFile中使用GDC、MDLC、MDC这类依赖日志事件上下文的渲染器,内部日志无对应事件上下文,这类渲染器永远取不到值
- 无论用哪种方案,都建议提前创建日志对应目录,避免因为目录不存在导致内部日志写入失败
- 如果项目使用的NLog版本低于4.7,直接选方案1即可,不需要升级版本
内容的提问来源于stack exchange,提问作者vgru
相关产品推荐
相关产品推荐

