[Asp.net 5] Logging-日志系统的基本架构(上)
本节主要介绍解决方案中的Microsoft.Framework.Logging.Abstractions、Microsoft.Framework.Logging俩个工程。
这俩个工程中所有类的关系如下图所示:
首先我们可以发现处于核心的是中间的四个接口:ILogger、ILoggerFactory、ILoggerProvider、ILogValues。
- ILogger:记录日志的接口,所以写日志的类都该实现该接口,工程中有俩个类实现了该接口:Logger、Logger<T>
- ILoggerFactory:创建ILogger的工厂。负责创建工厂的逻辑,但是一般不直接创建,而是调用内部ILoggerProvider去完成。
- ILoggerProvider:能够直接创建ILogger实例,做为属性添加到ILoggerFactory中,ILogger的具体逻辑受控制ILoggerFactory。
- ILogValues:在Logger的扩展方法中作为特殊类型的object传入,作为日志的数据源。
接口的定义源码如下:
public interface ILogger { void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter); bool IsEnabled(LogLevel logLevel); IDisposable BeginScopeImpl(object state); }
public interface ILoggerFactory { LogLevel MinimumLevel { get; set; } ILogger CreateLogger(string categoryName); void AddProvider(ILoggerProvider provider); }
public interface ILoggerProvider { ILogger CreateLogger(string name); }
public interface ILogValues { IEnumerable<KeyValuePair<string, object>> GetValues(); }
ILogger以及实现类
ILogger接口、ILogger<TCategoryName>(没有任何定义)、Logger<T>这种泛型继承是否有相识之感,之前的博客文章中已经对于这种情况有所介绍([Asp.net 5] Localization-resx资源文件的管理中IStringLocalizer 、IStringLocalizer<T> 、StringLocalizer<TResourceSource>是一致的)。实际Logger<T>中T是ILogger的实例子类,实际就是使用代理模式,内部包含ILogger实例,并且所有对外的方法都仅仅是内部ILogger实例的封装。
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) { _logger = factory.CreateLogger<T>(); } IDisposable ILogger.BeginScopeImpl(object state) { return _logger.BeginScopeImpl(state); } bool ILogger.IsEnabled(LogLevel logLevel) { return _logger.IsEnabled(logLevel); } void ILogger.Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter) { _logger.Log(logLevel, eventId, state, exception, formatter); } }
Logger类同样实现了ILogger接口,也同样使用了代理模式,不过不同于Logger<T>泛型,Logger类有自己的内部逻辑。而是在内部封装了 ILogger[] _loggers对象。使得Logger更像LoggerManage。但是由于Logger同样实现Logger接口,所以Logger类是管理其它Logger类的代理。而Logger内部的_loggers是通过LoggerFactory对象封装的。当记录日志时,依次遍历内部的 _loggers对象,进行写日志操作。
internal class Logger : ILogger { private readonly LoggerFactory _loggerFactory; private readonly string _name; private ILogger[] _loggers = new ILogger[0]; public Logger(LoggerFactory loggerFactory, string name) { _loggerFactory = loggerFactory; _name = name; var providers = loggerFactory.GetProviders(); _loggers = new ILogger[providers.Length]; for (var index = 0; index != providers.Length; index++) { _loggers[index] = providers[index].CreateLogger(name); } } public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter) { if (logLevel >= _loggerFactory.MinimumLevel) { foreach (var logger in _loggers) { logger.Log(logLevel, eventId, state, exception, formatter); } } } public bool IsEnabled(LogLevel logLevel) { if (logLevel < _loggerFactory.MinimumLevel) { return false; } foreach (var logger in _loggers) { if (logger.IsEnabled(logLevel)) { return true; } } return false; } public IDisposable BeginScopeImpl(object state) { var loggers = _loggers; var scope = new Scope(loggers.Length); for (var index = 0; index != loggers.Length; index++) { scope.SetDisposable(index, loggers[index].BeginScopeImpl(state)); } return scope; } internal void AddProvider(ILoggerProvider provider) { var logger = provider.CreateLogger(_name); _loggers = _loggers.Concat(new[] { logger }).ToArray(); } private class Scope : IDisposable { private bool _isDisposed; private IDisposable _disposable0; private IDisposable _disposable1; private readonly IDisposable[] _disposable; public Scope(int count) { if (count > 2) { _disposable = new IDisposable[count - 2]; } } public void SetDisposable(int index, IDisposable disposable) { if (index == 0) { _disposable0 = disposable; } else if (index == 1) { _disposable1 = disposable; } else { _disposable[index - 2] = disposable; } } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (disposing) { if (_disposable0 != null) { _disposable0.Dispose(); } if (_disposable1 != null) { _disposable1.Dispose(); } if (_disposable != null) { var count = _disposable.Length; for (var index = 0; index != count; ++index) { if (_disposable[index] != null) { _disposable[index].Dispose(); } } } } _isDisposed = true; } } // This code added to correctly implement the disposable pattern. public void Dispose() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); // TODO: tell GC not to call its finalizer when the above finalizer is overridden. // GC.SuppressFinalize(this); } internal void Add(IDisposable disposable) { throw new NotImplementedException(); } } }
ILoggerFactory以及实现类
ILoggerFactory主要有俩个作用,添加新的ILoggerProvider,创建ILogger。而ILoggerFactory的唯一实现类LoggerFactory,简单实现了上面两个功能,并且在LoggerFactory内部额外维护_loggers副本,该处loggers都是Logger类型(非泛型),只是categoryName不同。所以通过LoggerFactory创建的Logger如下图所示:
public class LoggerFactory : ILoggerFactory { private readonly Dictionary<string, Logger> _loggers = new Dictionary<string, Logger>(StringComparer.Ordinal); private ILoggerProvider[] _providers = new ILoggerProvider[0]; private readonly object _sync = new object(); public ILogger CreateLogger(string categoryName) { Logger logger; lock (_sync) { if (!_loggers.TryGetValue(categoryName, out logger)) { logger = new Logger(this, categoryName); _loggers[categoryName] = logger; } } return logger; } public LogLevel MinimumLevel { get; set; } = LogLevel.Verbose; public void AddProvider(ILoggerProvider provider) { lock (_sync) { _providers = _providers.Concat(new[] { provider }).ToArray(); foreach (var logger in _loggers) { logger.Value.AddProvider(provider); } } } internal ILoggerProvider[] GetProviders() { return _providers; } }