ASP.NET Core框架学习之日志框架
我们平时的开发离不开记录日志,.net core框架也内置了强大的日志记录功能。
简单示例
创建一个控制台应用,在appsettings.json中加入如下配置
1 "Logging": { 2 "LogLevel": { 3 "Default": "Debug", 4 "Microsoft": "Warning", 5 "Microsoft.Hosting.Lifetime": "Information" 6 }, 7 "Console": { 8 "IncludeScopes": true, 9 "LogLevel": { 10 "Default": "Debug", 11 "Microsoft": "Warning", 12 "Microsoft.Hosting.Lifetime": "Information", 13 "alog": "Debug" 14 } 15 } 16 }
引用包
1 Microsoft.Extensions.Logging 2 Microsoft.Extensions.Logging.Console
注入Logging到容器中
1 IConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); 2 configurationBuilder.AddJsonFile("appsettings.json", false, false); 3 var configuration = configurationBuilder.Build(); 4 var services = new ServiceCollection(); 5 services.AddLogging(builder => 6 { 7 builder.AddConfiguration(iconfigurationRoot.GetSection("Logging")); 8 builder.AddConsole(); 9 }); 10 var serviceProvider = services.BuildServiceProvider();
下面是AddLogging的源码,其中主要的部分就是将ILoggerFactory和ILogger<>注入到容器中。
1 public static IServiceCollection AddLogging(this IServiceCollection services, Action<ILoggingBuilder> configure) 2 { 3 if (services == null) 4 { 5 throw new ArgumentNullException("services"); 6 } 7 services.AddOptions(); 8 services.TryAdd(ServiceDescriptor.Singleton<ILoggerFactory, LoggerFactory>()); 9 services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>))); 10 services.TryAddEnumerable(ServiceDescriptor.Singleton((IConfigureOptions<LoggerFilterOptions>)new DefaultLoggerLevelConfigureOptions(LogLevel.Information))); 11 configure(new LoggingBuilder(services)); 12 return services; 13 }
我们可以通过两种方式创建ILogger对象
1 var logFactory = serviceProvider.GetService<ILoggerFactory>(); 2 var logger = logFactory.CreateLogger("Default"); 3 //或 4 var logger = serviceProvider.GetService<ILogger<Program>>(); 5 logger.LogInformation("aa"); 6 logger.LogError("bb"); 7 logger.LogDebug("cc");
这样我们就完成了打印日志的简单示例。
日志级别
日志级别分为如下7种,从上往下日志级别由低到高。如在配置文件中设置日志级别为Error,那么Warning等低级别的日志都不会被打印。
1 public enum LogLevel 2 { 3 Trace, 4 Debug, 5 Information, 6 Warning, 7 Error, 8 Critical, 9 None 10 }
打印日志时推荐使用字符串模板的方式
1 logger.LogDebug("时间:{date}",DateTime.Now);
不推荐下面这种方式,因为我们调试时可能记录大量Debug级别日志,当项目投入生产后,我们往往会关闭Debug级别日志,字符串模板方式在记录日志时才会进行字符串拼接,所以字符串模板的方式可以防止Dubug级别日志的字符串拼接影响性能。
1 logger.LogDebug($"时间:{DateTime.Now}");
日志域
使用日志域方法,可以让同一作用域下的日志带上相同的scopeId,这样可以帮助我们更好的做日志追踪和排查问题。
在Console配置文件中添加如下配置
1 "IncludeScopes": true
创建日志域并记录日志
using (logger.BeginScope("scopeId:{scopeId}", Guid.NewGuid())) { logger.LogInformation($"时间:{DateTime.Now}"); logger.LogError("bb"); logger.LogDebug("cc"); }
它的执行结果如下图所示,可以看到每条日志都记录了scopeId
通过Serilog框架记录结构化日志
结构化日志相比与文本日志易于检索,易于分析统计,可以用于日志告警,日志关联,以及与追踪系统的集成。下面演示Serilog的简单使用实例。
创建一个.net core web应用项目,并引用下面的nuget包
1 Serilog.AspNetCore
在appsettings.json中添加如下配置
1 "Serilog": { 2 "MinimumLevel": { 3 "Default": "Debug", 4 "Override": { 5 "Microsoft": "Warning", 6 "Microsoft.Hosting.Lifetime": "Information" 7 } 8 } 9 }
在Program.cs中添加如下代码
1 public class Program 2 { 3 public static void Main(string[] args) 4 { 5 var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", false, true).Build(); 6 Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration) 7 .WriteTo.Console(new RenderedCompactJsonFormatter()) 8 .Enrich.FromLogContext() 9 .CreateLogger(); 10 11 Log.Logger.Information("程序启动 {date}",DateTime.Now); 12 CreateHostBuilder(args).Build().Run(); 13 } 14 15 public static IHostBuilder CreateHostBuilder(string[] args) => 16 Host.CreateDefaultBuilder(args) 17 .ConfigureWebHostDefaults(webBuilder => 18 { 19 webBuilder.UseStartup<Startup>(); 20 }).UseSerilog(dispose:true); 21 }
在控制器中引用ILogger<>
1 public class WeatherForecastController : ControllerBase 2 { 3 private readonly ILogger<WeatherForecastController> _logger; 4 public WeatherForecastController(ILogger<WeatherForecastController> logger) 5 { 6 _logger = logger; 7 } 8 9 [HttpGet] 10 public string Get() 11 { 12 _logger.LogInformation("hello serilog "); 13 return "OK"; 14 } 15 }
运行效果如下图,可以看到日志都是以Json结构记录的。
上面的日志记录的较多,我们可以先将无用的日志关闭,在配置文件中将 Microsoft.Hosting.Lifetime的日志级别设置成 “Fatal”,这样我们的日志就清晰多了。
Serilog日志框架还支持多种的Sinks接收器,可以通过引用 Serilog.Sinks.Http 或 Serilog.Sinks.Elasticsearch 将日志记录到 ELK中。