• [Asp.net 5] Logging-其他日志系统的实现


    Microsoft.Framework.Logging.NLog

    使用Nlog扩展日志系统:按照我们上节说的,对于扩展的日志系统都要实现俩个接口ILogger、ILoggerProvider。所以在当前工程中也没例外,NLogLoggerProvider实现了ILoggerProvider、内部类Logger实现了ILogger。源代码如下:

    public class NLogLoggerProvider : ILoggerProvider
        {
            private readonly LogFactory _logFactory;
    
            public NLogLoggerProvider(LogFactory logFactory)
            {
                _logFactory = logFactory;
            }
    
            public ILogger CreateLogger(string name)
            {
                return new Logger(_logFactory.GetLogger(name));
            }
    
            private class Logger : ILogger
            {
                private readonly global::NLog.Logger _logger;
    
                public Logger(global::NLog.Logger logger)
                {
                    _logger = logger;
                }
    
                public void Log(
                    LogLevel logLevel,
                    int eventId,
                    object state,
                    Exception exception,
                    Func<object, Exception, string> formatter)
                {
                    var nLogLogLevel = GetLogLevel(logLevel);
                    var message = string.Empty;
                    if (formatter != null)
                    {
                        message = formatter(state, exception);
                    }
                    else
                    {
                        message = LogFormatter.Formatter(state, exception);
                    }
                    if (!string.IsNullOrEmpty(message))
                    {
                        var eventInfo = LogEventInfo.Create(nLogLogLevel, _logger.Name, message, exception);
                        eventInfo.Properties["EventId"] = eventId;
                        _logger.Log(eventInfo);
                    }
                }
    
                public bool IsEnabled(LogLevel logLevel)
                {
                    return _logger.IsEnabled(GetLogLevel(logLevel));
                }
    
                private global::NLog.LogLevel GetLogLevel(LogLevel logLevel)
                {
                    switch (logLevel)
                    {
                        case LogLevel.Verbose: return global::NLog.LogLevel.Debug;
                        case LogLevel.Information: return global::NLog.LogLevel.Info;
                        case LogLevel.Warning: return global::NLog.LogLevel.Warn;
                        case LogLevel.Error: return global::NLog.LogLevel.Error;
                        case LogLevel.Critical: return global::NLog.LogLevel.Fatal;
                    }
                    return global::NLog.LogLevel.Debug;
                }
    
                public IDisposable BeginScopeImpl([NotNull] object state)
                {
                    return NestedDiagnosticsContext.Push(state.ToString());
                }
            }
        }
    NLog

    这段代码很容易读懂,也就不过多解释了,需要注意的一点是:LogFactory是NLog的工厂。
    下面我们主要就NLog和大名鼎鼎的Log4net进行比较(道听途说比较多,欢迎指正)

    • 都不建议直接使用,使用门面类包装(也就是相当于本处的Microsoft.Framework.Logging.NLog的内部Logger类实际是Nlog的log的门面)
    • 如果现在系统使用了日志系统,建议使用原有的日志系统(应用log4net比较多),完全新的项目建议使用Nlog
    • 从初始化配置上看Nlog要比log4net简单
    • 从功能强大度上,基本可以平分秋色
    • 从开源代码更新程度上看:Nlog以及在github上开源(https://github.com/nlog)、log4net在Apache上开源(http://logging.apache.org/log4net/download_log4net.cgi)。但是Nlog还有更新,支持的.net版本也比较多;log4net感觉好久没更新了,核心版本还是.net2.0(此处不是道听途说,是楼猪自己下载源码得倒的结论)
    • 据说使用同步记录日志时log4net比Nlog要快,但是Nlog可以开启异步记录,并且速度会反超log4net

    下面是楼主参考的一些博文

    测试代码:

    <?xml version="1.0" encoding="utf-8" ?>
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          autoReload="true">
    
      <targets>
        <target name="logfile" 
                xsi:type="File" 
                fileName="file.txt" 
                layout="${longdate}|${level:uppercase=true}|${logger}|${event-context:item=EventId}|${message}|${ndc}" />
        <target name="console" 
                xsi:type="ColoredConsole" 
                layout="[${level:uppercase=true}:${logger}] ${message}"/>
      </targets>
    
      <rules>
        <logger name="*" minlevel="Info" writeTo="logfile,console" />
      </rules>
    </nlog>
            public Program()
            {
                // a DI based application would get ILoggerFactory injected instead
                var factory = new LoggerFactory();
    
                // getting the logger immediately using the class's name is conventional
                _logger = factory.CreateLogger(typeof(Program).FullName);
    
                // providers may be added to an ILoggerFactory at any time, existing ILoggers are updated
    #if !DNXCORE50
                factory.AddNLog(new global::NLog.LogFactory());
    #endif
                factory.AddConsole();
                factory.AddConsole((category, logLevel) => logLevel >= LogLevel.Critical && category.Equals(typeof(Program).FullName));
            }

    Microsoft.Framework.Logging.Console

    实际上用控制台直接写日志的并不多,所以这个日志系统可能用途并不广,不过精炼的代码还是有很多可圈可点的地方:使用IConsole接口以及LogConsole类。我们一般来说肯定只会实现ILogger、ILoggerProvider俩个接口,也就是写实现类ConsoleLogger、ConsoleLoggerProvider。但是我们主要到ConsoleLogger只是负责记录的逻辑操作,具体对于介质的操作属于IConsole的职责,如果将ConsoleLogger与LogConsole柔和在一起,问题也不大;但是明显违反了面向对象设计的单一职责原则。所以麻雀虽小,五脏俱全,这几个小类也能体现面向对象的能力的。

    Microsoft.Framework.Logging.TraceSource

    这个对于我来说是个陌生的东西,虽然是.net自带的,并且从1.0就有了。最开始使用的时Debug和Trace进行跟踪、记录,到.net2.0时,使用TraceSource作为Debug和Trace的增强版本。

    TraceSource的配置:

    • Listeners:控制跟踪信息输出的方向(可以是:TextWriterTraceListener,DefaultTraceListener,EventLogTraceListener,WebPageTraceListener等,而TextWriterTraceListener的子类又有ConsoleTraceListener, DelimitedListTraceListener,XmlWriterTraceListener,EventSchemaTraceListener)
    • Switch:筛选信息的开关,主要包括BooleanSwitch 类、TraceSwitch 类和 SourceSwitch 类

    主要参考的文献:

    我们回头看Microsoft.Framework.Logging.TraceSource代码,也就一目了然了.

        public class TraceSourceLoggerProvider : ILoggerProvider
        {
            private readonly SourceSwitch _rootSourceSwitch;
            private readonly TraceListener _rootTraceListener;
    
            private readonly ConcurrentDictionary<string, TraceSource> _sources = new ConcurrentDictionary<string, TraceSource>(StringComparer.OrdinalIgnoreCase);
    
            public TraceSourceLoggerProvider([NotNull]SourceSwitch rootSourceSwitch, [NotNull]TraceListener rootTraceListener)
            {
                _rootSourceSwitch = rootSourceSwitch;
                _rootTraceListener = rootTraceListener;
            }
    
            public ILogger CreateLogger(string name)
            {
                return new TraceSourceLogger(GetOrAddTraceSource(name));
            }
    
            private TraceSource GetOrAddTraceSource(string name)
            {
                return _sources.GetOrAdd(name, InitializeTraceSource);
            }
    
            private TraceSource InitializeTraceSource(string traceSourceName)
            {
                var traceSource = new TraceSource(traceSourceName);
                string parentSourceName = ParentSourceName(traceSourceName);
    
                if (string.IsNullOrEmpty(parentSourceName))
                {
                    if (HasDefaultSwitch(traceSource))
                    {
                        traceSource.Switch = _rootSourceSwitch;
                    }
    
                    if (_rootTraceListener != null)
                    {
                        traceSource.Listeners.Add(_rootTraceListener);
                    }
                }
                else
                {
                    if (HasDefaultListeners(traceSource))
                    {
                        TraceSource parentTraceSource = GetOrAddTraceSource(parentSourceName);
                        traceSource.Listeners.Clear();
                        traceSource.Listeners.AddRange(parentTraceSource.Listeners);
                    }
    
                    if (HasDefaultSwitch(traceSource))
                    {
                        TraceSource parentTraceSource = GetOrAddTraceSource(parentSourceName);
                        traceSource.Switch = parentTraceSource.Switch;
                    }
                }
    
                return traceSource;
            }
    
            private static string ParentSourceName(string traceSourceName)
            {
                int indexOfLastDot = traceSourceName.LastIndexOf('.');
                return indexOfLastDot == -1 ? null : traceSourceName.Substring(0, indexOfLastDot);
            }
    
            private static bool HasDefaultListeners(TraceSource traceSource)
            {
                return traceSource.Listeners.Count == 1 && traceSource.Listeners[0] is DefaultTraceListener;
            }
    
            private static bool HasDefaultSwitch(TraceSource traceSource)
            {
                return string.IsNullOrEmpty(traceSource.Switch.DisplayName) == string.IsNullOrEmpty(traceSource.Name) &&
                    traceSource.Switch.Level == SourceLevels.Off;
            }
        }
    TraceSourceLoggerProvider
        internal class TraceSourceLogger : ILogger
        {
            private readonly TraceSource _traceSource;
    
            public TraceSourceLogger(TraceSource traceSource)
            {
                _traceSource = traceSource;
            }
    
            public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
            {
                if (!IsEnabled(logLevel))
                {
                    return;
                }
                var message = string.Empty;
                if (formatter != null)
                {
                    message = formatter(state, exception);
                }
                else
                {
                    if (state != null)
                    {
                        message += state;
                    }
                    if (exception != null)
                    {
                        message += Environment.NewLine + exception;
                    }
                }
                if (!string.IsNullOrEmpty(message))
                {
                    _traceSource.TraceEvent(GetEventType(logLevel), eventId, message);
                }
            }
    
            public bool IsEnabled(LogLevel logLevel)
            {
                var traceEventType = GetEventType(logLevel);
                return _traceSource.Switch.ShouldTrace(traceEventType);
            }
    
            private static TraceEventType GetEventType(LogLevel logLevel)
            {
                switch (logLevel)
                {
                    case LogLevel.Critical: return TraceEventType.Critical;
                    case LogLevel.Error: return TraceEventType.Error;
                    case LogLevel.Warning: return TraceEventType.Warning;
                    case LogLevel.Information: return TraceEventType.Information;
                    case LogLevel.Verbose:
                    default: return TraceEventType.Verbose;
                }
            }
    
            public IDisposable BeginScopeImpl(object state)
            {
                return new TraceSourceScope(state);
            }
        }
    TraceSourceLogger
            [Fact]
            public static void IsEnabledReturnsCorrectValue()
            {
                // Arrange
                var testSwitch = new SourceSwitch("TestSwitch", "Level will be set to warning for this test");
                testSwitch.Level = SourceLevels.Warning;
    
                var factory = new LoggerFactory();
                var logger = factory.CreateLogger("Test");
    
                // Act
                factory.AddTraceSource(testSwitch, new ConsoleTraceListener());
    
                // Assert
                Assert.True(logger.IsEnabled(LogLevel.Critical));
                Assert.True(logger.IsEnabled(LogLevel.Error));
                Assert.True(logger.IsEnabled(LogLevel.Warning));
                Assert.False(logger.IsEnabled(LogLevel.Information));
                Assert.False(logger.IsEnabled(LogLevel.Verbose));
            }
    
            [Theory]
            [InlineData(SourceLevels.Warning, SourceLevels.Information, true)]
            [InlineData(SourceLevels.Information, SourceLevels.Information, true)]
            [InlineData(SourceLevels.Information, SourceLevels.Warning, true)]
            [InlineData(SourceLevels.Warning, SourceLevels.Warning, false)]
            public static void MultipleLoggers_IsEnabledReturnsCorrectValue(SourceLevels first, SourceLevels second, bool expected)
            {
                // Arrange
                var firstSwitch = new SourceSwitch("FirstSwitch", "First Test Switch");
                firstSwitch.Level = first;
    
                var secondSwitch = new SourceSwitch("SecondSwitch", "Second Test Switch");
                secondSwitch.Level = second;
    
                var factory = new LoggerFactory();
                var logger = factory.CreateLogger("Test");
    
                // Act
                factory.AddTraceSource(firstSwitch, new ConsoleTraceListener());
                factory.AddTraceSource(secondSwitch, new ConsoleTraceListener());
    
                // Assert
                Assert.Equal(expected, logger.IsEnabled(LogLevel.Information));
            }
        }
  • 相关阅读:
    hdu 4521 小明系列问题——小明序列(线段树 or DP)
    hdu 1115 Lifting the Stone
    hdu 5476 Explore Track of Point(2015上海网络赛)
    Codeforces 527C Glass Carving
    hdu 4414 Finding crosses
    LA 5135 Mining Your Own Business
    uva 11324 The Largest Clique
    hdu 4288 Coder
    PowerShell随笔3 ---别名
    PowerShell随笔2---初始命令
  • 原文地址:https://www.cnblogs.com/watermoon2/p/4554808.html
Copyright © 2020-2023  润新知