您现在的位置是:网站首页> 编程资料编程资料

.Net Core日志记录之日志配置_实用技巧_

2023-05-24 560人已围观

简介 .Net Core日志记录之日志配置_实用技巧_

一、前言

在项目的开发维护阶段,有时候我们关注的问题不仅仅在于功能的实现,甚至需要关注系统发布上线后遇到的问题能否及时的查找并解决。所以我们需要有一个好的解决方案来及时的定位错误的根源并做出正确及时的修复,这样才能不影响系统正常的运行状态。

这个时候我们发现,其实在asp.net core中已经内置了日志系统,并提供了各种内置和第三方日志记录提供程序的日志记录接口,在进行应用开发中,可以进行统一配置,并且利用第三方日志框架相结合,更加有效的实现日志记录。所以在这个系列中,主要是对内置日志记录系统的学习,以及后续使用第三方日志框架集成我们需要的日志系统。

二、说明

在这一篇中主要是对日志记录的配置进行说明,从开始配置日志,以及后续使用配置进行日志处理。

在新建项目成功之后,我们都会看到一个命名为appsettings.json配置,打开一看,短短的几行配置,

 "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } },

然后启动运行的时候,程序会在调试面板和控制台中分别输出显示来源如下:

在控制台中:

在调试面板中:

这里的日志配置,在系统中到底都起来什么作用?让我们来一探究竟吧!

三、开始

3.1 默认配置

我们查看源代码发现,在程序的入口点中发现,在初始化时候,通过CreateDefaultBuilder方法来实现日志记录的默认配置。

public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); }

所以下面我们看一下CreateDefaultBuilder在源码中都对日志做了哪些默认配置?

 public static IHostBuilder CreateDefaultBuilder(string[] args) { var builder = new HostBuilder(); builder.UseContentRoot(Directory.GetCurrentDirectory()); builder.ConfigureHostConfiguration(config => { config.AddEnvironmentVariables(prefix: "DOTNET_"); if (args != null) { config.AddCommandLine(args); } }); builder.ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)) { var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); if (appAssembly != null) { config.AddUserSecrets(appAssembly, optional: true); } } config.AddEnvironmentVariables(); if (args != null) { config.AddCommandLine(args); } }) .ConfigureLogging((hostingContext, logging) => { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (isWindows) { logging.AddFilter(level => level >= LogLevel.Warning); } logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); logging.AddEventSourceLogger(); if (isWindows) { logging.AddEventLog(); } }) .UseDefaultServiceProvider((context, options) => { var isDevelopment = context.HostingEnvironment.IsDevelopment(); options.ValidateScopes = isDevelopment; options.ValidateOnBuild = isDevelopment; }); return builder; }

通过上面这一段源码我们可以看到一个命名为ConfigureLogging的对象,我们根据命名的意思大致可以看出,这是一个配置日志的方法,继续查看ConfigureLogging源码

 public static IHostBuilder ConfigureLogging(this IHostBuilder hostBuilder, Action configureLogging) { return hostBuilder.ConfigureServices((context, collection) => collection.AddLogging(builder => configureLogging(context, builder))); }

通过IServiceCollection注册服务集合容器,将日志服务添加到这个服务容器,使用AddLogging方法实现对日志服务的注册。

 public static IServiceCollection AddLogging(this IServiceCollection services, Action configure) { if (services == null) { throw new ArgumentNullException(nameof(services)); } services.AddOptions(); services.TryAdd(ServiceDescriptor.Singleton()); services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>))); services.TryAddEnumerable(ServiceDescriptor.Singleton>( new DefaultLoggerLevelConfigureOptions(LogLevel.Information))); configure(new LoggingBuilder(services)); return services; }

通过AddLogging添加到服务集合容器,先通过添加所需的配置AddOptions,通过注入的方式实现默认的ILoggerFactory,ILogger ( 这个会在后续的篇章中进行说明),再后通过LoggingBuilder完成日志对象的创建,

public interface ILoggingBuilder { IServiceCollection Services { get; } } internal class LoggingBuilder : ILoggingBuilder { public LoggingBuilder(IServiceCollection services) { Services = services; } public IServiceCollection Services { get; } }

对日志系统的配置,用于提供程序的接口,ILoggingBuilder后面可以对该对象进行拓展使用。

通过以上的流程CreateDefaultBuilder方法,实现对预先配置的默认值初始化,因此也发现了其中的ConfigureLogging也是其中要进行默认初始化的值,也就是系统默认的日志配置。

单独把ConfigureLogging这一块的源码拎出来再看看:

 .ConfigureLogging((hostingContext, logging) => { var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (isWindows) { logging.AddFilter(level => level >= LogLevel.Warning); } logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); logging.AddEventSourceLogger(); if (isWindows) { logging.AddEventLog(); } })

在asp.net core启动中,根据操作系统平台适应不同的服务,在windows服务中,将EventLogLoggerProvider的默认值设置为警告或者更高的级别。

AddConfiguration : 添加系统日志的全局配置。

在配置中,可以根据提供的不同类型程序来针对实现日志记录的输出方式。而这里默认实现的AddConsole()AddDebug() 和AddEventSourceLogger()分别是将日志输出到控制台、调试窗口中,以及提供写入事件源。

AddConsole : 添加控制台到工厂方法中,用来将日志记录到控制台中。

AddDebug : 添加Debug窗口到工厂方法中,用来将日志记录到窗口中。

说明:asp.net core 内置的日志接口中,实现了多种内置的日志提供器,除了上面默认实现的ConsoleDebugEventSource,还包括下面的这几个

EventLog :

TraceSource

AzureAppServicesFile

AzureAppServicesBlob

ApplicationInsights

还记得上面提到的appsettings.json配置吗?在这里,我们来看看

{ "Logging": { "LogLevel": { "Default": "Debug", "Microsoft": "Information" }, "Console": { "LogLevel": { "Default": "Debug", "System": "Warning" } } } }

AddConfiguration中,

logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));

获取配置文件的Logging数据,实现全局配置,

 public static ILoggingBuilder AddConfiguration(this ILoggingBuilder builder, IConfiguration configuration) { builder.AddConfiguration(); builder.Services.AddSingleton>(new LoggerFilterConfigureOptions(configuration)); builder.Services.AddSingleton>(new ConfigurationChangeTokenSource(configuration)); builder.Services.AddSingleton(new LoggingConfiguration(configuration)); return builder; } internal class LoggerFilterConfigureOptions : IConfigureOptions { private const string LogLevelKey = "LogLevel"; private const string DefaultCategory = "Default"; private readonly IConfiguration _configuration; public LoggerFilterConfigureOptions(IConfiguration configuration) { _configuration = configuration; } public void Configure(LoggerFilterOptions options) { LoadDefaultConfigValues(options); } private void LoadDefaultConfigValues(LoggerFilterOptions options) { if (_configuration == null) { return; } options.CaptureScopes = _configuration.GetValue(nameof(options.CaptureScopes), options.CaptureScopes); foreach (var configurationSection in _configuration.GetChildren()) { if (configurationSection.Key.Equals(LogLevelKey, StringComparison.OrdinalIgnoreCase)) { // Load global category defaults LoadRules(options, configurationSection, null); } else { var logLevelSection = configurationSection.GetSection(LogLevelKey); if (logLevelSection != null) { // Load logger specific rules var logger = configurationSection.Key; LoadRules(options, logLevelSection, logger); } } } } private void LoadRules(LoggerFilterOptions options, IConfigurationSection configurationSection, string logger) { foreach (var section in configurationSection.AsEnumerable(true)) { if (TryGetSwitch(section.Value, out var level)) { var category = section.Key; if (category.Equals(DefaultCategory, StringComparison.OrdinalIgnoreCase)) { category = null; } var newRule = new LoggerFilterRule(logger, category, level, null); options.Rules.Add(newRule); } } } }

以上是AddConfiguration实现的整体流程源码,默认注册实现LoggerFilterConfigureOptions对配置数据的读取,其中定义的 LogLevelKey = "LogLevel" 、DefaultCategory = "Default" 默认字符串,以此来获取默认全局配置数据。

在默认配置的文本格式appsettings.json中,Logging属性可以具有LogLevel和日志提供程序属性。Logging

-六神源码网