日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core 源码学习之 Logging[3]:Logger

發(fā)布時(shí)間:2023/11/29 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 源码学习之 Logging[3]:Logger 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上一章,我們介紹了日志的配置,在熟悉了配置之后,自然是要了解一下在應(yīng)用程序中如何使用,而本章則從最基本的使用開始,逐步去了解去源碼。

LoggerFactory

我們可以在構(gòu)造函數(shù)中注入 ILoggerFactory,來創(chuàng)建一個(gè)日志記錄器:

public class TestController : Controller {private readonly ILogger _logger;public TestController(ILoggerFactory factory){_logger = factory.CreateLogger(nameof(TestController));}public void TestLog(){_logger.LogInformation("info");_logger.LogDebug("debug");} }

在上一章中我們有介紹到,ILoggerFactory 的默認(rèn)實(shí)現(xiàn)是 LoggerFactory。而 LoggerFactory 中的代碼較多,我們慢慢來看:

首先是構(gòu)造函數(shù):

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

看到這里不得不先說一下 ILoggerProvider:

public interface ILoggerProvider : IDisposable {ILogger CreateLogger(string categoryName); }

而我們知道,LoggerFactory 也有一個(gè) CreateLogger 方法,那他們之間有什么區(qū)別呢,后面會(huì)解釋。

而現(xiàn)在我們可以猜到,在具體的 Provider 中,如 AddConsole 擴(kuò)展方法,只是簡(jiǎn)單的將注冊(cè)了一個(gè) ILoggerProvider 的實(shí)例,這樣,在DI系統(tǒng)創(chuàng)建 LoggerFactory 實(shí)例時(shí),便能夠解析到所有注冊(cè)的 Provider。再往下看一下我們所調(diào)用的 LoggerFactory 的 CreateLogger 方法:

public ILogger CreateLogger(string categoryName) {if (CheckDisposed()){throw new ObjectDisposedException(nameof(LoggerFactory));}lock (_sync){Logger logger;if (!_loggers.TryGetValue(categoryName, out logger)){logger = new Logger(){Loggers = CreateLoggers(categoryName)};_loggers[categoryName] = logger;}return logger;} }private LoggerInformation[] CreateLoggers(string categoryName) {var loggers = new LoggerInformation[_providerRegistrations.Count];for (int i = 0; i < _providerRegistrations.Count; i++){var provider = _providerRegistrations[i].Provider;loggers[i].Logger = provider.CreateLogger(categoryName);loggers[i].ProviderType = provider.GetType();}ApplyRules(loggers, categoryName, 0, loggers.Length);return loggers; }

首先是直接 new 了一個(gè) Logger 實(shí)例,然后為其 Loggers 屬性賦值,而 Loggers 屬性則是由注冊(cè)的所有 ILoggerProvider 所創(chuàng)建出來的 Logger 集合。

回到剛才的問題,有兩種 CreateLogger 方法,也就有兩種 Logger,一種是直接 New 出來的 Logger,是 ILogger 的默認(rèn)實(shí)現(xiàn)者,也是我們記錄日志時(shí)所直接調(diào)用的 Logger,另外一種則是由 ILoggerProvider 所創(chuàng)建出來的 Logger,姑且稱之為 PLogger 吧。而在我們的應(yīng)用程序中記錄日志時(shí),只需要關(guān)注 Logger 就可以了,而不需要去關(guān)注 PLogger,因?yàn)?Logger 是一個(gè)日志記錄器的聚合,包含所有注冊(cè)的 PLogger,PLogger 則是具體的執(zhí)行者,我們可以通過代碼來更清楚的了解:

internal class Logger : ILogger {public LoggerInformation[] Loggers { get; set; }public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter){var loggers = Loggers;if (loggers == null){return;}List<Exception> exceptions = null;foreach (var loggerInfo in loggers){if (!loggerInfo.IsEnabled(logLevel)){continue;}try{loggerInfo.Logger.Log(logLevel, eventId, state, exception, formatter);}catch (Exception ex){if (exceptions == null){exceptions = new List<Exception>();}exceptions.Add(ex);}}if (exceptions != null && exceptions.Count > 0){throw new AggregateException(message: "An error occurred while writing to logger(s).", innerExceptions: exceptions);}}public bool IsEnabled(LogLevel logLevel){...}public IDisposable BeginScope<TState>(TState state){...} }

可以看到,Logger 的 Log 方法只是依次調(diào)用 Loggers 屬性中的 Log 方法,而其本身并不具有記錄日志的功能。

再繼續(xù)把視線轉(zhuǎn)回到 LoggerFactory 類,在其 CreateLoggers 方法中,最后還調(diào)用了 ApplyRules,這便是我們上一章中所配置的過濾器的用武之地了。

private void ApplyRules(LoggerInformation[] loggers, string categoryName, int start, int count) {for (var index = start; index < start + count; index++){ref var loggerInformation = ref loggers[index];RuleSelector.Select(_filterOptions,loggerInformation.ProviderType,categoryName,out var minLevel,out var filter);loggerInformation.Category = categoryName;loggerInformation.MinLevel = minLevel;loggerInformation.Filter = filter;} }

RuleSelector 中的代碼我的就不貼了,簡(jiǎn)單說一下其過濾規(guī)則的選擇順序:

  • 首先查找指定了 ProviderName 并與當(dāng)且 Provider的名稱(Alias)相同的過濾規(guī)則,如果沒有,則選用未指定 ProviderName 的過濾規(guī)則。
  • 選擇指定的 CategoryName 相符合的過濾規(guī)則,如果沒有,則選擇未指定 CategoryName 的那一條。
  • 如果符合的規(guī)則有多條,則選用最后一條。
  • 如果未找到相符合的規(guī)則,則使用全局的最小過濾級(jí)別。
  • 而且我們可以看到,LoggerInformation 帶有 MinLeve 屬性和 Filter 委托兩種過濾配置,而這兩種配置的來源,在上一章中可以看到,分別是從配置文件(AddConfiguration)和直接使用委托(AddFilter)來進(jìn)行配置的。而他們的優(yōu)先級(jí)又是怎么樣的?

    internal struct LoggerInformation {public ILogger Logger { get; set; }public string Category { get; set; }public Type ProviderType { get; set; }public LogLevel? MinLevel { get; set; }public Func<string, string, LogLevel, bool> Filter { get; set; }public bool IsEnabled(LogLevel level){if (MinLevel != null && level < MinLevel){return false;}if (Filter != null){return Filter(ProviderType.FullName, Category, level);}return true;} }

    無(wú)需多說,通過上面的 IsEnabled 方法能夠清楚的看到,先使用 MinLevel 過濾,再使用 Filter 進(jìn)行過濾。

    再總結(jié)一下其整個(gè)流程:首先是注冊(cè) Provider,然后 LogFactory 通過DI系統(tǒng)解析所有注冊(cè)的 Privoder,在我們調(diào)用其 CreateLogger 方法時(shí),創(chuàng)建一個(gè) Logger 對(duì)象,并通過這些 Provider 創(chuàng)建一個(gè) LoggerInformation 集合賦予給 Logger 對(duì)象,并包含 PLogger 和 經(jīng)過篩選后的過濾規(guī)則,最后在我們調(diào)用 Log 方法記錄日志時(shí),會(huì)遍歷 LoggerInformation 集合,然后執(zhí)行過濾方法,再調(diào)用 PLogger 中的 Log 方法。

    ILogger

    上面介紹了使用 LogFactory 創(chuàng)建 ILogger 的方式,其實(shí)還有一種更簡(jiǎn)單的使用方式,我們可以直接在構(gòu)造函數(shù)中注入 ILogger<T> 來記錄日志:

    public class TestController : Controller {private readonly ILogger _logger;public TestController(ILogger<AccountController> logger){_logger = logger;} }

    是不是很神奇,那么是如何實(shí)現(xiàn)的呢?

    public interface ILogger<out TCategoryName> : ILogger {}

    而 ILogger 的默認(rèn)實(shí)現(xiàn),在上一章中介紹的 AddLogging 方法中,我們知道是 Logger<T>。

    public class Logger<T> : ILogger<T> {private readonly ILogger _logger;/// <summary>/// Creates a new <see cref="Logger{T}"/>./// </summary>/// <param name="factory">The factory.</param>public Logger(ILoggerFactory factory){if (factory == null){throw new ArgumentNullException(nameof(factory));}_logger = factory.CreateLogger(TypeNameHelper.GetTypeDisplayName(typeof(T)));}IDisposable ILogger.BeginScope<TState>(TState state){return _logger.BeginScope(state);}bool ILogger.IsEnabled(LogLevel logLevel){return _logger.IsEnabled(logLevel);}void ILogger.Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter){_logger.Log(logLevel, eventId, state, exception, formatter);} }

    可以看到,在 Logger 其實(shí)是一種簡(jiǎn)寫形式,使用泛型的方式來獲取 categoryName,最后還是調(diào)用了 factory.CreateLogger。

    總結(jié)

    本章主要講解了 ILogger 的創(chuàng)建,過濾一系列過程,主要關(guān)注的是 Logger 的實(shí)現(xiàn)方式,而到此對(duì) ASP.NET Core Logging 系統(tǒng)也有了一個(gè)基本的了解,在我們的應(yīng)用程序中對(duì) Logging 的配置和使用也算是游刃有余。而下一章則會(huì)介紹了一下 LoggerProvider 的實(shí)現(xiàn)以及如何自己來寫一個(gè) LoggerProvider。

    轉(zhuǎn)載于:https://www.cnblogs.com/RainingNight/p/asp-net-core-logging-logger.html

    總結(jié)

    以上是生活随笔為你收集整理的ASP.NET Core 源码学习之 Logging[3]:Logger的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。