使用 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("ページを表示するタイミングでログを出力します。");
}