日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

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

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

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

LoggerFactory

我們可以在構(gòu)造函數(shù)中注入 ILoggerFactory,來(lái)創(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 中的代碼較多,我們慢慢來(lái)看:

首先是構(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); }

看到這里不得不先說(shuō)一下 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)建出來(lái)的 Logger 集合。

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

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,這便是我們上一章中所配置的過(guò)濾器的用武之地了。

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)單說(shuō)一下其過(guò)濾規(guī)則的選擇順序:

  • 首先查找指定了 ProviderName 并與當(dāng)且 Provider的名稱(Alias)相同的過(guò)濾規(guī)則,如果沒(méi)有,則選用未指定 ProviderName 的過(guò)濾規(guī)則。
  • 選擇指定的 CategoryName 相符合的過(guò)濾規(guī)則,如果沒(méi)有,則選擇未指定 CategoryName 的那一條。
  • 如果符合的規(guī)則有多條,則選用最后一條。
  • 如果未找到相符合的規(guī)則,則使用全局的最小過(guò)濾級(jí)別。
  • 而且我們可以看到,LoggerInformation 帶有 MinLeve 屬性和 Filter 委托兩種過(guò)濾配置,而這兩種配置的來(lái)源,在上一章中可以看到,分別是從配置文件(AddConfiguration)和直接使用委托(AddFilter)來(lái)進(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ú)需多說(shuō),通過(guò)上面的 IsEnabled 方法能夠清楚的看到,先使用 MinLevel 過(guò)濾,再使用 Filter 進(jìn)行過(guò)濾。

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

    ILogger

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

    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)寫(xiě)形式,使用泛型的方式來(lái)獲取 categoryName,最后還是調(diào)用了 factory.CreateLogger。

    總結(jié)

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

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