使用 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 IndexModelILogger<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" 不會記錄 TraceDebug ,因為它指定 。 此外 final="true" ,由於指定了 ,因此後續 Microsoft.Hosting.Lifetime 定義不會列印相關日誌。

第三 name="Microsoft.*" 個停止紀錄紀錄 name="System.Net.Http.*" ,為與 final="true" 的紀錄指定 。 name 中的"*"是通配 Microsoft System.Net.Http 符,表示指向 所有相關庫。 maxlevel="Info" 因為 Trace Debug ,, Information 停止在這裡,但 WArningError 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("ページを表示するタイミングでログを出力します。");
}