如何在 ASP.NET Core 中使用 NLog 的高级特性
NLog 是一個(gè)開(kāi)源的輕量級(jí)日志框架,提供了豐富的日志路由和管理功能,同時(shí) NLog 也是非常容易的去配置和擴(kuò)展,其實(shí)在之前的文章中我已經(jīng)討論過(guò)了 Nlog,在這篇我準(zhǔn)備繼續(xù)和大家討論一下 NLog 的更多高級(jí)功能。
接下來(lái)看看如何通過(guò) .config 和 代碼方式 配置 NLog,如何去 輪轉(zhuǎn)日志,如何將 Log 對(duì)接 database,如何使用異步的模式提高日志寫(xiě)入性能,同時(shí)我還會(huì)分享一些 NLog 的經(jīng)驗(yàn)技巧。
安裝 NLog
可以通過(guò) 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 來(lái)說(shuō)不是唯一的,言外之意就是你即可以用 config 模式配置,也可以用 基于代碼 的模式配置。
使用 .config 文件配置 NLog
NLog 提供了兩種配置方式。
file-based 配置模式
code-based 配置模式
回到剛才的問(wèn)題,如何采用 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}如果你想通過(guò)編程的方式找到當(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)單來(lái)說(shuō)就是:你可以讓 Nlog 只保存近 N 個(gè)小時(shí)的日志 并且自動(dòng)刪除大于 N 小時(shí)的日志,這個(gè)特性太實(shí)用了,否則的話(huà),你需要經(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ù)庫(kù)
創(chuàng)建數(shù)據(jù)庫(kù)
你可以使用 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ù)庫(kù)連接串和參數(shù)屬性
接下來(lái)如何在 NLog 的 target 中指定數(shù)據(jù)庫(kù)連接串,請(qǐng)注意 connectionString 和 commandText 是如何配置的。
<target?name="database"?xsi:type="Database"?keepConnection="true"useTransactions="true"dbProvider="System.Data.SqlClient"connectionString="data?source=localhost;initialcatalog=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ún) 來(lái)防止注入攻擊,詳細(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;initialcatalog=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ù)庫(kù)。
使用 AsyncWrapper 提高性能
NLog 支持多種 targets,比如:AsyncWrapper, BufferingWrapper, FallbackGroup 和 RetryingWrapper,異步的 target 為了提升性能采用 消息的隊(duì)列化 并在多個(gè)線(xiàn)程中提取隊(duì)列消息,下面的代碼展示了如何使用 AsyncWrapper。
<targets><target?xsi:type="AsyncWrapper"name="String"queueLimit="Integer"timeToSleepBetweenBatches="Integer"batchSize="Integer"overflowAction="Enum"><target?...?/></target> </targets>你可以實(shí)現(xiàn) AsyncWrapper 來(lái)實(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 初始化帶來(lái)的性能開(kāi)銷(xiāo)。
利用好 NLog 的 Format(當(dāng)你想結(jié)構(gòu)化日志)支持,避免你自己對(duì) string 的創(chuàng)建和拼接。
指定 throwConfigExceptions="true" ,可以確保當(dāng) NLog 配置錯(cuò)誤的時(shí)候有詳細(xì)的錯(cuò)誤信息,例子如下:
當(dāng)記錄完日志后,可以調(diào)用 LogManager.Shutdown() 來(lái)實(shí)現(xiàn)數(shù)據(jù)刷新并且關(guān)閉內(nèi)部所有的線(xiàn)程和定時(shí)器。
不要將 async 屬性用在 AsyncWrapper 之上,否則性能會(huì)變慢。
慎用 Trace 級(jí)別,因?yàn)?Trace 會(huì)記錄所有的日志,考慮使用 Debug 或者 Info 代替。
NLog 是輕量級(jí)并且快速的,可以使用 asynchronous wrappers 的方式來(lái)提升性能。
關(guān)于 NLog 還是有太多的話(huà)要說(shuō),NLog 提供了日志的結(jié)構(gòu)化,方便在大量日志上進(jìn)行快速過(guò)濾和分析,在未來(lái)的文章中我會(huì)討論 NLog 的更多高級(jí)特性。
譯文鏈接:https://www.infoworld.com/article/3438540/using-advanced-nlog-features-in-aspnet-core.html
總結(jié)
以上是生活随笔為你收集整理的如何在 ASP.NET Core 中使用 NLog 的高级特性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 对CORS OPTIONS预检请求的一些
- 下一篇: 强烈推荐:SiteServer CMS开