先來介紹.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>(); }); } }