NLog 是一個開源的輕量級日誌框架,提供了豐富的日誌路由和管理功能,同時 NLog 也是非常容易的去配置和擴展,其實在之前的文章中我已經討論過了 Nlog,在這篇我準備繼續和大家討論一下 NLog 的更多高級功能。
接下來看看如何通過 .config
和 代碼方式
配置 NLog,如何去 輪轉日誌
,如何將 Log 對接 database,如何使用異步的模式提高日誌寫入性能,同時我還會分享一些 NLog 的經驗技巧。
安裝 NLog
可以通過 NuGet Package Manager
可視化界面 或者 NuGet Package Manager Console
控制檯 安裝以下包文件。
NLog.Web.AspNetCore
NLog.Extensions.Logging
NLog.Config
當你安裝完 NLog.Config
之後,有一個叫做 NLog.config
文件會自動引用到你的項目中,值得注意的是,NLog.Config
對 NLog 來說不是唯一的,言外之意就是你即可以用 config 模式配置,也可以用 基於代碼
的模式配置。
使用 .config 文件配置 NLog
NLog 提供了兩種配置方式。
file-based
配置模式code-based
配置模式
回到剛纔的問題,如何採用 file-based
模式,剛纔被引入的 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"
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
}
如果你想通過編程的方式找到當前 NLog 的 target,可使用如下代碼:
var fileTarget = (FileTarget)LogManager.Configuration.FindTargetByName("logfile");
使用 代碼配置 NLog
同樣你也可以使用編碼的形式配置 NLog,只需要調用 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;
}
配置輪轉日誌
你可以讓 NLog 自動實現 輪轉日誌
,什麼叫 輪轉
呢?簡單來說就是:你可以讓 Nlog 只保存近 N 個小時的日誌 並且自動刪除大於 N 小時的日誌,這個特性太實用了,否則的話,你需要經常到生產上去刪除日誌,下面的代碼展示瞭如何使用 .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"
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>
記錄日誌到數據庫
創建數據庫
你可以使用 NLog 將日誌接入到 database 中,下面的腳本用於創建幾張記錄日誌的表。
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
數據庫連接串和參數屬性
接下來如何在 NLog 的 target 中指定數據庫連接串,請注意 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)">
使用參數化
最後,使用 參數化查詢
來防止注入攻擊,詳細代碼如下。
<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
數據庫。
使用 AsyncWrapper 提高性能
NLog 支持多種 targets,比如:AsyncWrapper, BufferingWrapper, FallbackGroup 和 RetryingWrapper,異步的 target 爲了提升性能採用 消息的隊列化
並在多個線程中提取隊列消息,下面的代碼展示瞭如何使用 AsyncWrapper
。
<targets>
<target xsi:type="AsyncWrapper"
name="String"
queueLimit="Integer"
timeToSleepBetweenBatches="Integer"
batchSize="Integer"
overflowAction="Enum">
<target ... />
</target>
</targets>
你可以實現 AsyncWrapper
來實現日誌記錄的異步化,詳細配置如下:
<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
直接進行標記爲異步化 target,如下配置所示:
<targets async="true">
... Write your targets here ...
</targets>
NLog 的最佳實踐
這一小節列舉了一些使用 NLog 的一些最佳實踐
logger 實例應該靜態化,這樣就可以避免在程序中出現多次 logger 初始化帶來的性能開銷。
利用好 NLog 的 Format(當你想結構化日誌)支持,避免你自己對 string 的創建和拼接。
指定
throwConfigExceptions="true"
,可以確保當 NLog 配置錯誤的時候有詳細的錯誤信息,例子如下:
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true" throwConfigExceptions="true">
當記錄完日誌後,可以調用
LogManager.Shutdown()
來實現數據刷新並且關閉內部所有的線程和定時器。
NLog.LogManager.Shutdown();
不要將
async
屬性用在AsyncWrapper
之上,否則性能會變慢。慎用 Trace 級別,因爲 Trace 會記錄所有的日誌,考慮使用 Debug 或者 Info 代替。
NLog 是輕量級並且快速的,可以使用
asynchronous wrappers
的方式來提升性能。
關於 NLog 還是有太多的話要說,NLog 提供了日誌的結構化,方便在大量日誌上進行快速過濾和分析,在未來的文章中我會討論 NLog 的更多高級特性。
譯文鏈接:https://www.infoworld.com/article/3438540/using-advanced-nlog-features-in-aspnet-core.html