[Asp.net 5] Logging-日志系统的基本架构(上)

8/10/2015来源:ASP.NET技巧人气:1686

[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);    }
ILogger
    public interface ILoggerFactory    {        LogLevel MinimumLevel { get; set; }        ILogger CreateLogger(string categoryName);        void AddProvider(ILoggerProvider provider);    }
ILoggerFactory
    public interface ILoggerProvider    {        ILogger CreateLogger(string name);    }
ILoggerProvider
    public interface ILogValues    {        IEnumerable<KeyValuePair<string, object>> GetValues();    }
ILogValues

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

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)            {