如何在 ASP.NET Core 中使用 NLog 的高級(jí)特性
本文轉(zhuǎn)載自微信公眾號(hào)「 碼農(nóng)讀書」,作者 碼農(nóng)讀書 。轉(zhuǎn)載本文請(qǐng)聯(lián)系 碼農(nóng)讀書公眾號(hào)。
NLog 是一個(gè)開源的輕量級(jí)日志框架,提供了豐富的日志路由和管理功能,同時(shí) NLog 也是非常容易的去配置和擴(kuò)展,其實(shí)在之前的文章中我已經(jīng)討論過了 Nlog,在這篇我準(zhǔn)備繼續(xù)和大家討論一下 NLog 的更多高級(jí)功能。
接下來看看如何通過 .config 和 代碼方式 配置 NLog,如何去 輪轉(zhuǎn)日志,如何將 Log 對(duì)接 database,如何使用異步的模式提高日志寫入性能,同時(shí)我還會(huì)分享一些 NLog 的經(jīng)驗(yàn)技巧。
安裝 NLog
可以通過 NuGet Package Manager 可視化界面 或者 NuGet Package Manager Console 控制臺(tái) 安裝以下包文件。
- NLog.Web.AspNetCore
 - NLog.Extensions.Logging
 - NLog.Config
 
當(dāng)你安裝完 NLog.Config 之后,有一個(gè)叫做 NLog.config 文件會(huì)自動(dòng)引用到你的項(xiàng)目中,值得注意的是,NLog.Config 對(duì) NLog 來說不是唯一的,言外之意就是你即可以用 config 模式配置,也可以用 基于代碼 的模式配置。
使用 .config 文件配置 NLog
NLog 提供了兩種配置方式。
- file-based 配置模式
 - code-based 配置模式
 
回到剛才的問題,如何采用 file-based 模式,剛才被引入的 NLog.Config 內(nèi)容如下:
- <?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">
 - <extensions>
 - <add assembly="NLog.Web.AspNetCore"/>
 - </extensions>
 - <targets>
 - <target name="logfile" xsi:type="File" fileName="D:\logs\LogMessages-${shortdate}.log" />
 - </targets>
 - <rules>
 - <logger name="*" minlevel="Trace" writeTo="logfile" />
 - </rules>
 - </nlog>
 
下面的代碼展示了如何在 Controller 下用 NLog 記錄日志。
- public class HomeController : Controller
 - {
 - Logger _logger = (Logger)LogManager.GetCurrentClassLogger(typeof(Logger));
 - public IActionResult Index()
 - {
 - _logger.Info("Application started");
 - return View();
 - }
 - //Other action methods
 - }
 
如果你想通過編程的方式找到當(dāng)前 NLog 的 target,可使用如下代碼:
- var fileTarget = (FileTarget)LogManager.Configuration.FindTargetByName("logfile");
 
使用 代碼配置 NLog
同樣你也可以使用編碼的形式配置 NLog,只需要調(diào)用 NLog 提供的 API 接口即可,下面的代碼展示了如何配置 Nlog。
- private static void ConfigureNLog()
 - {
 - var logConfiguration = new LoggingConfiguration();
 - var dbTarget = new DatabaseTarget();
 - dbTarget.ConnectionString = "Data Source=JOYDIP;initial catalog=NLogDemo;User Id=sa;Password=sa1@3#.;"; dbTarget.CommandText = "INSERT INTO DbLog (level, callsite, message, logdatetime)" +" Values(@level, @callsite, @message, @logdatetime)";
 - dbTarget.Parameters.Add(new DatabaseParameterInfo("@level", "${level}"));
 - dbTarget.Parameters.Add(new DatabaseParameterInfo("@callSite", "${callSite}"));
 - dbTarget.Parameters.Add(new DatabaseParameterInfo("@message", "${message}"));
 - dbTarget.Parameters.Add(new DatabaseParameterInfo("@logdatetime","${date:s}"));
 - var rule = new LoggingRule("*", LogLevel.Debug, dbTarget);
 - logConfiguration.LoggingRules.Add(rule);
 - LogManager.Configuration = logConfiguration;
 - }
 
配置輪轉(zhuǎn)日志
你可以讓 NLog 自動(dòng)實(shí)現(xiàn) 輪轉(zhuǎn)日志,什么叫 輪轉(zhuǎn) 呢?簡(jiǎn)單來說就是:你可以讓 Nlog 只保存近 N 個(gè)小時(shí)的日志 并且自動(dòng)刪除大于 N 小時(shí)的日志,這個(gè)特性太實(shí)用了,否則的話,你需要經(jīng)常到生產(chǎn)上去刪除日志,下面的代碼展示了如何使用 .config 實(shí)現(xiàn)自動(dòng)輪轉(zhuǎn)日志。
- <?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="${basedir}/logs/App.log"
 - layout="${longdate} ${message}"
 - archiveFileName="${basedir}/logs/archive.{#}.log"
 - archiveEvery="Day"
 - archiveNumbering="Rolling"
 - maxArchiveFiles="7"
 - concurrentWrites="true"
 - keepFileOpen="true" />
 - </targets>
 - <rules>
 - <logger name="*" minlevel="Info" writeTo="logfile" />
 - </rules>
 - </nlog>
 
記錄日志到數(shù)據(jù)庫
創(chuàng)建數(shù)據(jù)庫
你可以使用 NLog 將日志接入到 database 中,下面的腳本用于創(chuàng)建幾張記錄日志的表。
- CREATE TABLE [dbo].[DbLog](
 - [Id] [int] IDENTITY(1,1) NOT NULL,
 - [Level] [varchar](max) NULL,
 - [CallSite] [varchar](max) NULL,
 - [Message] [varchar](max) NULL,
 - [AdditionalInfo] [varchar](max) NULL,
 - [LogDateTime] [datetime] NOT NULL,
 - CONSTRAINT [PK_DbLogs] PRIMARY KEY CLUSTERED
 - (
 - [Id] ASC
 - )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
 - ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
 - GO
 
數(shù)據(jù)庫連接串和參數(shù)屬性
接下來如何在 NLog 的 target 中指定數(shù)據(jù)庫連接串,請(qǐng)注意 connectionString 和 commandText 是如何配置的。
- <target name="database" xsi:type="Database" keepConnection="true"
 - useTransactions="true"
 - dbProvider="System.Data.SqlClient"
 - connectionString="data source=localhost;initial
 - catalog=NLogDemo;integrated security=false;
 - persist security info=True;User ID=sa;Password=sa1@3#."
 - commandText="INSERT INTO DbLog (level, callsite, message, additionalInfo,
 - logdatetime) Values (@level, @callsite, @message, @additionalInfo,
 - @logdatetime)">
 
使用參數(shù)化
最后,使用 參數(shù)化查詢 來防止注入攻擊,詳細(xì)代碼如下。
- <parameter name="@level" layout="${level}" />
 - <parameter name="@callSite" layout="${callsite}" />
 - <parameter name="@message" layout="${message}" />
 - <parameter name="@additionalInfo" layout="${var:AdditionalInfo}" />
 - <parameter name="@logdatetime" layout="${date:s}" />
 
完整的 NLog
以下是完整的 NLog 文件僅供參考。
- <?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">
 - <extensions>
 - <add assembly="NLog.Web.AspNetCore"/>
 - </extensions>
 - <variable name="AdditionalInfo" value=""/>
 - <targets>
 - <target name="database" xsi:type="Database" keepConnection="true"
 - useTransactions="true"
 - dbProvider="System.Data.SqlClient"
 - connectionString="data source=localhost;initial
 - catalog=NLogDemo;integrated security=false;persist security
 - info=True;User ID=sa;Password=sa1@3#."
 - commandText="INSERT INTO DbLog
 - (level, callsite, message, additionalInfo, logdatetime)
 - Values (@level, @callsite, @message, @additionalInfo, @logdatetime)">
 - <parameter name="@level" layout="${level}" />
 - <parameter name="@callSite" layout="${callsite}" />
 - <parameter name="@message" layout="${message}" />
 - <parameter name="@additionalInfo" layout="${var:AdditionalInfo}" />
 - <parameter name="@logdatetime" layout="${date:s}" />
 - </target>
 - </targets>
 - <rules>
 - <logger levels="Debug,Info,Error,Warn,Fatal" name="databaseLogger" writeTo="database"/>
 - </rules>
 - </nlog>
 
除了 SQL Server 之外,還可以使用 NLog 將日志記錄到 MySQL,Oracle 和 SQLite 數(shù)據(jù)庫。
使用 AsyncWrapper 提高性能
NLog 支持多種 targets,比如:AsyncWrapper, BufferingWrapper, FallbackGroup 和 RetryingWrapper,異步的 target 為了提升性能采用 消息的隊(duì)列化 并在多個(gè)線程中提取隊(duì)列消息,下面的代碼展示了如何使用 AsyncWrapper。
- <targets>
 - <target xsi:type="AsyncWrapper"
 - name="String"
 - queueLimit="Integer"
 - timeToSleepBetweenBatches="Integer"
 - batchSize="Integer"
 - overflowAction="Enum">
 - <target ... />
 - </target>
 - </targets>
 
你可以實(shí)現(xiàn) AsyncWrapper 來實(shí)現(xiàn)日志記錄的異步化,詳細(xì)配置如下:
- <targets>
 - <target name="asyncFile" xsi:type="AsyncWrapper">
 - <target xsi:type="File" name="fileLog"
 - fileName="${basedir}/Logs/${shortdate}.log"
 - layout="${longdate} ${uppercase:${level}} ${message}"/>
 - </target>
 - </targets>
 - <rules>
 - <logger levels="Debug,Info,Error,Warn,Fatal" writeTo="asyncFile"/>
 - </rules>
 
除了這種方式,你還可以在所有的 targets 上用 async=true 直接進(jìn)行標(biāo)記為異步化 target,如下配置所示:
- <targets async="true">
 - ... Write your targets here ...
 - </targets>
 
NLog 的最佳實(shí)踐
這一小節(jié)列舉了一些使用 NLog 的一些最佳實(shí)踐
- logger 實(shí)例應(yīng)該靜態(tài)化,這樣就可以避免在程序中出現(xiàn)多次 logger 初始化帶來的性能開銷。
 - 利用好 NLog 的 Format(當(dāng)你想結(jié)構(gòu)化日志)支持,避免你自己對(duì) string 的創(chuàng)建和拼接。
 - 指定 throwConfigExceptions="true" ,可以確保當(dāng) NLog 配置錯(cuò)誤的時(shí)候有詳細(xì)的錯(cuò)誤信息,例子如下:
 
- <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 - autoReload="true" throwConfigExceptions="true">
 
- 當(dāng)記錄完日志后,可以調(diào)用 LogManager.Shutdown() 來實(shí)現(xiàn)數(shù)據(jù)刷新并且關(guān)閉內(nèi)部所有的線程和定時(shí)器。
 
- NLog.LogManager.Shutdown();
 
- 不要將 async 屬性用在 AsyncWrapper 之上,否則性能會(huì)變慢。
 - 慎用 Trace 級(jí)別,因?yàn)?Trace 會(huì)記錄所有的日志,考慮使用 Debug 或者 Info 代替。
 - NLog 是輕量級(jí)并且快速的,可以使用 asynchronous wrappers 的方式來提升性能。
 
關(guān)于 NLog 還是有太多的話要說,NLog 提供了日志的結(jié)構(gòu)化,方便在大量日志上進(jìn)行快速過濾和分析,在未來的文章中我會(huì)討論 NLog 的更多高級(jí)特性。
譯文鏈接:https://www.infoworld.com/article/3438540/using-advanced-nlog-features-in-aspnet-core.html















 
 
 
 
 
 
 