Search code examples
windowsnlogtaskscheduler

NLog environment layout renderer doesn't work when run as a scheduled task


I'm using NLog 4.4.12 with .NET 4.6.2 on Windows Server 2012.

I've configured my app.config with the nlog section as follows:

  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <include file="conf/nlog.${environment:MY_ENV}.config"/>
  </nlog>

The idea here is that it will bring in an environment specific configuration for setting up NLog.

I setup a System Environment Variable (not user) called MY_ENV, and set its value to production.

If I run the program as the currently logged in user, the proper config file is found, and logs are written as expected.

However, if I setup a scheduled task, through Windows Task Scheduler, to run the program with the same user credentials just used, the Environment Variable seems not to be found?

I have configured the scheduled task to run whether the user is logged on or not, and I have enabled Run with highest privileges.

When I enable the internal diagnostics of NLog, I see the following in the diagnostic log:

2017-10-19 19:27:42.1744 Error Error when including 'conf/nlog..config'. Exception: System.IO.FileNotFoundException: Included file not found: E:\Utilities\MyApp\conf/nlog..config
   at NLog.Config.XmlLoggingConfiguration.ParseIncludeElement(NLogXmlElement includeElement, String baseDirectory, Boolean autoReloadDefault)
2017-10-19 19:27:42.1744 Error Parsing configuration from E:\Utilities\MyApp\MyApp.exe.Config failed. Exception: NLog.NLogConfigurationException: Exception when parsing E:\Utilities\MyApp\MyApp.exe.Config.  ---> NLog.NLogConfigurationException: Error when including: conf/nlog..config ---> System.IO.FileNotFoundException: Included file not found: E:\Utilities\MyApp\conf/nlog..config
   at NLog.Config.XmlLoggingConfiguration.ParseIncludeElement(NLogXmlElement includeElement, String baseDirectory, Boolean autoReloadDefault)
   --- End of inner exception stack trace ---
   at NLog.Config.XmlLoggingConfiguration.ParseIncludeElement(NLogXmlElement includeElement, String baseDirectory, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.ParseNLogElement(NLogXmlElement nlogElement, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.ParseTopLevel(NLogXmlElement content, String filePath, Boolean autoReloadDefault)
   at NLog.Config.XmlLoggingConfiguration.Initialize(XmlReader reader, String fileName, Boolean ignoreErrors)
   --- End of inner exception stack trace ---

As you can see, it seems to be getting an empty string or null value for the layout rendering of the path for the include file. This results in the file path getting rendered as: conf/nlog..config.

I'm not sure this is a problem with NLog specifically. I looked into the source code for the Environment Layout Renderer, and it eventually calls Environment.GetEnvironmentVariable(string).

I feel like this might have something more to do with the nature of Scheduled Tasks in Windows, but I'm not sure what my options are.

This task needs to run automatically whether the user is logged in or not.

Can someone explain what is going on here? Why is NLog unable to pull in the proper environment variable? What can I do to fix this problem?


Solution

  • I think this is the problem, when changing the environment variable, you need to restart Taskeng.exe.

    You should terminate Taskeng.exe and the next time scheduled task is run it will get an updated environment.

    https://superuser.com/questions/331077/accessing-environment-variables-in-a-scheduled-task