使用 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.DefaultTrace 的值更改为 。 如果使用 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("ページを表示するタイミングでログを出力します。");
}