• .NET .Core 选择日志框架


    先来介绍.NET中三种最受欢迎​​的日志记录框架:log4net,NLog和Serilog。

    一、Log4net

    1、Log4net概述

      Log4Net有四种主要的组件,分别是Logger(记录器),Repository(库),Appender(附着器)以及 Layout(布局)

    • Logger记录器

      Logger是应用程序需要交互的主要组件,它用来产生日志消息。产生的日志消息并不直接显示,还要预先经过Layout的格式化处理后才会输出。Logger提供了多种方式来记录一个日志消息,你可以在你的应用程序里创建多个Logger,每个实例化的Logger对象都被log4net框架作为命名实体(named entity)来维护,这意味着为了重用Logger对象,可以将Logger对象当做参数使用。Log4net框架定义了一个ILog接口,所有的logger类都必须实现这个接口。如果你想实现一个自定义的logger,你必须首先实现这个接口。Log4Net框架定义了一个叫做LogManager的类,用来管理所有的logger对象。它有一个GetLogger()静态方法,用我们提供的名字参数来检索已经存在的Logger对象。如果框架里不存在该Logger对象,它也会为我们创建一个Logger对象。 

    • Repository库

      Repository主要用于负责日志对象组织结构的维护。

    • Appender(附着器)

      Appender决定日志输出的媒介。主要包括以下几种:

      • AnsiColorTerminalAppender:在ANSI 窗口终端写下高亮度的日志事件。
      • AspNetTraceAppender:能用asp.net中Trace的方式查看记录的日志。
      • BufferingForwardingAppender:在输出到子Appenders之前先缓存日志事件。
      • ConsoleAppender:将日志输出到控制台。
      • EventLogAppender:将日志写到Windows Event Log. 
      • FileAppender:将日志写到文件中。
      • LocalSyslogAppender:将日志写到local syslog service (仅用于UNIX环境下). 
      • MemoryAppender:将日志存到内存缓冲区。
      • NetSendAppender:将日志输出到Windows Messenger service.这些日志信息将在用户终端的对话框中显示。
      • RemoteSyslogAppender:通过UDP网络协议将日志写到Remote syslog service。
      • RemotingAppender:通过.NET Remoting将日志写到远程接收端。
      • RollingFileAppender:将日志以回滚文件的形式写到文件中。(实例代码中使用的是此类型)
      • SmtpAppender:将日志写到邮件中。
      • TraceAppender:将日志写到.NET trace 系统。
      • UdpAppender:将日志connectionless UDP datagrams的形式送到远程宿主或以UdpClient的形式广播。   
    • root

      Appender和root经常搭配使用,root用来对设置输出的方式进行指定。
    <root>
        <!--批定DEBUG输出的文件形式记录日志-->
        <level value="DEBUG"/>
        <appender-ref ref="Log4Net_ERROR" />
      
      <!--批定INFO输出的文件形式记录日志-->
        <level value="INFO"/>
        <appender-ref ref="Log4Net_INFO" />
    </root>
    • Appender Filters过滤器

      Appender的过滤器(Appender Filters) 可以按照不同的标准过滤日志事件。在log4net.Filter的名字空间下已经有几个预定义的过滤器。使用这些过滤器,你可以按照日志级别范围过滤日志事件,或者按照某个特殊的字符串进行过滤。过滤器通常有以下几种:

      • DenyAllFilter 阻止所有的日志事件被记录
      • LevelMatchFilter 只有指定等级的日志事件才被记录
      • LevelRangeFilter 日志等级在指定范围内的事件才被记录
      • LoggerMatchFilter 与Logger名称匹配,才记录
      • PropertyFilter 消息匹配指定的属性值时才被记录
      • StringMathFilter 消息匹配指定的字符串才被记录
    • Layout布局

      Layout 组件用于向用户显示最后经过格式化的输出信息。输出信息可以以多种格式显示,主要依赖于我们采用的Layout组件类型。可以是线性的或一个XML文件。Layout组件和一个Appender组件一起工作。API帮助手册中有关于不同Layout组件的列表。一个Appender对象,只能对应一个Layout对象。要实现你自己的Layout类,你需要从log4net.Layout.LayoutSkeleton类继承,它实现了ILayout接口。一个Appender只能有一个Layout。最常用的Layout应该是经典格式的PatternLayout,其次是SimpleLayout,RawTimeStampLayout和ExceptionLayout。然后还有IRawLayout,XMLLayout等几个使用较少。Layout可以自己实现,需要从log4net.Layout.LayoutSkeleton类继承,来输出一些特殊需要的格式,在后面扩展时就重新实现了一个Layout。

        • SimpleLayout简单输出格式,只输出日志级别与消息内容。
        • RawTimeStampLayout 用来格式化时间,在向数据库输出时会用到。样式如“yyyy-MM-dd HH:mm:ss“
        • ExceptionLayout需要给Logger的方法传入Exception对象作为参数才起作用,否则就什么也不输出。输出的时候会包含Message和Trace。
        • PatterLayout使用最多的一个Layout,能输出的信息很多
    • 配置文件说明

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <configSections>
        <!--添加自定义节点:log4net  type:解析类名,程序集名(log4net.dll)-->
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
      </configSections>
    
      <log4net>
        <!--定义输出到文件中-->
        <appender name="Log4Net_INFO" type="log4net.Appender.RollingFileAppender">
          <!--定义文件存放位置-->
          <file value="C:/log4net/"/>
          <!--是否追加到文件,默认为true,通常无需设置-->
          <appendToFile value="true"/>
          <RollingStyle value="Date"/>
          <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
          <DatePattern value="INFO_yyyyMMdd".log"" />
          <!--日志文件名是否为静态-->
          <StaticLogFileName value="false"/>
          <!--多线程时采用最小锁定-->
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <!--布局(向用户显示最后经过格式化的输出信息)-->
          <layout type="log4net.Layout.PatternLayout">
            <!--
               %m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息 
               %n(new line):换行 
               %d(datetime):输出当前语句运行的时刻 
               %r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数 
               %t(thread id):当前语句所在的线程ID 
               %p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等 
               %c(class):当前日志对象的名称,例如:
               %L:输出语句所在的行号 
               %F:输出语句所在的文件名 
               %-数字:表示该项的最小长度,如果不够,则用空格填充
              -->
            <Header value="[Header]
    "/>
            <Footer value="[Footer]
    "/>
            <!--正文-->
            <ConversionPattern value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 出错类:%logger property:[%property{NDC}] - 错误描述:%message%newline"  />
          </layout>
        </appender>
    
        <appender name="Log4Net_ERROR" type="log4net.Appender.RollingFileAppender">
          <file value="C:/log4net/"/>
          <appendToFile value="true"/>
          <RollingStyle value="Date"/>
          <DatePattern value="ERROR_yyyyMMdd".log"" />
          <StaticLogFileName value="false"/>
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <layout type="log4net.Layout.PatternLayout">
            <Header value="[Header]
    "/>
            <Footer value="[Footer]
    "/>
            <!--正文-->
            <ConversionPattern value="记录时间:%date 线程ID:[%thread] 日志级别:%-5level 出错类:%logger property:[%property{NDC}] - 错误描述:%message%newline"  />
          </layout>
        </appender>
    
        <root>
          <level value="DEBUG"/>
          <appender-ref ref="Log4Net_ERROR" />
    
          <level value="INFO"/>
          <appender-ref ref="Log4Net_INFO" />
        </root>
    
      </log4net>
    
    </configuration>

    2、自定义Logger示例

    定义一个类库Log4netManager,通过nuget引用log4net组件,类库结构如下:

    ELogLevel.cs代码如下:

    namespace Log4netManager
    {
        public enum ELogLevel
        {
            /// <summary>
            /// 错误信息
            /// </summary>
            Error=1,
            /// <summary>
            /// 跟踪信息
            /// </summary>
            Trace=2,
            /// <summary>
            /// 调试信息
            /// </summary>
            Debug=3,
            /// <summary>
            /// 记录信息
            /// </summary>
            Info=4
        }
    }
    

    ILog.cs代码如下:

    using System;
    
    namespace Log4netManager
    {
        public interface ILog:IDisposable
        {
            void LogWithTime(string msg, ELogLevel logLevel = ELogLevel.Error);
            bool Enabled { get; set; }
        }
    }

    FileLogger.cs代码如下:

    using System;
    using System.Diagnostics;
    using System.IO;
    
    namespace Log4netManager
    {
        public class FileLogger : ILog
        {
            private string _configLevel = null;
            private bool _enabled = true;
            private log4net.ILog _log = null;
            public FileLogger()
            {
                this._configLevel = GetAppSettingValue("LogLevel");
                string logName = GetAppSettingValue("LogName");
                string configPath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "log4net.xml");
                log4net.Config.XmlConfigurator.Configure(new FileInfo(configPath));
                this._log = log4net.LogManager.GetLogger(logName);
            }
    
            public static string GetAppSettingValue(string key)
            {
                string value = null;
                foreach (string item in System.Configuration.ConfigurationManager.AppSettings)
                {
                    if (item.Equals(key, System.StringComparison.CurrentCultureIgnoreCase))
                    {
                        value = System.Configuration.ConfigurationManager.AppSettings[key];
                        break;
                    }
                }
                return value;
            }
    
            #region ILog成员
            public void LogWithTime(string msg, ELogLevel logLevel)
            {
                if (string.IsNullOrWhiteSpace(msg) || !this._enabled)
                {
                    return;
                }
    #if DEBUG
                Trace.TraceInformation(msg);
    #endif
                if (string.IsNullOrWhiteSpace(this._configLevel))
                {
                    this._configLevel = ((int)ELogLevel.Error).ToString();
                }
                int configLevel = Convert.ToInt32(this._configLevel);
                if ((int)logLevel < configLevel)
                {
                    try
                    {
                        switch (logLevel)
                        {
                            case ELogLevel.Error:
                                this._log.Error(msg);
                                break;
                            case ELogLevel.Trace:
                                this._log.Warn(msg);
                                break;
                            case ELogLevel.Debug:
                                this._log.Debug(msg);
                                break;
                            case ELogLevel.Info:
                                this._log.Info(msg);
                                break;
                            default:
                                break;
                        }
                    }
                    catch
                    {
                    }
                }
            }
            public bool Enabled
            {
                get { return this._enabled; }
                set { this._enabled = value; }
            }
            #endregion
    
            #region IDisposable
            public void Dispose()
            { }
            #endregion 
        }
    }

    OK,接下来使用下我们自定义的Logger,先建立一个控制台项目,引入刚刚自定义的Log4netManager类库,结构如下:

    App.config代码:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
        </startup>
      <appSettings>
        <add key="LogName" value="TestConsole"/>
        <add key="LogLevel" value="4"/>
      </appSettings>
    </configuration>

    log4net.xml如下:

    <?xml version="1.0" encoding="utf-8" ?>
    <log4net debug="true">
      <appender name="FlatFile" type="log4net.Appender.RollingFileAppender,log4net">
        <param name="File" value="logs/website.log" />
        <param name="Encoding" value="utf-8" />
        <param name="AppendToFile" value="true" />
        <param name="RollingStyle" value="Date" />
        <param name="ImmediateFlush" value="true" />
        <param name="MaximumFileSize" value="50MB"/>
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
        <param name="DatePattern" value="-yyyy.MM.dd'.log'" />
        <param name="StaticLogFileName" value="true" />
        <layout type="log4net.Layout.PatternLayout,log4net">
          <param name="ConversionPattern" value="%-5level [%logger] - %message [%date] %newline" />
        </layout>
      </appender> 
      <root>
        <priority value="DEBUG" />
        <appender-ref ref="FlatFile" />
      </root>  
    </log4net>

    Program.cs如下:

    using Log4netManager;
    
    namespace log4netConsole
    {
        class Program
        {
            static void Main(string[] args)
            {
                ILog _fileLogger = new FileLogger();
                _fileLogger.LogWithTime("日志测试",ELogLevel.Debug);
                System.Console.WriteLine("日志所在的位置 "+System.AppDomain.CurrentDomain.BaseDirectory);
                System.Console.ReadKey();
            }
        }
    }

    效果如下:

    3、Netcore中使用log4net

    新建一个netcore mvc项目,通过nuget引入包Microsoft.Extensions.Logging.Log4Net.AspNetCore,项目结构如下:

    Program.cs代码如下:

    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    
    namespace NetCoreLog
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureLogging((context, loggingbuilder) =>
                    {
                        loggingbuilder.AddFilter("System", LogLevel.Warning); //过滤掉系统默认的一些日志
                        loggingbuilder.AddFilter("Microsoft", LogLevel.Warning);//过滤掉系统默认的一些日志                    
                        loggingbuilder.AddLog4Net();
                    })
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    });
        }
    }

    log4net.config如下:

    <?xml version="1.0" encoding="utf-8"?>
    <log4net>
        <appender name="RollingAppender" type="log4net.Appender.RollingFileAppender">
            <!--指定日志文件保存的目录-->
            <file value="loglog.txt"/>
            <!--追加日志内容-->
            <appendToFile value="true"/>
            <!--可以为:Once|Size|Date|Composite-->
            <!--Compoosite为Size和Date的组合-->
            <rollingStyle value="Composite"/>
            <!--设置为true,当前最新日志文件名永远为file字节中的名字-->
            <staticLogFileName value="false"/>
            <!--当备份文件时,备份文件的名称及后缀名-->
            <datePattern value="yyyyMMdd.TXT"/>
            <!--日志最大个数-->
            <!--rollingStyle节点为Size时,只能有value个日志-->
            <!--rollingStyle节点为Composie时,每天有value个日志-->
            <maxSizeRollBackups value="20"/>
            <!--可用的单位:KB|MB|GB-->
            <maximumFileSize value="5MB"/>
            <filter type="log4net.Filter.LevelRangeFilter">
                <param name="LevelMin" value="ALL"/>
                <param name="LevelMax" value="FATAL"/>
            </filter>
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline"/>
            </layout>
        </appender>
        <root>
            <priority value="ALL"/>
            <level value="ALL"/>
            <appender-ref ref="RollingAppender"/>
        </root>
    </log4net>

    HomeController.cs代码如下:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using NetCoreLog.Models;
    using System.Diagnostics;
    
    namespace NetCoreLog.Controllers
    {
        public class HomeController : Controller
        {
            //ILoggerFactory和ILogger都是系统内置的接口,两个都可以写日志,使用其中之一即可
            private readonly ILogger<HomeController> _logger;
            private readonly ILoggerFactory _factory;
            public HomeController(ILogger<HomeController> logger, ILoggerFactory factory)
            {
                this._logger = logger;
                this._factory = factory;
            }
    
            public IActionResult Index()
            {
                this._factory.CreateLogger<HomeController>().LogError("记录错误信息!!!");
                this._logger.LogError("记录错误信息!");
                return View();
            }
    
            public IActionResult Privacy()
            {
                return View();
            }
    
            [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
            public IActionResult Error()
            {
                return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
            }
        }
    }

    效果如下:

    二、NLog

    1、NLog概述

    NLog是一个基于.NET平台编写的类库,我们可以使用NLog在应用程序中添加极为完善的跟踪调试代码。NLog是一个简单灵活的.NET日志记录类库。通过使用NLog,我们可以在任何一种.NET语言中输出带有上下文的(contextual information)调试诊断信息,根据喜好配置其表现样式之后发送到一个或多个输出目标(target)中。NLog遵从BSD license,即允许商业应用且完全开放源代码。任何人都可以免费使用并对其进行测试,然后通过邮件列表反馈问题以及建议。 

    • NLog和Log4net的区别

      NLog的API非常类似于log4net,且配置方式非常简单。NLog使用路由表(routing table)进行配置,但log4net却使用层次性的appender配置,这样就让NLog的配置文件非常容易阅读,并便于今后维护。

    • NLog配置介绍

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- 默认命名空间 -->
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd">
      <!-- 这个命名空间里面的元素或者属性就必须要以xsi:这种方式来写,比如schemaLocation就是他的一个属性,所以写成xsi:schemaLocation。
      而默认命名空间不带类似xsi这种;其实xml标签名称有个专业叫法叫做QName,而如果没有前面的xsi:这种一般叫做NCName -->
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      <!--表示把定义这个命名空间的schema文件给引用进来,好让开发类型工具能够解析和验证你的xml文件是否符合语法规范
      简单来说 上面是用来验证你XML格式是否正确的。-->
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      <!--一旦启动程序,这时候NLog.config文件被读取后,知道程序再启动都不会再读取配置文件了。假如我们不想停掉程序,比如说服务器哪能说停就停哈。这就用上这个配置了,这个配置功能是,一旦你对配置文件修改,程序将会重新读取配置文件,也就是自动再配置。-->
      autoReload="true"
      <!--NLog日志系统抛出异常-->
      throwExceptions="false"
      <!--日志级别 -->
      internalLogLevel="Debug"
      <!--NLog内部日志文件位置 -->
      internalLogFile="c:	emp
    log-internal.log">
      <!--variable定义配置文件中用到的变量-->
    <variable name="myvar" value="myvalue"/>
      <!--定义日志的目标/输出-->
      <targets> </targets>
      <!--定义日志的路由规则-->
      <rules> </rules>
    </nlog>

    2、NetCore中使用NLog

    新建一个netcore  mvc项目,通过nuget引入包NLog.Config和NLog.Web.AspNetCore。在引入NLog.Config包的时候,在项目根目录自动生成一个NLog.config,将该文件属性改为始终复制。项目结构如下:

    修改下NLog.config:

    <?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"
          xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
          autoReload="true"
          throwExceptions="false"
          internalLogLevel="Off" internalLogFile="c:	emp
    log-internal.log">
    
        <!-- optional, add some variables
      https://github.com/nlog/NLog/wiki/Configuration-file#variables
      -->
        <variable name="myvar" value="myvalue"/>
    
        <!--
      See https://github.com/nlog/nlog/wiki/Configuration-file
      for information on customizing logging rules and outputs.
       -->
        <targets>
    
            <!--
        add your targets here
        See https://github.com/nlog/NLog/wiki/Targets for possible targets.
        See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
        -->
    
            <!--
        Write events to a file with the date in the filename.
         -->
            <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
                    layout="${longdate} ${uppercase:${level}} ${message}" />
    
        </targets>
    
        <rules>
            <!-- add your logging rules here -->
    
            <!--
        Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace)  to "f"
        -->
            <logger name="*" minlevel="Debug" writeTo="f" />
    
        </rules>
    </nlog>

    Program.cs代码如下:

    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using NLog.Web;
    
    namespace NetCoreNlog
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    })
                    //using NLog.Web;
                    .ConfigureLogging(logging =>
                    {
                        logging.ClearProviders();
                    }).UseNLog();
        }
    }

    HomeController.cs代码如下:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using NetCoreNlog.Models;
    using System.Diagnostics;
    
    namespace NetCoreNlog.Controllers
    {
        public class HomeController : Controller
        {
            private readonly ILogger<HomeController> _logger;
    
            public HomeController(ILogger<HomeController> logger)
            {
                _logger = logger;
            }
    
            public IActionResult Index()
            {
                _logger.LogInformation("这里是日志记录");
                return View();
            }
    
            public IActionResult Privacy()
            {
                return View();
            }
    
            [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
            public IActionResult Error()
            {
                return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
            }
        }
    }

    效果如下:

    三、Serilog

    1、Serilog概述

    该系列的最新日志记录框架Serilog于2013年发布。Serilog与其他框架之间的最大区别在于,该框架旨在进行结构化的现成日志记录。

    2、Serilog示例

    这次无需任何XML配置!Serilog的配置使用流畅的界面,使其非常美观和干净。

    using Serilog;
    using System;
    namespace LoggingDemo.Serilog
    {
        class Program
        {
            static void Main(string[] args)
            {
                Log.Logger = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .WriteTo.Console()
                    .WriteTo.File("logfile.log", rollingInterval: RollingInterval.Day)
                    .CreateLogger();
                Log.Debug("Starting up");
                Log.Debug("Shutting down");
                Console.ReadLine();
            }
        }
    }
    The logging output from Serilog looks like:
    

    输出结果如下:

    2018-08-18 14:37:21.463 -06:00 [DBG] Starting up
    2018-08-18 14:37:21.560 -06:00 [DBG] Shutting down

    四、.NET .Core 使用Serilog

    最佳日志记录框架:Serilog。该API更现代,更易于设置,维护更好,并且默认情况下进行结构化日志记录。添加浓缩器的功能能够拦截和修改消息,这非常有用。

    1、在控制台项目中使用

    前提:引入Serilog.AspNetCore包

    新建一个Serilog帮助类SerilogHelper,定义两种方法,一个是将日志输出到console,一个是将日志输出到文件

    using Serilog;
    using System;
    using System.IO;
    
    namespace SerilogTest
    {
        public static class SerilogHelper
        {
            /// <summary>
            /// 输出到Console
            /// </summary>
            public static void WriteToConsole()
            {
                //日志的输出模板
                string Logformat = @"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3} {SourceContext:l}] {Message:lj}{NewLine}{Exception}";
                //类似创建一个管道
                Log.Logger = new LoggerConfiguration()
                    //设置最低等级
                    .MinimumLevel.Debug()
                    //将事件发送到控制台并展示
                    .WriteTo.Console(outputTemplate: Logformat)
                    .CreateLogger();
    
                //这里因为设置了最低等级为Debug,所以比Debug低的Verbose不会展示在控制台
                Log.Verbose("Verbose级别的日志消息");
                Log.Information("计算开始");
    
                try
                {
                    int a = 0;
                    int b = 5;
                    Log.Debug("计算两者相除");
                    Console.WriteLine(b / a);
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "计算出现意外的错误");
                }
                Log.Information("计算结束");
            }
    
            public static void WriteToFile()
            {
                var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "log.txt");
                //日志的输出模板
                string Logformat = @"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3} {SourceContext:l}] {Message:lj}{NewLine}{Exception}";
                Log.Logger = new LoggerConfiguration()
                  .MinimumLevel.Debug()
                  //该行代码表示输出到console
                  .WriteTo.Console(outputTemplate: Logformat)
                  //第一个参数是文件路径,第二个参数是输出模板的选择,第三个参数是表示程序隔多长时间新创造一个日志文件
                  .WriteTo.File(path, outputTemplate: Logformat, rollingInterval: RollingInterval.Day)
                  .CreateLogger();
    
                //这里因为设置了最低等级为Debug,所以比Debug低的Verbose不会展示在控制台
                Log.Verbose("Verbose级别的日志消息");
                Log.Information("计算开始");
    
                try
                {
                    int a = 0;
                    int b = 5;
                    Log.Debug("计算两者相除");
                    Console.WriteLine(b / a);
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "计算出现意外的错误");
                }
                Log.Information("计算结束");
            }
        }
    }

    在Program调用方法

    复制代码
    namespace SerilogTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                //SerilogHelper.WriteToConsole();
                SerilogHelper.WriteToFile();
            }        
        }
    }
    复制代码

    2、在web中使用Serilog

    前提:引入Serilog.AspNetCore包

    配置appsettings.json

    {
      "log": { //日志配置
        "minlevel": "Verbose", //定义详见Serilog.Events.LogEventLevel
        "console": {
          "enabled": true
        },
        "debug": {
          "enabled": true
        },
        "file": {
          "enabled": true
        },
        "elasticsearch": {
          "enabled": false,
          "nodes": [ "http://localhost:9200/" ],
          "indexformat": "colder"
        },
        "overrides": [ //重写日志输出级别
          {
            "source": "Microsoft.AspNetCore",
            "minlevel": "Warning"
          },
          {
            "source": "Microsoft.EntityFrameworkCore",
            "minlevel": "Information"
          },
          {
            "source": "Microsoft.EntityFrameworkCore.Infrastructure",
            "minlevel": "Warning"
          }
        ]
      },
      "AllowedHosts": "*"
    }

    新建一个对应appsettings.json的model

    复制代码
    using System.Collections.Generic;
    
    namespace SerilogWebTest
    {
        public class LogConfig
        {
            public string minlevel { get; set; }
            public Option console { get; set; } = new Option();
            public Option debug { get; set; } = new Option();
            public Option file { get; set; } = new Option();
            public Option elasticsearch { get; set; } = new Option();
            public List<OverrideConfig> overrides { get; set; } = new List<OverrideConfig>();
        }
    
        public class Option
        {
            public bool enabled { get; set; }
            public List<string> nodes { get; set; } = new List<string>();
            public string indexformat { get; set; }
        }
    
        public class OverrideConfig
        {
            public string source { get; set; }
            public string minlevel { get; set; }
        }
    }
    复制代码

    定义IHostBuilder扩展类,配置Serilog

    using Serilog.Events;
    using Serilog.Sinks.Elasticsearch;
    using System;
    using System.IO;
    using Microsoft.Extensions.Configuration;
    using System.Linq;
    using Microsoft.Extensions.Hosting;
    using Serilog;
    
    namespace SerilogWebTest
    {
        public static partial class Extention
        {
            /// <summary>
            /// 将枚举类型的文本转为枚举类型
            /// </summary>
            /// <typeparam name="TEnum">枚举类型</typeparam>
            /// <param name="enumText">枚举文本</param>
            /// <returns></returns>
            public static TEnum ToEnum<TEnum>(this string enumText) where TEnum : struct
            {
                Enum.TryParse(enumText, out TEnum value);
                return value;
            }
            public static IHostBuilder UseLog(this IHostBuilder hostBuilder)
            {
                var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "log.txt");
                return hostBuilder.UseSerilog((hostingContext, serilogConfig) =>
                {
                    var envConfig = hostingContext.Configuration;
                    LogConfig logConfig = new LogConfig();
                    envConfig.GetSection("log").Bind(logConfig);
                    logConfig.overrides.ForEach(aOverride =>
                    {
                        serilogConfig.MinimumLevel.Override(aOverride.source, aOverride.minlevel.ToEnum<LogEventLevel>());
                    });
    
                    serilogConfig.MinimumLevel.Is(logConfig.minlevel.ToEnum<LogEventLevel>());
                    if (logConfig.console.enabled)
                        serilogConfig.WriteTo.Console();
                    if (logConfig.debug.enabled)
                        serilogConfig.WriteTo.Debug();
                    if (logConfig.file.enabled)
                    {
                        string template = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3} {SourceContext:l}] {Message:lj}{NewLine}{Exception}";
                        serilogConfig.WriteTo.File(
                            path,
                            outputTemplate: template,
                            rollingInterval: RollingInterval.Day,
                            shared: true,
                            fileSizeLimitBytes: 10 * 1024 * 1024,
                            rollOnFileSizeLimit: true
                            );
                    }
                    if (logConfig.elasticsearch.enabled)
                    {
                        var uris = logConfig.elasticsearch.nodes.Select(x => new Uri(x)).ToList();
    
                        serilogConfig.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(uris)
                        {
                            IndexFormat = logConfig.elasticsearch.indexformat,
                            AutoRegisterTemplate = true,
                            AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7
                        });
                    }
                });
            }
        }
    
        
    }

    扩展类中除了允许将日志输出到console、文件,还允许输出到elasticsearch,如果要输出到elasticsearch,需要引入包

     在Program中注入日志服务

    复制代码
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Hosting;
    
    namespace SerilogWebTest
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .UseLog()//注入服务
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    });  
        }
    }
    复制代码 
  • 相关阅读:
    接口XMPPConnection
    Smack 4.3.4 API
    Tigase XMPP Server
    Openfire Meetings插件是一个包含各种Jitsi项目(如VideoBridge和Meet)的实现
    华为方舟编译器 下载 和 LiteOS Studio Setup 2019-04-16.exe SDK下载
    华为 鸿蒙系统(HarmonyOS)
    C#.NET常见问题(FAQ)-如何使用2D绘图控件ZedGraph绘制坐标轴和坐标曲线
    C#.NET常见问题(FAQ)-如何声明list的多维数组
    C#.NET常见问题(FAQ)-如何设置控件水平对齐,垂直对齐
    C#.NET常见问题(FAQ)-如何修改Form不能修改窗体大小
  • 原文地址:https://www.cnblogs.com/qtiger/p/14452974.html
Copyright © 2020-2023  润新知