M.E.Logging Deep Dive

1 Overview

上周在工作中为 SDK 增加了 M.E.Logging 的支持,由于是为 Legacy 的代码中增加日志功能,所以遇到了一些挑战,主要有:

2. ILogger/ILoggerProvider/ILoggerFactory

API 定义上来看,三者之间的关系如下

3. Logger

M.E.Logging 包中定义了一个 内部类型 Logger ,它是 LoggerFactory 类的CreateLogger(string categoryName) 方法返回的对象。刚刚的分析我们知道,该对象包含了所有 LoggerProvider 创建的对象。

  • MessageLogger[] 该数组对象仍然包含了 Logger 对象,不过包含了 MinLevel 以及 Func<string, string, LogLevel, bool> 该委托主要是用来判断某个 ProviderType, CategoryLevel 是否 IsEnabled. 它盘的判断逻辑是首先和 MinLevel 进行判断,然后调用 Filter 委托来判断该条记录是否值得输出,否则返回 true
  • ScopLogger[] 主要是为了日志范围使用,暂时先不讨论。

4. LoggerFactory

LoggerFactoryILoggerFactory 的默认实现,几乎所有的细节都隐藏在这些类中。

  • List<ProviderRegistration> _providerRegistrations 这个保存了所有注册的 ILoggerProvider ,但是这里封装成了 ProviderRegistration 对象,主要原因是 如果 ILoggerFactory 是从依赖注入的容器中获取的,那么 LoggerProvider 就应当不会随着 ILoggerFactory 的释放而释放,对于通过 AddProvider 方法加入的 LoggerProvider 则在释放的时候释放。

5. FilterOptions/FilterRule

Logger 并不是将所有的日志都会输出,而是只有满足要输出日志的 Level 大于 MinLevel 的日志才会得到输出。

  • MinLevel 默认的最小 Level
  • List<LoggerFilterRule> Rules 为不同的 CategoryName, ProviderType 定义的规则集合
  • CategoryName 特定 CategoryName 匹配的条件
  • LogLevel 匹配条件的 level
  • Func<string, string, LogLevel, bool> 委托, 根据不同的条件配置不同的 IsEnabled 的结果。
  1. 筛选最长匹配的 Category 的规则
  2. 筛选最后一个有 levelfilter 的规则
  3. 使用默认的 level

6 Scope

Scope 是一个非常有趣的概念,我们知道我们的日志的输出的顺序的不做任何保证的,比如采用远程之类的 LoggerProvider , 网络的延迟肯定不会保证日志顺序按照程序执行的顺序。

  1. LoggerExternalScopeProvider 中的 Push 方法,先创建目前的 state 创建一个 Scope ,让将这个 scope 作为当前值返回,而 Scope 对象的 Dispose 方法则将 parent 的值作为当前的值; ForEachScope 方法则从当前值依次迭所有 Scope中的 State 值。
  2. LoggerBeginScope 方法中,创建了一个 Scope 类型,该类型包含了 IDispose 的数组,进入方法的时候,调用 Push 方法,将这个 TState 保存到当前的 context 中。在 Scope 调用 Dispose 方法的时候。

A software developer in Microsoft at Suzhou. Most articles spoken language is Chinese. I will try with English when I’m ready

A software developer in Microsoft at Suzhou. Most articles spoken language is Chinese. I will try with English when I’m ready