最近排查一个ASP.Net Core项目的Bug,用LogInformation()记录一些运行日志,本地测试日志记录正常,然后发到RC环境测试,结果发现死活没有日志信息。
首先想到就是LogLevel设置有问题。检查了基础的配置文件(appsettings.json)没有问题,而RC环境的配置文件(appsettings.RC.json)未配置Logging节点,也就不会覆盖。
1 "Logging": { 2 ??"IncludeScopes": false, 3 ??"LogLevel": { 4 ????"Default": "Information", 5 ????"System": "Warning", 6 ????"Microsoft": "Warning" 7 ??}, 8 ??"Console": { 9 ????"LogLevel": {10 ??????"Default": "Warning"11 ????}12 ??}13 }
然后检查了涉及appsettings.json的代码。在Startup.cs中,会根据“environment.json”文件中配置的“EnvironmentName”值,来加载不同配置文件。
1 private readonly ILoggerFactory m_LoggerFactory; 2 private readonly IConfiguration m_Configuration; 3 ?4 public Startup(IHostingEnvironment env, ILoggerFactory loggerFactory) 5 { 6 ????m_LoggerFactory = loggerFactory; 7 ?8 ????var environmentName = GetEnvironmentName(); 9 ????var builder = new ConfigurationBuilder()10 ????????.SetBasePath(env.ContentRootPath)11 ????????.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)12 ????????.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true);13 14 ????m_Configuration = builder.Build();15 }16 17 private static string GetEnvironmentName()18 {19 ????var configuration = new ConfigurationBuilder()20 ????????.AddJsonFile("environment.json", optional: true)21 ????????.Build();22 ????return configuration["EnvironmentName"] ?? string.Empty;23 }
可是environment.json配置也没问题,而其中的m_Configuration变量只是会注入IoC中供业务代码读取配置使用,并没有对Logging配置做任何修改。
之后又想到,所有环境的配置文件都是放在同一个目录下,是否是串文件了呢?而其中appsettings.Production.json中确实有配置Logging.LogLevel为“Warning”,如果加载了这个配置,那LogInformation()就不会输出日志了。因而调整了下appsettings.Production.json中的Loggind.LogLevel为“Information”,然后再测试,嘿,有日记信息了!也就是说,Production的配置文件确实被加载了。
再次检查代码发现并未有明确加载Production文件,那该不会是某个系统方法通过环境变量ASPNETCORE_ENVIRONMENT加载的吧?因为未设置该值(确实没设置)默认就会是Production[1]。
于是立马修改ASPNETCORE_ENVIRONMENT=RC(注意是1个“_”),还原appsettings.Production.json,然后重启服务测试,不出所料,日志正常记录。那么,接下来就是找到那个“系统方法”了。
仔细翻了翻官方文档,找到了以下内容[2]:
CreateDefaultBuilder方法(2.0新增[4])会调用2次AddJsonFile(),第1次加载appsettings.json,第2次加载appsettings.{Environment}.json,而Environment取至IHostingEnvironment.EnvironmentName,即环境值。对应源码[5]:
1 builder.UseKestrel((builderContext, options) => 2 { 3 ????options.Configure(builderContext.Configuration.GetSection("Kestrel")); 4 }) 5 .ConfigureAppConfiguration((hostingContext, config) => 6 { 7 ????var env = hostingContext.HostingEnvironment; 8 ?9 ????config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)10 ??????????.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);11 12 ????if (env.IsDevelopment())13 ????{14 ????????var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));15 ????????if (appAssembly != null)16 ????????{17 ????????????config.AddUserSecrets(appAssembly, optional: true);18 ????????}19 ????}20 21 ????config.AddEnvironmentVariables();22 23 ????if (args != null)24 ????{25 ????????config.AddCommandLine(args);26 ????}27 })
好嘛,真相大白:
- 未设置环境变量ASPNETCORE_ENVIRONMENT,则默认为Production
- 调用CreateDefaultBuilder方法构建WebHost,自动加载appsettings.Production.json
- 最终,Logging.LogLevel被设置为了Production配置的值“Warning”,因而LogInformation()失效
那么,只要正确设置ASPNETCORE_ENVIRONMENT值即可解决问题咯。
但是,还记得上面提到的“environment.json”文件吗?这个文件目的本就是为了方便切换不同环境的配置文件而建立的,Logging的配置理应由它来决定,如果通过ASPNETCORE_ENVIRONMENT来设置,就多此一举了。那怎么才能让在Startup构造方法中构建的m_Configuration对象对Logging生效呢?官方也给出了方案:ConfigureAppConfiguration方法[2]!是不是觉得眼熟?在上面的CreateDefaultBuilder方法中正是通过ConfigureAppConfiguration()来加载默认配置的。
最终,代码修正如下:
1 private static IWebHost BuildWebHost(string[] args) 2 { 3 ????return WebHost.CreateDefaultBuilder(args) 4 ????????.CaptureStartupErrors(true) 5 ????????.UseSetting(WebHostDefaults.DetailedErrorsKey, "true") 6 ????????.ConfigureAppConfiguration((hostingContext, config) => 7 ????????{ 8 ????????????config.Sources.Clear(); 9 ????????????config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)10 ????????????????.AddJsonFile($"appsettings.{GetEnvironmentName()}.json", optional: true, reloadOnChange: true);11 ????????})12 ????????.UseStartup<Startup>()13 ????????.UseNLog()14 ????????.Build();15 }16 17 private static string GetEnvironmentName()18 {19 ????var configuration = new ConfigurationBuilder()20 ????????.AddJsonFile("environment.json", optional: true)21 ????????.Build();22 ????return configuration["EnvironmentName"] ?? string.Empty;23 }
构建m_Configuration的代码,由Startup.cs转移到了Program.cs,而在Startup.cs中,Configuration对象可直接注入:
1 private readonly ILoggerFactory m_LoggerFactory;2 private readonly IConfiguration m_Configuration;3 4 public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)5 {6 ????m_LoggerFactory = loggerFactory;7 ????m_Configuration = configuration;8 }
至此,告一段落!
参考文档
- 官方文档:配置Environment
- 官方文档:配置Configuration
- 官方文档:配置Logging
- ASP.Net Core 1.x迁移至2.0
- CreateDefaultBuilder源码
- asp.netcore 深入了解配置文件加载过程
记一个ASP.Net Core配置文件问题
原文地址:https://www.cnblogs.com/linys2333/p/9970597.html