.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="log\log.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:\temp\nlog-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:\temp\nlog-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>();
                });  
    }
}
復制代碼 


免責聲明!

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



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