[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)
            {
                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();
            }
        }
    }
Logger

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;
        }
    }
LoggerFactory

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM