ASP.NET Core 源码学习之 Logging[2]:Configure

在上一章中,我们对 ASP.NET Logging 系统做了一个整体的介绍,而在本章中则开始从最基本的配置开始,逐步深入到源码当中去。

默认配置

在 ASP.NET Core 2.0 中,对默认配置做了很大的简化,并把一些基本配置移动到了程序的入口点 Program 类中,更加简洁。

public class Program{  

 public static void Main(string[] args)    {BuildWebHost(args).Run();}  
 
  public static IWebHost BuildWebHost(string[] args) =>WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build(); }

如上,可以看到基本的配置都放到了 CreateDefaultBuilder 方法中,而 WebHost则在 MetaPackages 中,提供了一些简化方法。

public static IWebHostBuilder CreateDefaultBuilder(string[] args){    

var builder = new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).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()){              
                 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) =>{logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));logging.AddConsole();logging.AddDebug();}).UseIISIntegration().UseDefaultServiceProvider((context, options) =>{options.ValidateScopes = context.HostingEnvironment.IsDevelopment();});  
        return builder; }

如上可以看到一些我们在 1.0 中非常熟悉的代码,而 ConfigureLogging 则是 IWebHostBuilder 类的一个扩展方法:

public static IWebHostBuilder ConfigureLogging(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, ILoggingBuilder> configureLogging){  

 return hostBuilder.ConfigureServices((context, collection) => collection.AddLogging(builder => configureLogging(context, builder))); }

而 AddLogging 则是 Logging 系统的入口点,是由 Microsoft.Extensions.Logging 所提供的扩展方法:

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

首先注册了 Logging 系统基本服务的默认实现,用来激活 Logging 系统,然后创建 LoggingBuilder 对象,而后一系列对日志系统的配置,都是调用的该对象的扩展方法。

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

现在回头看看 CreateDefaultBuilder方法中通过 ConfigureLogging 来对日志系统所做的默认配置。

AddConfiguration

该方法是对日志系统的一个全局配置:

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

public static ILoggingBuilder AddConfiguration(this ILoggingBuilder builder, IConfiguration configuration){builder.Services.AddSingleton<IConfigureOptions<LoggerFilterOptions>>(new LoggerFilterConfigureOptions(configuration));builder.Services.AddSingleton<IOptionsChangeTokenSource<LoggerFilterOptions>>(new ConfigurationChangeTokenSource<LoggerFilterOptions>(configuration));  
 return builder; }

首先使用 Options 模式注册了一个 LoggerFilterOptions

public class LoggerFilterOptions{ 
   public LogLevel MinLevel { get; set; }  
     public IList<LoggerFilterRule> Rules { get; } = new List<LoggerFilterRule>(); }
     public class LoggerFilterRule{...  
      public string ProviderName { get; }  
      public string CategoryName { get; }  
        public LogLevel? LogLevel { get; }  
         public Func<string, string, LogLevel, bool> Filter { get; }.... }

而默认实现 LoggerFilterConfigureOptions 的逻辑很简单,就是从配置文件中读取 LogLevel 的配置:

internal class LoggerFilterConfigureOptions : IConfigureOptions<LoggerFilterOptions>
{...  
 private void LoadDefaultConfigValues(LoggerFilterOptions options)    {        if (_configuration == null){        
     return;}        
     foreach (var configurationSection in _configuration.GetChildren()){        
        if (configurationSection.Key == "LogLevel"){            
            // Load global category defaultsLoadRules(options, configurationSection, null);}      
           else{       var logLevelSection = configurationSection.GetSection("LogLevel");      
                    if (logLevelSection != null){                    // Load logger specific rulesvar 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 == "Default"){category = null;}              
                         var newRule = new LoggerFilterRule(logger, category, level, null);options.Rules.Add(newRule);}}}... }

通过代码,我们可以清楚的知道,我们的配置文件应该按如下格式来定义

{"Logging": {"LogLevel": { // 表示全局"Default": "Warning" // 不指定CategoryName,应用于所有Category},"Console":{ // 指定 ProviderName,仅针对于 ConsoleProvider"Default": "Warning","Microsoft": "Error" // 指定CategoryName为Microsoft的日志级别为Error}}}

而 IOptionsChangeTokenSource 是对上面 IConfigureOptions 的一个补充,为我们获取 OptionsMonitor 注入了必要的服务,更多关于 Options 的介绍可以看我之前文章 IOptionsMonitor。

而在 Logging 系统中,也是通过注入 IOptionsMonitor<LoggerFilterOptions> 来使用 LoggerFilterOptions 的:

public LoggerFactory(IEnumerable<ILoggerProvider> providers, IOptionsMonitor<LoggerFilterOptions> filterOption){
_providerRegistrations = providers.Select(provider => new ProviderRegistration { Provider = provider }).ToList();
_changeTokenRegistration = filterOption.OnChange(RefreshFilters);RefreshFilters(filterOption.CurrentValue); }

AddConsole

上面我们提到,在配置文件中可以指定针对某个 Provider 的配置,而 AddConsole 则是用来添加一个 Console 类型的 Provider,用来将日志记录到控制台中:

public static ILoggingBuilder AddConsole(this ILoggingBuilder builder){builder.Services.AddSingleton<ILoggerProvider, ConsoleLoggerProvider>();  
 return builder; }
 public static ILoggingBuilder AddConsole(this ILoggingBuilder builder, Action<ConsoleLoggerOptions> configure){  
  if (configure == null){      
    throw new ArgumentNullException(nameof(configure));}builder.AddConsole();builder.Services.Configure(configure);  
      return builder; }

以上代码在 Microsoft.Extensions.Logging.Console Package 中,首先提供了 ILoggerProvider 的注入方法,用来启用控制台的日志记录功能,而且还提供了一个方法重载,用来指定针对 ConsoleProvider 的配置。

AddDebug

而 AddDebug 与 AddConsole 类似,只不过是把日志输出在 Debug 窗口中。

更多关于 Provider 的配置,会在以后再详细探索。

自定义配置

上面介绍了 ASP.NET Core 中对日志系统的默认配置,那么如果我们想再添加一些其它配置应该怎么做呢?

在 1.0 时代,我们通过是在 Startup 类中的 Configure 方法中,注入 ILoggerFactory 来进行配置,当然,在 2.0 中我们仍然可以这样做,但是更加推荐的做法是在 Program 入口方法中进行配置,而 Configure 方法通过是对一些中间件的配置。

我们可以直接使用上面介绍过的 ConfigureLogging 扩展方法来添加我们自己的配置:

public static IWebHost BuildWebHost(string[] args) =>WebHost.CreateDefaultBuilder(args).ConfigureLogging(build =>{build.AddFilter(f => f == LogLevel.Debug);build.AddEventSourceLogger();}).UseStartup<Startup>().Build();

我们添加了一个 EventSource Provider,并且使用了 AddFilter扩展方法对日志的过滤进行配置。而 AddFilter 的作用类似于 前面介绍的 AddConfiguration,只是把配置方式从配置文件变成了代码。

public static class FilterLoggingBuilderExtensions{  
 // 具有多个重载,此处省略public static ILoggingBuilder AddFilter(this ILoggingBuilder builder, Func<string, string, LogLevel, bool> filter) =>builder.ConfigureFilter(options => options.AddFilter(filter));  
 
  private static ILoggingBuilder ConfigureFilter(this ILoggingBuilder builder, Action<LoggerFilterOptions> configureOptions)    {builder.Services.Configure(configureOptions);      
   return builder;} }

可以看到,最终也是对 ConfigureOptions 的配置,而后执行的配置会覆盖之前配置的。

总结

本章从 Logging 系统的起始点入手,详细分析了如何对 Logging 系统进行配置,分为日志级别过滤和日志提供者两种配置,而下一章则会分析一下日志的过滤原理。

相关文章: 

  • ASP.NET Core 源码学习之 Options[1]:Configure

  • ASP.NET Core 源码学习之 Options[2]:IOptions

  • ASP.NET Core 源码学习之 Options[3]:IOptionsSnapshot

  • ASP.NET Core 源码学习之 Options[4]:IOptionsMonitor

  • ASP.NET Core 源码学习之Logging[1]:Introduction

  • ASP.NET Core MVC 源码学习:详解 Action 的匹配

  • asp.net core源码飘香:从Hosting开始

  • asp.net core源码飘香:Configuration组件

  • asp.net core源码飘香:Options组件

  • asp.net core源码飘香:Logging组件

原文地址:http://www.cnblogs.com/RainingNight/p/asp-net-core-logging-configure.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

两个月拿到N个offer,看看我是如何做到的

转载自 两个月拿到N个offer&#xff0c;看看我是如何做到的 前言&#xff1a; 北京-三年经验-Java&#xff0c;在金三银四这两个月期间&#xff08;在五月初还去面试了几家&#xff0c;主要是三四月份期面试剧居多&#xff09;&#xff0c;我跳槽面试&#xff0c;前前后后我…

“小朋友”们节日快乐呀~

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。今天是六月一日——儿童节&#xff0c;看了看朋友圈&#xff0c;不管是大孩子还是小孩子&#xff0c;都在过节&#xff0c;哈哈哈。最近四班一直在做项目&#xff0c;一共6个小组&#xff…

Entity Framework Core 2.0 全局查询过滤器

本博文翻译自&#xff1a;http://gunnarpeipman.com/2017/08/ef-core-global-query-filters/ Entity Framework Core 2.0 全局查询过滤器 Entity Framework Core 2.0引入了全局查询过滤器&#xff0c;可以在创建模型时应用到实体 。它使得构建多租户应用程序和支持对实体 的软…

SpringCloudGateway

文章目录SpringCloudGateway起步消费端整合SpringCloudGateway静态路由配置内置扩展网关过滤内置网关过滤自定义过滤全局过滤器内置全局过滤器自定义全局过滤器ForwardRoutingFilterNetty全局路由响应式负载均衡代理GatewayMetricsFilter网关度量过滤器&#xff08;服务监控&am…

来自一位家长的肺腑之言,句句在理!!!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。今天分享一段话&#xff0c;原创来自三班的一位同学家长&#xff0c;可所谓字字在理&#xff01;看完之后我自己也反思了好多&#xff0c;主要是思想观念的转变&#xff0c;就像佟老师给我说的一样…

jzoj1295,P1607-轻轨(庙会班车)【贪心,线段树】

前言 我考试时敲了一个不仅比正解编程复杂度高&#xff0c;而且时间更慢&#xff0c;还AC不了的费用流 垃圾代码 #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define MN 20011 using namespace std; struct node{int…

一篇文章了解RPC框架原理

转载自 一篇文章了解RPC框架原理 1.RPC框架的概念 RPC&#xff08;Remote Procedure Call&#xff09;–远程过程调用&#xff0c;通过网络通信调用不同的服务&#xff0c;共同支撑一个软件系统&#xff0c;微服务实现的基石技术。使用RPC可以解耦系统&#xff0c;方便维护…

winform分页案例简单实现方式~

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。最近&#xff0c;四班在做KTV点歌系统&#xff0c;正好需要用到分页的内容&#xff0c;所以今天我就整理整理&#xff0c;写了一个简易的winfrom分页案例&#xff0c;以下是案例截图&#…

.Net Core下通过Proxy 模式 使用 WCF

.NET Core下的WCF客户端也是开源的&#xff0c;这次发布.NET Core 2.0,同时也发布了 WCF for .NET Core 2.0.0, 本文介绍在.NET Core下如何通过Proxy 消费WCF服务。 我们现在直接可以在 standard 2.0下调用wcf服务了&#xff0c;不过 Microsoft WCF Web Service Reference Pro…

JWT 入门

文章目录使用JWT的原因JWT结构JWT入门案例Token拦截使用JWT的原因 为了保护项目之中的数据资源&#xff0c;那么一定就需要采用认证检测机制&#xff0c;于是SpringCloud进行认证处理&#xff0c;就可以使用SpringSecurity 来实现了&#xff0c;但是如果你真的去使用了SpringSe…

当你左右看看没有发现我时,千万千万别往看……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。周五&#xff0c;又是一个考试的周五&#xff0c;因为本周都在做项目&#xff0c;还以为同学们没有好好的备考&#xff0c;估计考的不好&#xff0c;没想到今天测试的结果是自从考试以来最…

2018/7/11-纪中某C组题【jzoj1293,jzoj1294,jzoj1295】

前言 今天C组题目有毒&#xff0c;第一题题目玄学&#xff0c;第二题就是不会&#xff0c;第三题考的贼偏。fw(hjw&#xff0c;his博客&#xff1a;https://blog.csdn.net/gx_man_vip)说今天B组题目还行早知道就去做B组了qwq 今日分数 去掉了十分强大的纪中dalao 正题 T1&…

关系型数据库的分片原则

来自Citus的Ozgun Erdogan分享了进行数据库分片的三个原则&#xff0c;并强调应用类型是决定数据库分片最主要的因素。其中B2B类型的应用最容易进行数据库分片。 在数据库很小的时候&#xff0c;可以很容易地通过添加硬件来扩展数据库。但随着数据表数量的不断增长&#xff0c…

分布式架构--基本思想汇总

转载自 分布式架构&#xff0d;&#xff0d;基本思想汇总 在互联网大行其道的今天&#xff0c;各种分布式系统已经司空见惯。搜索引擎、电商网站、微博、微信、O2O平台。。凡是涉及到大规模用户、高并发访问的&#xff0c;无一不是分布式。 关于分布式系统&#xff0c;并没有…

花了100多去KTV不是唱歌,竟然是……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。老师&#xff0c;歌词可以实现&#xff0c;不过比较麻烦~也还行你这样 准备几首歌的歌词就行到时候只演示这几首歌如果是其他的哥的话&#xff0c;就显示暂无歌词行&#xff0c;有时间就试…

jzoj4272-序章-弗兰德的秘密【树形dp】

正题 大意 两棵树&#xff0c;它们的相似值是它们留下最多的节点使它们的结构相同。求相似值。 这两颗树就是结构相同的&#xff0c;相似值是8。 解题思路 就是树形dp。可以用f[i][j]f[i][j]表示树1的第ii号节点和它的子树与树2的j" role="presentation" s…

从NIO到Netty开发

转载自 从NIO到Netty开发 1. 从传统BIO到NIO的升级 Client/Server模型是网络编程的基本模型&#xff0c;服务端提供位置信息&#xff0c;客户端通过连接操作向服务端发起连接请求&#xff0c;通过三次握手建立连接&#xff0c;如果连接建立成功&#xff0c;双方就可以通过网…

Orleans入门例子

Orleans是微软开源的分布式actor模型框架.actor模型的原理网络上有很多文章.有许多理论性的文章,深刻地我都不知道怎么应用.在这里我就不赘述了.既然是博客,就说说自己的理解。 对于编程来说&#xff0c;不管是前台还是后台&#xff0c;在现在的计算机环境下&#xff0c;多线程…

JavaScript常用单词整理总结

第一章object对象undefined未定义变量boolean布尔类型sort()对数组排序charAt返回在指定位置的字符toLowerCase()把字符串转换为小写button按钮break结束循环toUpperCase()把字符串转换为大写split(str)将字符串分割为字符串数组length获取数组的长度continue结束当前循环&…

JWT 应用

文章目录JWT工具模块Token认证微服务JWT授权监测网关认证过滤消费端获取JWTJWT工具模块 如果要想在项目之中去使用JWT技术&#xff0c;那么就必须结合到已有的模块之中,最佳的做法就是将JWT的相关的处理 操作做为一个自动的starter组件进行接入 1、【microcloud项目】既然要开…