ASP.NET Core has built-in aspsettings.env.json which can automatically apply to different environments. But how about NLog? In official examples, it only got one nlog.config file which will be used in all environments. Let's see how we can change it to use different config files on different environments.
Why do we need this
This requirement actually came from this blog system. My blog runs on Azure App Services, and it has a special folder for putting logs that sits outside of the root directory of the website. Although I can write logs inside the application directory, it is not a good Azure practice. I need to change the log file location.
From
fileName="${basedir}\logs\${shortdate}.log"
To
fileName="${basedir}\..\..\LogFiles\Application\${shortdate}.log"
Yes, NLog can identify the parent directory by "..\"
Now, my log is fine on the production environment, but what about my local dev machine? The log may be written into an unwanted or non-exist directory.
So, to solve this problem, I need a way to check the current application environment and make NLog use an environment specific config file.
Create a new config file
Copy the nlog.config to nlog.debug.config for my dev machine to use. The only difference from nlog.config is the log file path:
fileName="${basedir}\logs\${shortdate}.log"
Now we have 2 files for 2 environments
Load config file based on environment
NLog will load it's config file when ASP.NET Core application starts, which is in Program.cs
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
// ...
}
But at this moment, the Dependency Injection is not ready to use yet. We can't use IHostingEnvironment, how can we get the environment name?
Actually, the environment name for ASP.NET Core can be set by an environment variable called ASPNETCORE_ENVIRONMENT, you can see it in project property:
So, even we don't have DI yet, we can still code like this:
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
It will return the current environment name as string, for the most commonly used environment names, ASP.NET Core has a built-in class:
namespace Microsoft.AspNetCore.Hosting
{
//
// Summary:
// Commonly used environment names.
public static class EnvironmentName
{
public static readonly string Development;
public static readonly string Staging;
public static readonly string Production;
}
}
In my case, if the environment name is not Production, I will need NLog to load nlog.debug.config:
public static void Main(string[] args)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var isProd = environment == EnvironmentName.Production;
var logger = NLogBuilder.ConfigureNLog(isProd ? "nlog.config" : "nlog.debug.config").GetCurrentClassLogger();
}
Now, my logs can be written in the special folder on Azure:
and when I am debugging the application locally, the log can be written under the project directory:
Corentin
Thank you for this clear and concise guide. ASP.NET also allows merging configuration files: keep in appsettings.json the configuration common to all environments, and appsettings.env.json the environment's specific configuration. How would we achieve that with nlog configuration file?
I'm afraid of the burden of maintaining common config in every nlog file.