zoukankan      html  css  js  c++  java
  • [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));
            }
        }
  • 相关阅读:
    论文阅读 | Spatial Transformer Networks
    Latex的各种帽子
    SiamFC网络影响
    Faster RCNN Tensorflow在测试时得到的result.txt文件
    ubuntu16.04使用docker部署TFserving之安装docker
    ubuntu系统使用Faster RCNN训练自己的数据集
    pandas基础1数据结构介绍
    numpy基础4线性代数等
    numpy基础3通用函数等
    numpy基础2索引和切片
  • 原文地址:https://www.cnblogs.com/watermoon2/p/4554808.html
Copyright © 2011-2022 走看看