我们知道ASP.NET Core自带了appsettings.环境名.json,天生就能做到根据不同的环境选择不同的配置文件。但是NLog的官方例子里只有一份nlog.config,如何根据不同环境加载不同配置呢?
怎么会有这种想法
首先,这个需求的背景,依然来源于我自己的博客系统(https://edi.wang)。我的博客运行在全球领先的微软智能云Azure国际版的App Services上(真香)。而这个服务有配套的日志文件夹,位于应用程序目录以外。虽然我仍然可以把日志记在网站目录下,但这么做并不是Azure的推荐实践。因此对于生产环境,我需要更改NLog的日志文件路径。
原路径
fileName="${basedir}logs${shortdate}.log"
新路径
fileName="${basedir}....LogFilesApplication${shortdate}.log"
没错,NLog支持用".."的方式表示上一级文件夹。
现在生产环境没问题了,但是开发环境会跟着受影响。日志会写到不合理的文件夹里去,如果没有二级父目录,那么日志就直接没了。因此为了解决这个问题,我们需要一个能判断当前环境,并使用不同NLog配置文件的方法。
新建环境配置文件
首先,复制出一个用于开发环境的配置文件,如:nlog.debug.config,这种命名的好处在于,VS会自动将它nest到nlog.config下。
在我的例子里,只有日志路径是环境独立的。因此我需要在nlog.debug.config里针对开发环境,设置日志路径:
fileName="${basedir}logs${shortdate}.log"
加载环境配置文件
NLog加载配置文件的位置位于ASP.NET Core应用刚启动的时候:
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
// ...
}
然而这时候程序还没有加载依赖注入,用不了IHostingEnvironment,如何获取环境名称呢?
其实呢,ASP.NET Core的环境名称是通过一个名为 ASPNETCORE_ENVIRONMENT 的环境变量配置的,这在VS里可以通过工程属性看到:
所以就算我们还没有DI服务,我们可以这样硬搞:
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
它会返回环境名称的字符串值。对于最常用的环境名称,ASP.NET Core框架自己有一个预定义的文件:
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;
}
}
在我的例子里,只要不是Production环境,我就要让NLog加载nlog.debug.config,所以这样写就OK啦:
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();
}
现在,网站在Azure上能够将日志写入专用文件夹:
在本地debug的时候,写入网站根目录: