使用 NLog 記錄
環境
- Visual Studio
-
- Visual Studio 2019
- ASP.NET Core
-
- 5.0 (MVC, Razor 頁)
入門
NLog 現在可以根據設置將日誌輸出到檔、電子郵件和資料庫。
NLog ASP.NET 核心的標準日誌記錄系統中。 使用默認記錄器時,可以根據設置輸出日誌。
關於日誌級別
Microsoft 日誌和 NLog 都分為六個階段,輸出級別基本一致:
等級 | Microsoft | NLog |
---|---|---|
0 | Trace | Trace |
1 | Debug | Debug |
2 | Information | Info |
3 | Warning | Warn |
4 | Error | Error |
5 | Critical | Fatal |
(6) | (None) | (Off) |
級別越高,日誌越重要,無論日誌輸出限制如何,寫入日誌的可能性就越大。
日誌記錄過程
引入 NLog 包
ASP.NET 核心專案后,添加包。
右鍵單擊項目的依賴項,然後選擇"管理 NuGet 包"。
按下「瀏覽」選項卡,然後在搜索欄位中輸入 NLog 以查看與 NLog 相關的套件。
選擇 NLog, 然後單擊「 安裝」 按鈕以選擇最新的穩定版本。
單擊"確定"。
還安裝 NLog.Web.AspNetCore
包已添加到專案中。
添加 nlog.config
將 nlog.config 添加到 專案中,這是 NLog 日誌的輸出定義。 由於內容採用 XML 格式,因此我創建它作為 XML 檔。 檔名必須 為 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"
internalLogLevel="Info"
throwConfigExceptions="true"
internalLogFile="${basedir}/internal-nlog-AspNetCore.txt">
<!-- ログの出力レイアウトを変数 layoutDefine で定義 -->
<variable name="layoutDefine"
value="${longdate} [${event-properties:item=EventId_Id:whenEmpty=0}][${level:padding=-5}] ${message} ${exception:format=tostring} (${callsite:includeNamespace=false:fileName=true:includeSourcePath=false})" />
<!-- 書き込むターゲット -->
<targets>
<!-- Visual Studio の出力 (デバッグ) に書き込みます -->
<target xsi:type="Trace" name="TraceOutput" rawWrite="true" layout="${layoutDefine}" />
<!-- 基本的な詳細を含むすべてのログメッセージのファイルターゲット -->
<target xsi:type="File" name="FileOutput" fileName="${aspnet-appbasepath}/Log-${shortdate}.log" layout="${layoutDefine}" />
<!-- Docker / Visual Studio の起動検出を改善するためにライフタイムメッセージをホストするためのコンソールターゲット -->
<target xsi:type="Console" name="LifetimeConsole" layout="${level:truncate=4}\: ${logger}[0]${newline} ${message}${exception:format=tostring}" />
</targets>
<!-- ロガー名からターゲットにマップするルール -->
<rules>
<!-- Microsoft からのものを含むすべてのログ -->
<logger name="*" writeTo="TraceOutput" />
<!-- 起動の検出を高速化するために、ホスティングライフタイムメッセージをコンソールターゲットに出力します。Microsoft.Hosting.Lifetime はここより下の定義には出力しません -->
<logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="LifetimeConsole" final="true" />
<!-- 重要でない Microsoft ログをスキップして、自分のログのみをログに記録する。システムが出す Warning 以上のログ以外はここより下の定義には出力されません -->
<logger name="Microsoft.*" maxlevel="Info" final="true" />
<logger name="System.Net.Http.*" maxlevel="Info" final="true" />
<!-- 上記で除外したもの以外をファイルに出力 -->
<logger name="*" writeTo="FileOutput" />
</rules>
</nlog>
確保 nlog.config 屬性設置為"生成操作:內容"和"複製到輸出目錄:複製(如果新)」。
編輯 appsetting.json
默認情況下,如何設置 nlog.config Information
僅輸出這些級別。
這是因為日誌記錄也依賴於 appsetting.json。
開啟 appsetting.json, Logging.LogLevel.Default
Trace
將的值變更為 。
如果使用 NLog,則可以通過設置 appsetting.json 來輸出實際 Trace
所有級別,因為級別調整在 NLog 端進行。
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
另外,開發時為appsettings。 Development.json 的設置將載入,因此我們將以同樣的方式更改它。
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
準備 NLog 程式
添加程式,以便 NLog 機制可以記錄日誌。
開啟程式.cs 檔案並更正它,如下所示:
using NLog.Web; // 追加
// 省略
public class Program
{
public static void Main(string[] args)
{
var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
try
{
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
// NLog:セットアップエラーをキャッチ
logger.Error(exception, "例外のためにプログラムを停止しました。");
throw;
}
finally
{
// アプリケーションを終了する前に、内部タイマー/スレッドをフラッシュして停止するようにしてください
// (Linux でのセグメンテーション違反を回避してください)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(logging =>
{
logging.ClearProviders(); // NLog 以外で設定された Provider の無効化.
logging.SetMinimumLevel(LogLevel.Trace); // 最小ログレベルの設定
})
.UseNLog(); // NLog:依存性注入のための NLog のセットアップ
}
日誌輸出
對於 MVC HomeComtroller
專案,我認為 Razor IndexModel
頁 ILogger<IndexModel> logger
的建構函數已傳遞給 。
它還設置為私 _logger
有欄位,因此您可以使用它來記錄日誌。
下面是 Razor 頁的輸出範例,但 MVC 可以使用相同的代碼進行輸出。
// 省略
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
_logger.LogTrace("Trace で出力します。");
_logger.LogDebug("Debug で出力します。");
_logger.LogInformation("Information で出力します。");
_logger.LogWarning("Warning で出力します。");
_logger.LogError("Error で出力します。");
_logger.LogCritical("Critical で出力します。");
_logger.LogInformation(1, "EventID ありで出力します。");
}
public void OnGet()
{
_logger.LogInformation("ページを表示するタイミングでログを出力します。");
}
}
運行除錯時,紀錄檔可能位於專案的資料夾中。
通過查看文件的內容,可以查看日誌。
示例 nlog.config 的說明
我按順序解釋,但省略了不太重要的部分。
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Info"
throwConfigExceptions="true"
internalLogFile="${basedir}/internal-nlog-AspNetCore.txt">
有NLog本身的紀錄輸出設定等參數 。
internalLogFile
日誌將列印到該日誌。 例如,如果日誌輸出本身存在錯誤,則非常有用。 ${basedir}
指向程式的執行資料夾。
internalLogLevel
是 NLog 日誌的輸出級別。 Off
不會列印任何內容。
<!-- ログの出力レイアウトを変数 layoutDefine で定義 -->
<variable name="layoutDefine"
value="${longdate} [${event-properties:item=EventId_Id:whenEmpty=0}][${level:padding=-5}] ${message} ${exception:format=tostring} (${callsite:includeNamespace=false:fileName=true:includeSourcePath=false})" />
將日誌內容設置為變數,以以何種佈局輸出日誌的內容。 您可以直接在以後的目標中輸入它,但如果要指定多個相同的佈局,則最好將變數放在一個變數中。
最好查看官方網站, 瞭解佈局 可以具有哪些參數。
此處提供的參數以以下格式輸出以供參考:
參數 | 輸出內容 |
---|---|
longdate | 日期/時間分鐘/秒,如"2021-03-17 11:46:36.5034" |
event-properties | 顯示程式指定的紀錄記錄的事件 ID 等。 |
level | 級別,如"Trace"和"Error" |
message | 程序記錄中指定的消息 |
exception | 在程式的日誌輸出中傳遞 Exception 時的內容 |
callsite | 日誌輸出位置、檔名等 |
輸出示例
2021-03-17 11:46:37.3537 [0][Info ] ページを表示するタイミングでログを出力します。 (IndexModel.OnGet(Index.cshtml.cs:26))
<!-- 書き込むターゲット -->
<targets>
<!-- Visual Studio の出力 (デバッグ) に書き込みます -->
<target xsi:type="Trace" name="TraceOutput" rawWrite="true" layout="${layoutDefine}" />
<!-- 基本的な詳細を含むすべてのログメッセージのファイルターゲット -->
<target xsi:type="File" name="FileOutput" fileName="${aspnet-appbasepath}/Log-${shortdate}.log" layout="${layoutDefine}" />
<!-- Docker / Visual Studio の起動検出を改善するためにライフタイムメッセージをホストするためのコンソールターゲット -->
<target xsi:type="Console" name="LifetimeConsole" layout="${level:truncate=4}\: ${logger}[0]${newline} ${message}${exception:format=tostring}" />
</targets>
要輸出的目標。 可以有多個。
第一個 xsi:type="Trace"
指定 ,日誌列印到 Visual Studio 輸出視窗。
它主要用於在調試運行中檢查。
第二 xsi:type="File"
個指定 ,並記錄到指定路徑的檔。
在 ${shortdate}
路徑中指定 時,可以將日誌寫入日誌記錄時日期的檔。
此外 ${aspnet-appbasepath}
,指定 Web 專案的根資料夾。
但是,在操作時,最好將日誌檔列印出 Web 目錄,以考慮程式交換和安全性。
第三個 xsi:type="Console"
指定 ,並且可以顯示在主控台應用中的控制台中。
ASP.NET Core 本身不是控制台應用,但您可以在 Docker 或 Azure 等環境中在控制台中顯示狀態,並可用於此目的。
我們使用 NLog 官方網站上的描述。
<!-- ロガー名からターゲットにマップするルール -->
<rules>
<!-- Microsoft からのものを含むすべてのログ -->
<logger name="*" writeTo="TraceOutput" />
<!-- 起動の検出を高速化するために、ホスティングライフタイムメッセージをコンソールターゲットに出力します。Microsoft.Hosting.Lifetime はここより下の定義には出力しません -->
<logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="LifetimeConsole" final="true" />
<!-- 重要でない Microsoft ログをスキップして、自分のログのみをログに記録する。システムが出す Warning 以上のログ以外はここより下の定義には出力されません -->
<logger name="Microsoft.*" maxlevel="Info" final="true" />
<logger name="System.Net.Http.*" maxlevel="Info" final="true" />
<!-- 上記で除外したもの以外をファイルに出力 -->
<logger name="*" writeTo="FileOutput" />
</rules>
在這裡,您可以指定要列印的級別和日誌類型。 此說明按從上到下的順序應用。
第一個 name="*"
指定 ,但未指定級別,因此將所有 writeTo
日誌列印到 的目標。
由於 target
您在此處 TraceOutput
指定了 在中創建的 ,因此它顯示在 Visual Studio 輸出中。
第二 Microsoft.Hosting.Lifetime
個輸出是輸出到庫 writeTo (コンソール)
的日誌。
您可以在主控台(如 Azure 和 Docker)中查看 ConsoleLifetime 關係。
minlevel="Info"
不會記錄 Trace
或 Debug
,因為它指定 。
此外 final="true"
,由於指定了 ,因此後續 Microsoft.Hosting.Lifetime
定義不會列印相關日誌。
第三 name="Microsoft.*"
個停止紀錄紀錄 name="System.Net.Http.*"
,為與 final="true"
的紀錄指定 。
name
中的"*"是通配 Microsoft
System.Net.Http
符,表示指向 所有相關庫。
maxlevel="Info"
因為 Trace
Debug
,, Information
停止在這裡,但
WArning
在 Error
Critical
後續定義中也會列印、 與的紀錄。
第四個輸出 final="true"
檔,而不是上面停止的日誌。
存檔日誌
另一種方法是僅將一個主日誌檔存檔到另一個資料夾中,每個日期都有一個舊日誌檔。
例如:
<target xsi:type="File"
name="FileOutput"
fileName="${aspnet-appbasepath}/Log.log"
archiveNumbering="Date"
archiveEvery="Day"
archiveFileName="${aspnet-appbasepath}/Archive/Log_{#}.log"
archiveDateFormat="yyyy-MM-dd"
maxArchiveFiles="7"
layout="${layoutDefine}" />
此處使用的參數具有以下含義:
參數 | 標題 |
---|---|
archiveNumbering | 如果指定了日期,則按日期創建存檔檔。 |
archiveEvery | 如果指定了"天",則按天存檔。 其他指定方法包括"月"、"Hour"和"Sunday"。 |
archiveFileName | 要存檔的路徑。 {#} 的位置以存檔單位更改。 |
archiveDateFormat | 依日期存檔的檔名的年日期格式。 |
maxArchiveFiles | 指定最多存檔多少個檔。 |
除了日期之外,您還可以以其他方式存檔它們。 有關詳細資訊 ,請參閱 官方網站。
執行它時,它看起來像這樣:
按日誌發送電子郵件
NLog 還允許您在日誌記錄時發送電子郵件。 但是,如果發送調試日誌等郵件,則發送量會過大, 最好只針對有限的日誌級別,如錯誤和致命級別。 此外,為了避免由於過度發送而阻止郵件伺服器等故障風險, 我們建議您指定專用於日誌的電子郵件帳戶。
下面是一個設置示例。 如果要實際發送郵件,請根據要使用的 SMTP 伺服器進行設置。
<targets>
<target xsi:type="Mail"
name="SendMail"
smtpServer="SMTP Server Name"
smtpPort="25"
subject="XXXX システムでエラーが発生しました"
from="aaaa@example.com"
to="bbbb@example.com"
enableSsl="False"
smtpAuthentication="None"
smtpUserName=""
smtpPassword=""
layout="${layoutDefine}"/>
</targets>
<rules>
<logger name="*" minlevel="Error" writeTo="SendMail" />
</rules>
將日誌寫入資料庫
NLog 還允許您將日誌寫入資料庫。 下面是一個示例 ,請參閱官方網站 以瞭解更多資訊。
本節提供寫入另一台伺服器上的 SQL Server 的分步說明。
首先,在目標 SQL Server 上創建一個用於日誌記錄的表。 由於可以選擇寫入值,因此將日誌所需的值定義為列。
下面是創建表的 SQL 的範例。
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Log](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Application] [nvarchar](50) NOT NULL,
[Logged] [datetime] NOT NULL,
[Level] [nvarchar](50) NOT NULL,
[User] [nvarchar](250) NOT NULL,
[Message] [nvarchar](max) NOT NULL,
[Logger] [nvarchar](250) NULL,
[Callsite] [nvarchar](max) NULL,
[Exception] [nvarchar](max) NULL,
CONSTRAINT [PK_dbo.Log] 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
資料庫處理需要 System.Data.SqlClient
資料庫用戶端庫。
讓我們從 NuGet 安裝它。
將資料庫資訊寫入 appsettings.json。 nlog.config 可以讀取 appsettings.json 中的資訊。 設置是臨時的,因此請根據實際資料庫進行設置。 金鑰名稱是可選的,但在 nlog.config 中指定時使用。
{
"": "省略",
"NlogConnection": {
"DbHost": "ServerName\\SQLEXPRESS",
"Database": "TestDatabase",
"User": "UserName",
"Password": "********"
}
}
nlog.config 設定如下:
<targets>
<target xsi:type="Database"
name="DatabaseOutput"
dbProvider="sqlserver"
dbHost="${configsetting:name=NlogConnection.DbHost}"
dbDatabase="${configsetting:name=NlogConnection.Database}"
dbUserName="${configsetting:name=NlogConnection.User}"
dbPassword="${configsetting:name=NlogConnection.Password}">
<commandText>
insert into dbo.Log (
Application, Logged, [Level], [User], Message, Logger, CallSite, Exception
) values (
@Application, @Logged, @Level, @User, @Message, @Logger, @Callsite, @Exception
);
</commandText>
<parameter name="@application" layout="XXXX System" />
<parameter name="@logged" layout="${date}" />
<parameter name="@level" layout="${level}" />
<parameter name="@user" layout="${aspnet-user-identity}" />
<parameter name="@message" layout="${message}" />
<parameter name="@logger" layout="${logger}" />
<parameter name="@callSite" layout="${callsite:filename=true}" />
<parameter name="@exception" layout="${exception:tostring}" />
</target>
</targets>
<rules>
<logger name="*" writeTo="DatabaseOutput" />
</rules>
如果沒有錯誤,則按如下方式寫入。
請注意,.cs嘗試將日誌寫入資料庫(如 Program .cs方法 CreateHostBuilder
之前)可能會失敗。
從 RequestServices 獲取記錄器並記錄日誌
每次創建新控制器或頁面模型時,向 ILogger
建構函數添加 可能很麻煩。
另一種方法是 RequestServices
從 中獲取它。
public void OnGet()
{
// RequestServices から ILogger を取得する
var logger = (ILogger<IndexModel>)HttpContext.RequestServices.GetService(typeof(ILogger<IndexModel>));
logger.LogInformation("ページを表示するタイミングでログを出力します。");
}
如果指定自己的控制器或頁面模型很麻煩,則可以創建擴展方法或創建基類。
public static class AspNetExtention
{
<summary>
ロガーを取得する拡張メソッドです。
</summary>
public static ILogger<T> GetLogger<T>(this T self) where T : PageModel
=> (ILogger<T>)self.HttpContext.RequestServices.GetService(typeof(ILogger<T>));
// MVC の場合
//public static ILogger<T> GetLogger<T>(this T self) where T : Controller
// => (ILogger<T>)self.HttpContext.RequestServices.GetService(typeof(ILogger<T>));
}
使用示例
public void OnGet()
{
// RequestServices から ILogger を取得する (this. は必要)
var logger = this.GetLogger();
logger.LogInformation("ページを表示するタイミングでログを出力します。");
}