.NET Core 和 ASP.NET Core 中的日志记录
注意
此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本。
作者:Kirk Larkin、Juergen Gutsch 和 Rick Anderson
本文介绍了 .NET 中适用于 ASP.NET Core 应用的日志记录。 有关在 .NET 中进行日志记录的详细信息,请参阅 .NET 中的日志记录。
有关补充或取代此节点中指南的 Blazor 日志记录指南,请参阅 ASP.NET Core Blazor 日志记录。
日志记录提供程序
日志记录提供程序存储日志,但显示日志的 Console
提供程序除外。 例如,Azure Application Insights 提供程序将日志存储在 Azure Application Insights 中。 可以启用多个提供程序。
默认 ASP.NET Core Web 应用模板调用 WebApplication.CreateBuilder,该操作将添加以下日志记录提供程序:
- 控制台
- 调试
- EventSource
- EventLog:仅限 Windows
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
上面的代码显示了使用 ASP.NET Core Web 应用模板创建的 Program.cs
文件。 接下来的几节提供基于 ASP.NET Core Web 应用模板的示例。
下面的代码将重写由 WebApplication.CreateBuilder
添加的一组默认的日志记录提供程序:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Services.AddRazorPages();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
或者,可以按如下所示编写上述日志记录代码:
var builder = WebApplication.CreateBuilder();
builder.Host.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
});
有关其他提供程序,请参阅:
创建日志
若要创建日志,请使用依赖项注入 (DI) 中的 ILogger<TCategoryName>对象。
如下示例中:
- 创建一个记录器
ILogger<AboutModel>
,该记录器使用类型为AboutModel
的完全限定名称的日志类别。 日志类别是与每个日志关联的字符串。 - 调用 LogInformation 以在 Information 级别登录。 日志“级别”代表所记录事件的严重程度。
public class AboutModel : PageModel
{
private readonly ILogger _logger;
public AboutModel(ILogger<AboutModel> logger)
{
_logger = logger;
}
public void OnGet()
{
_logger.LogInformation("About page visited at {DT}",
DateTime.UtcNow.ToLongTimeString());
}
}
有关 Blazor 的信息,请参阅 ASP.NET Core Blazor 日志记录。
配置日志记录
日志记录配置通常由 appsettings.{ENVIRONMENT}.json
文件的 Logging
部分提供,其中 {ENVIRONMENT}
占位符是环境。 以下 appsettings.Development.json
文件由 ASP.NET Core Web 应用模板生成:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
在上述 JSON 中:
- 指定了
"Default"
和"Microsoft.AspNetCore"
类别。 "Microsoft.AspNetCore"
类别适用于以"Microsoft.AspNetCore"
开头的所有类别。 例如,此设置适用于"Microsoft.AspNetCore.Routing.EndpointMiddleware"
类别。"Microsoft.AspNetCore"
类别在日志级别Warning
或更高级别记录。- 未指定特定的日志提供程序,因此
LogLevel
适用于所有启用的日志记录提供程序,但 Windows EventLog 除外。
Logging
属性可以具有 LogLevel 和日志提供程序属性。 LogLevel
指定要针对所选类别进行记录的最低级别。 在前面的 JSON 中,指定了 Information
和 Warning
日志级别。 LogLevel
表示日志的严重性,范围为 0 到 6:
Trace
= 0、Debug
= 1、Information
= 2、Warning
= 3、Error
= 4、Critical
= 5 和 None
= 6。
指定 LogLevel
时,将为指定级别和更高级别的消息启用日志记录。 在前面的 JSON 中,记录了 Information
及更高级别的 Default
类别。 例如,记录了 Information
、Warning
、Error
和 Critical
消息。 如果未指定 LogLevel
,则日志记录默认为 Information
级别。 有关详细信息,请参阅日志级别。
提供程序属性可以指定 LogLevel
属性。 提供程序下的 LogLevel
指定要为该提供程序记录的级别,并替代非提供程序日志设置。 请考虑以下 appsettings.json
文件:
{
"Logging": {
"LogLevel": { // All providers, LogLevel applies to all the enabled providers.
"Default": "Error", // Default logging, Error and higher.
"Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
},
"Debug": { // Debug provider.
"LogLevel": {
"Default": "Information", // Overrides preceding LogLevel:Default setting.
"Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
}
},
"EventSource": { // EventSource provider
"LogLevel": {
"Default": "Warning" // All categories of EventSource provider.
}
}
}
}
Logging.{PROVIDER NAME}.LogLevel
中的设置会覆盖 Logging.LogLevel
中的设置,其中 {PROVIDER NAME}
占位符是提供程序名称。 在前面的 JSON 中,Debug
提供程序的默认日志级别设置为 Information
:
Logging:Debug:LogLevel:Default:Information
前面的设置为每个 Logging:Debug:
类别(Microsoft.Hosting
除外)指定 Information
日志级别。 当列出特定类别时,该特定类别将替代默认类别。 在前面的 JSON 中,Logging:Debug:LogLevel
类别 "Microsoft.Hosting"
和 "Default"
替代 Logging:LogLevel
中的设置。
可以为以下任何一项指定最低日志级别:
- 特定提供程序:例如,
Logging:EventSource:LogLevel:Default:Information
- 特定类别:例如,
Logging:LogLevel:Microsoft:Warning
- 所有提供程序和所有类别:
Logging:LogLevel:Default:Warning
低于最低级别的任何日志均不会执行以下操作:
- 传递到提供程序。
- 记录或显示。
若要禁止显示所有日志,请指定 LogLevel.None。 LogLevel.None
的值为 6,该值高于 LogLevel.Critical
(5)。
如果提供程序支持日志作用域,则 IncludeScopes
将指示是否启用这些域。 有关详细信息,请参阅日志范围。
以下 appsettings.json
文件包含默认情况下启用的所有提供程序:
{
"Logging": {
"LogLevel": { // No provider, LogLevel applies to all the enabled providers.
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": { // Debug provider.
"LogLevel": {
"Default": "Information" // Overrides preceding LogLevel:Default setting.
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
"Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
"Microsoft.AspNetCore.Mvc.Razor": "Error",
"Default": "Information"
}
},
"EventSource": {
"LogLevel": {
"Microsoft": "Information"
}
},
"EventLog": {
"LogLevel": {
"Microsoft": "Information"
}
},
"AzureAppServicesFile": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Warning"
}
},
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
在上述示例中:
- 类别和级别不是建议的值。 提供该示例是为了显示所有默认提供程序。
Logging.{PROVIDER NAME}.LogLevel
中的设置会覆盖Logging.LogLevel
中的设置,其中{PROVIDER NAME}
占位符是提供程序名称。 例如,Debug.LogLevel.Default
中的级别将替代LogLevel.Default
中的级别。- 将使用每个默认提供程序别名。 每个提供程序都定义了一个别名;可在配置中使用该别名来代替完全限定的类型名称。 内置提供程序别名包括:
Console
Debug
EventSource
EventLog
AzureAppServicesFile
AzureAppServicesBlob
ApplicationInsights
Program.cs
中的日志
以下示例调用 Program.cs
中的 Builder.WebApplication.Logger 并记录信息性消息:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Logger.LogInformation("Adding Routes");
app.MapGet("/", () => "Hello World!");
app.Logger.LogInformation("Starting the app");
app.Run();
以下示例调用 Program.cs
中的 AddConsole 并记录 /Test
终结点:
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddConsole();
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapGet("/Test", async (ILogger<Program> logger, HttpResponse response) =>
{
logger.LogInformation("Testing logging in Program.cs");
await response.WriteAsync("Testing");
});
app.Run();
以下示例调用 Program.cs
中的 AddSimpleConsole,禁用颜色输出并记录 /Test
终结点:
using Microsoft.Extensions.Logging.Console;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddSimpleConsole(i => i.ColorBehavior = LoggerColorBehavior.Disabled);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapGet("/Test", async (ILogger<Program> logger, HttpResponse response) =>
{
logger.LogInformation("Testing logging in Program.cs");
await response.WriteAsync("Testing");
});
app.Run();
通过命令行、环境变量和其他配置设置日志级别
日志级别可以由任何配置提供程序设置。
所有平台上的环境变量分层键都不支持 :
分隔符。 例如,Bash 不支持 :
分隔符。 双下划线 __
是:
- 受所有平台支持。
- 自动替换为冒号,
:
。
以下命令:
- 在 Windows 上,将环境密钥
Logging:LogLevel:Microsoft
设置为值Information
。 - 使用通过 ASP.NET Core Web 应用模板创建的应用时,请测试设置。 使用
set
之后,必须在项目目录中运行dotnet run
命令。
set Logging__LogLevel__Microsoft=Information
dotnet run
前面的环境设置:
- 仅在进程中设置,这些进程是从设置进程的命令窗口启动的。
- 不由使用 Visual Studio 启动的浏览器读取。
以下 setx 命令还可以在 Windows 上设置环境键和值。 与 set
不同,setx
设置是持久的。 /M
开关在系统环境中设置变量。 如果未使用 /M
,则设置用户环境变量。
setx Logging__LogLevel__Microsoft Information /M
请考虑以下 appsettings.json
文件:
"Logging": {
"Console": {
"LogLevel": {
"Microsoft.Hosting.Lifetime": "Trace"
}
}
}
以下命令在环境中设置上述配置:
setx Logging__Console__LogLevel__Microsoft.Hosting.Lifetime Trace /M
注意
在 macOS 和 Linux 中使用包含 .
(句点)的名称配置环境变量时,请注意 Stack Exchange 上提出的“导出带有点 (.) 的变量”问题以及相应的已接受解答。
在 Azure 应用服务上,选择“设置”>“配置”页面上的“新应用程序设置”。 Azure 应用服务应用程序设置:
- 已 rest 加密并通过加密通道进行传输。
- 已作为环境变量公开。
有关详细信息,请参阅 Azure 应用:使用 Azure 门户替代应用配置。
有关使用环境变量设置 ASP.NET Core 配置值的详细信息,请参阅环境变量。 有关使用其他配置源(包括命令行、Azure Key Vault、Azure 应用配置、其他文件格式等)的信息,请参阅 ASP.NET Core 中的配置。
如何应用筛选规则
创建 ILogger<TCategoryName> 对象时,ILoggerFactory 对象将根据提供程序选择一条规则,将其应用于该记录器。 将按所选规则筛选 ILogger
实例写入的所有消息。 从可用规则中为每个提供程序和类别对选择最具体的规则。
在为给定的类别创建 ILogger
时,以下算法将用于每个提供程序:
- 选择匹配提供程序或其别名的所有规则。 如果找不到任何匹配项,则选择提供程序为空的所有规则。
- 根据上一步的结果,选择具有最长匹配类别前缀的规则。 如果找不到任何匹配项,则选择未指定类别的所有规则。
- 如果选择了多条规则,则采用最后一条 。
- 如果未选择任何规则,则使用
MinimumLevel
。
记录来自 dotnet run 和 Visual Studio 的输出
将显示使用默认日志记录提供程序创建的日志:
- 在 Visual Studio 中
- 在调试时,在“调试输出”窗口中。
- 在“ASP.NET Core Web 服务器”窗口中。
- 使用
dotnet run
运行应用时,在控制台窗口中。
以“Microsoft”类别开头的日志来自 .NET。 .NET 和应用程序代码使用相同的日志记录 API 和提供程序。
日志类别
创建 ILogger
对象时,将指定类别。 该类别包含在由此 ILogger
实例创建的每条日志消息中。 类别字符串是任意的,但约定将使用完全限定的类名称。 例如,在控制器中,名称可能为 "TodoApi.Controllers.TodoController"
。 ASP.NET Core Web 应用使用 ILogger<T>
自动获取使用完全限定类型名称 T
作为类别的 ILogger
实例:
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
_logger.LogInformation("GET Pages.PrivacyModel called.");
}
}
如需进一步分类,约定可使用分层名称,方法是将子类别追加到完全限定的类名称,然后使用 ILoggerFactory.CreateLogger
显式指定类别:
public class ContactModel : PageModel
{
private readonly ILogger _logger;
public ContactModel(ILoggerFactory logger)
{
_logger = logger.CreateLogger("TodoApi.Pages.ContactModel.MyCategory");
}
public void OnGet()
{
_logger.LogInformation("GET Pages.ContactModel called.");
}
在多个方法中使用时,使用固定名称调用 CreateLogger
很有用,这样可以按类别组织事件。
ILogger<T>
相当于使用 T
的完全限定类型名称来调用 CreateLogger
。
日志级别
下表列出了 LogLevel 值、方便的 Log{LogLevel}
扩展方法以及建议的用法:
LogLevel | “值” | 方法 | 说明 |
---|---|---|---|
Trace | 0 | LogTrace | 包含最详细的消息。 这些消息可能包含敏感的应用数据。 这些消息默认情况下处于禁用状态,并且不应在生产中启用。 |
Debug | 1 | LogDebug | 用于调试和开发。 由于量大,请在生产中小心使用。 |
Information | 2 | LogInformation | 跟踪应用的常规流。 可能具有长期值。 |
Warning | 3 | LogWarning | 对于异常事件或意外事件。 通常包括不会导致应用失败的错误或情况。 |
Error | 4 | LogError | 表示无法处理的错误和异常。 这些消息表示当前操作或请求失败,而不是整个应用失败。 |
Critical | 5 | LogCritical | 需要立即关注的失败。 例如数据丢失、磁盘空间不足。 |
None | 6 | 指定日志记录类别不应写入消息。 |
在上表中,LogLevel
按严重性由低到高的顺序列出。
Log 方法的第一个参数 LogLevel 指示日志的严重性。 大多数开发人员调用 Log{LOG LEVEL}
扩展方法,而不调用 Log(LogLevel, ...)
,其中 {LOG LEVEL}
占位符是日志级别。 例如,以下两个日志记录调用功能相同,并生成相同的日志:
[HttpGet]
public IActionResult Test1(int id)
{
var routeInfo = ControllerContext.ToCtxString(id);
_logger.Log(LogLevel.Information, MyLogEvents.TestItem, routeInfo);
_logger.LogInformation(MyLogEvents.TestItem, routeInfo);
return ControllerContext.MyDisplayRouteInfo();
}
MyLogEvents.TestItem
是事件 ID。 MyLogEvents
是示例应用的一部分,并显示在日志事件 ID 部分中。
MyDisplayRouteInfo 和 ToCtxString 由 Rick.Docs.Samples.RouteInfo NuGet 包提供。 这些方法会显示 Controller
和 Razor Page
路线信息。
下面的代码会创建 Information
和 Warning
日志:
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
return ItemToDTO(todoItem);
}
在前面的代码中,第一个 Log{LOG LEVEL}
参数 MyLogEvents.GetItem
是日志事件 ID。 第二个参数是消息模板,其中的占位符用于填写剩余方法形参提供的实参值。 本文档后面的消息模板部分介绍了方法参数。
调用相应的 Log{LOG LEVEL}
方法,以控制写入到特定存储介质的日志输出量。 例如:
- 生产中:
- 在
Trace
、Debug
或Information
级别记录时,会产生大量详细的日志消息。 为了控制成本且不超过数据存储上限,请将Trace
、Debug
或Information
级别消息记录到容量大、成本低的数据存储中。 考虑将Trace
、Debug
或Information
限制为特定类别。 - 从
Warning
到Critical
级别的日志记录应该很少产生日志消息。- 成本和存储限制通常不是问题。
- 很少有日志可以为数据存储选择提供更大的灵活性。
- 在
- 在开发过程中:
- 设置为
Warning
。 - 在进行故障排除时,添加
Trace
、Debug
或Information
消息。 要限制输出,请仅对正在调查的类别设置Trace
、Debug
或Information
。
- 设置为
ASP.NET Core 为框架事件写入日志。 例如,考虑以下对象的日志输出:
- 使用 ASP.NET Core 模板创建的 Razor Pages 应用。
- 日志记录设置为
Logging:Console:LogLevel:Microsoft:Information
。 - 导航到 Privacy 页面:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/2 GET https://localhost:5001/Privacy
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint '/Privacy'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
Route matched with {page = "/Privacy"}. Executing page /Privacy
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[101]
Executing handler method DefaultRP.Pages.PrivacyModel.OnGet - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
Executed handler method OnGet, returned result .
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
Executing an implicit handler method - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
Executed page /Privacy in 74.5188ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint '/Privacy'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 149.3023ms 200 text/html; charset=utf-8
以下 JSON 设置了 Logging:Console:LogLevel:Microsoft:Information
:
{
"Logging": { // Default, all providers.
"LogLevel": {
"Microsoft": "Warning"
},
"Console": { // Console provider.
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
日志事件 ID
每个日志都可指定一个事件 ID 。 示例应用使用 MyLogEvents
类来定义事件 ID:
public class MyLogEvents
{
public const int GenerateItems = 1000;
public const int ListItems = 1001;
public const int GetItem = 1002;
public const int InsertItem = 1003;
public const int UpdateItem = 1004;
public const int DeleteItem = 1005;
public const int TestItem = 3000;
public const int GetItemNotFound = 4000;
public const int UpdateItemNotFound = 4001;
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
return ItemToDTO(todoItem);
}
事件 ID 与一组事件相关联。 例如,与在页面上显示项列表相关的所有日志可能是 1001。
日志记录提供程序可将事件 ID 存储在 ID 字段中,存储在日志记录消息中,或者不进行存储。 调试提供程序不显示事件 ID。 控制台提供程序在类别后的括号中显示事件 ID:
info: TodoApi.Controllers.TodoItemsController[1002]
Getting item 1
warn: TodoApi.Controllers.TodoItemsController[4000]
Get(1) NOT FOUND
一些日志记录提供程序将事件 ID 存储在一个字段中,该字段允许对 ID 进行筛选。
日志消息模板
每个日志 API 都使用一个消息模板。 消息模板可包含要填写参数的占位符。 请在占位符中使用名称而不是数字。
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
return ItemToDTO(todoItem);
}
参数的顺序(而不是它们的占位符名称)决定了用于在日志消息中提供占位符值的参数。 在以下代码中,消息模板的占位符中的参数名称失序:
var apples = 1;
var pears = 2;
var bananas = 3;
_logger.LogInformation("Parameters: {Pears}, {Bananas}, {Apples}", apples, pears, bananas);
但是,这些参数按以下顺序分配给占位符:apples
、pears
、bananas
。 日志消息反映参数的顺序:
Parameters: 1, 2, 3
此方法允许日志记录提供程序实现语义或结构化日志记录。 参数本身会传递给日志记录系统,而不仅仅是格式化的消息模板。 这使日志记录提供程序可以将参数值存储为字段。 例如,考虑使用以下记录器方法:
_logger.LogInformation("Getting item {Id} at {RequestTime}", id, DateTime.Now);
例如,登录到 Azure 表存储时:
- 每个 Azure 表实体都可以有
ID
和RequestTime
属性。 - 具有属性的表简化了对记录数据的查询。 例如,查询可以找到特定
RequestTime
范围内的所有日志,而不必分析文本消息中的时间。
记录异常
记录器方法的重载采用异常参数:
[HttpGet("{id}")]
public IActionResult TestExp(int id)
{
var routeInfo = ControllerContext.ToCtxString(id);
_logger.LogInformation(MyLogEvents.TestItem, routeInfo);
try
{
if (id == 3)
{
throw new Exception("Test exception");
}
}
catch (Exception ex)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, ex, "TestExp({Id})", id);
return NotFound();
}
return ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo 和 ToCtxString 由 Rick.Docs.Samples.RouteInfo NuGet 包提供。 这些方法会显示 Controller
和 Razor Page
路线信息。
异常日志记录是特定于提供程序的。
默认日志级别
如果未设置默认日志级别,则默认的日志级别值为 Information
。
例如,考虑以下 Web 应用:
- 使用 ASP.NET Web 应用模板创建的应用。
- 已删除或重命名
appsettings.json
和appsettings.Development.json
。
使用上述设置,导航到 privacy 或 home 页会生成许多 Trace
、Debug
和 Information
消息,并在类别名称中包含 Microsoft
。
如果未在配置中设置默认日志级别,以下代码会设置默认日志级别:
var builder = WebApplication.CreateBuilder();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
通常,日志级别应在配置中指定,而不是在代码中指定。
筛选器函数
对配置或代码没有向其分配规则的所有提供程序和类别调用筛选器函数:
var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter((provider, category, logLevel) =>
{
if (provider.Contains("ConsoleLoggerProvider")
&& category.Contains("Controller")
&& logLevel >= LogLevel.Information)
{
return true;
}
else if (provider.Contains("ConsoleLoggerProvider")
&& category.Contains("Microsoft")
&& logLevel >= LogLevel.Information)
{
return true;
}
else
{
return false;
}
});
如果类别包含 Controller
或 Microsoft
,并且日志级别为 Information
或更高级别,以上代码会显示控制台日志。
通常,日志级别应在配置中指定,而不是在代码中指定。
ASP.NET Core 类别
下表包含 ASP.NET Core 使用的一些类别。
类别 | 说明 |
---|---|
Microsoft.AspNetCore |
常规 ASP.NET Core 诊断。 |
Microsoft.AspNetCore.DataProtection |
考虑、找到并使用了哪些密钥。 |
Microsoft.AspNetCore.HostFiltering |
所允许的主机。 |
Microsoft.AspNetCore.Hosting |
HTTP 请求完成的时间和启动时间。 加载了哪些承载启动程序集。 |
Microsoft.AspNetCore.Mvc |
MVC 和 Razor 诊断。 模型绑定、筛选器执行、视图编译和操作选择。 |
Microsoft.AspNetCore.Routing |
路由匹配信息。 |
Microsoft.AspNetCore.Server |
连接启动、停止和保持活动响应。 HTTP 证书信息。 |
Microsoft.AspNetCore.StaticFiles |
提供的文件。 |
若要在控制台窗口中查看更多类别,请将 appsettings.Development.json
设置为以下各项:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Trace",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
如需实体框架类别的列表,请参阅 EF 消息类别。
日志作用域
“作用域”可对一组逻辑操作分组 。 此分组可用于将相同的数据附加到作为集合的一部分而创建的每个日志。 例如,在处理事务期间创建的每个日志都可包括事务 ID。
范围:
- 是 BeginScope 方法返回的 IDisposable 类型。
- 持续到处置完毕。
以下提供程序支持范围:
要使用作用域,请在 using
块中包装记录器调用:
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
TodoItem todoItem;
var transactionId = Guid.NewGuid().ToString();
using (_logger.BeginScope(new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("TransactionId", transactionId),
}))
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound,
"Get({Id}) NOT FOUND", id);
return NotFound();
}
}
return ItemToDTO(todoItem);
}
内置日志记录提供程序
ASP.NET Core 包括以下日志记录提供程序作为共享框架的一部分:
以下日志记录提供程序由 Microsoft 提供,但不是共享框架的一部分。 它们必须作为附加 NuGet 安装。
ASP.NET Core 不包括用于将日志写入文件的日志记录提供程序。 若要将日志从 ASP.NET Core 应用写入文件,请考虑使用第三方日志记录提供程序。
有关 stdout
和使用 ASP.NET Core 模块调试日志记录的信息,请参阅对 Azure 应用服务和 IIS 上的 ASP.NET Core 进行故障排除和用于 IIS 的 ASP.NET Core 模块 (ANCM)。
控制台
Console
提供程序将输出记录到控制台。 如需详细了解如何在开发环境中查看 Console
日志,请参阅记录来自 dotnet run 和 Visual Studio 的输出。
调试
Debug
提供程序使用 System.Diagnostics.Debug 类写入日志输出。 对 System.Diagnostics.Debug.WriteLine
的调用写入到 Debug
提供程序。
在 Linux 上,Debug
提供程序日志位置取决于分发,并且可以是以下位置之一:
/var/log/message
/var/log/syslog
事件来源
EventSource
提供程序写入名称为 Microsoft-Extensions-Logging
的跨平台事件源。 在 Windows 上,提供程序使用的是 ETW。
dotnet-trace 工具
dotnet-trace
工具是一种跨平台 CLI 全局工具,可用于收集正在运行的进程的 .NET Core 跟踪。 该工具会使用 LoggingEventSource 收集 Microsoft.Extensions.Logging.EventSource 提供程序数据。
有关安装说明,请参阅dotnet-trace
。
使用 dotnet-trace
工具从应用中收集跟踪:
使用
dotnet run
命令运行此应用。确定 .NET Core 应用的进程标识符 (PID):
dotnet-trace ps
找到进程的 PID,它与应用的程序集的名称相同。
执行
dotnet-trace
命令。常规命令语法:
dotnet-trace collect -p {PID} --providers Microsoft-Extensions-Logging:{Keyword}:{Provider Level} :FilterSpecs=\" {Logger Category 1}:{Category Level 1}; {Logger Category 2}:{Category Level 2}; ... {Logger Category N}:{Category Level N}\"
使用 PowerShell 命令行界面时,将
--providers
值用单引号 ('
) 引起来:dotnet-trace collect -p {PID} --providers 'Microsoft-Extensions-Logging:{Keyword}:{Provider Level} :FilterSpecs=\" {Logger Category 1}:{Category Level 1}; {Logger Category 2}:{Category Level 2}; ... {Logger Category N}:{Category Level N}\"'
在非 Windows 平台上,添加
-f speedscope
选项,将输出跟踪文件更改为speedscope
。下表定义了关键字:
关键字 说明 1 记录有关 LoggingEventSource
的 meta 事件。 请不要从ILogger
记录事件。2 在调用 ILogger.Log()
时启用Message
事件。 以编程(未格式化)方式提供信息。4 在调用 ILogger.Log()
时启用FormatMessage
事件。 提供格式化字符串版本的信息。8 在调用 ILogger.Log()
时启用MessageJson
事件。 提供参数的 JSON 表示形式。下表列出了提供程序级别:
提供程序级别 说明 0 LogAlways
1 Critical
2 Error
3 Warning
4 Informational
5 Verbose
类别级别的分析可以是字符串或数字:
具有类别名称的值 数值 Trace
0 Debug
1 Information
2 Warning
3 Error
4 Critical
5 提供程序级别和类别级别:
- 顺序相反。
- 字符串常量并不完全相同。
如果未指定
FilterSpecs
,则EventSourceLogger
实现尝试将提供程序级别转换为类别级别,并将其应用于所有类别。提供程序级别 类别级别 Verbose
(5)Debug
(1)Informational
(4)Information
(2)Warning
(3)Warning
(3)Error
(2)Error
(4)Critical
(1)Critical
(5)如果提供了
FilterSpecs
,则列表中包含的任何类别都使用其中编码的类别级别,所有其他类别都将被筛选掉。下面的示例假定:
- 应用正在运行并调用
logger.LogDebug("12345")
。 - 进程 ID (PID) 已通过
set PID=12345
设置,其中12345
是实际的 PID。
请考虑以下命令:
dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5
上述命令:
- 捕获调试消息。
- 不应用
FilterSpecs
。 - 指定级别 5,该级别映射“调试”类别。
请考虑以下命令:
dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:5\"
上述命令:
- 不会捕获调试消息,因为类别级别 5 为
Critical
。 - 提供
FilterSpecs
。
以下命令捕获调试消息,因为类别级别 1 指定
Debug
。dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:1\"
以下命令捕获调试消息,因为类别指定
Debug
。dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:Debug\"
{Logger Category}
和{Category Level}
的FilterSpecs
条目表示其他日志筛选条件。 使用分号 (;
) 分隔FilterSpecs
条目。使用 Windows 命令 shell 的示例:
dotnet-trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:2:FilterSpecs=\"Microsoft.AspNetCore.Hosting*:4\"
上面的命令会激活:
- 事件源记录器,它用于为错误 (
2
) 生成格式化字符串 (4
)。 Informational
日志记录级别 (4
) 的Microsoft.AspNetCore.Hosting
日志记录。
通过按 Enter 键或 Ctrl+C 停止
dotnet-trace
工具。跟踪使用名称
trace.nettrace
保存在执行dotnet-trace
命令的文件夹中。使用预览功能打开跟踪。 打开
trace.nettrace
文件并浏览跟踪事件。
如果应用不使用 WebApplication.CreateBuilder 生成主机,则请向应用的日志记录配置添加事件源提供程序
有关详细信息,请参阅:
- 跟踪性能分析实用工具 (
dotnet-trace
)(.NET Core 文档) - 跟踪性能分析实用工具 (
dotnet-trace
)(dotnet/诊断 GitHub 存储库文档) - LoggingEventSource
- EventLevel
- Perfview:适用于查看事件源跟踪。
Perfview
使用 PerfView 实用工具收集和查看日志。 虽然其他工具也可以查看 ETW 日志,但在处理由 ASP.NET Core 发出的 ETW 事件时,使用 PerfView 能获得最佳体验。
要将 PerfView 配置为收集此提供程序记录的事件,请向 Additional Providers 列表添加字符串 *Microsoft-Extensions-Logging
。 请勿遗漏字符串起始处的 *
。
Windows 事件日志
EventLog
提供程序将日志输出发送到 Windows 事件日志。 与其他提供程序不同,EventLog
提供程序不继承默认的非提供程序设置。 如果未指定 EventLog
日志设置,则它们默认为 LogLevel.Warning。
若要记录低于 LogLevel.Warning 的事件,请显式设置日志级别。 以下示例将事件日志的默认日志级别设置为 LogLevel.Information:
"Logging": {
"EventLog": {
"LogLevel": {
"Default": "Information"
}
}
}
AddEventLog 重载可以传入 EventLogSettings。 如果为 null
或未指定,则使用以下默认设置:
LogName
:“Application”SourceName
:“.NET Runtime”MachineName
:使用本地计算机名称。
以下代码将 SourceName
从默认值 ".NET Runtime"
更改为 MyLogs
:
var builder = WebApplication.CreateBuilder();
builder.Logging.AddEventLog(eventLogSettings =>
{
eventLogSettings.SourceName = "MyLogs";
});
Azure 应用服务
Microsoft.Extensions.Logging.AzureAppServices
提供程序包将日志写入 Azure 应用服务应用的文件系统中的文本文件,以及 Azure 存储帐户中的 blob 存储。
共享框架中不包括该提供程序包。 若要使用提供程序,请将提供程序包添加到项目。
要配置提供程序设置,请使用 AzureFileLoggerOptions 和 AzureBlobLoggerOptions,如以下示例所示:
using Microsoft.Extensions.Logging.AzureAppServices;
var builder = WebApplication.CreateBuilder();
builder.Logging.AddAzureWebAppDiagnostics();
builder.Services.Configure<AzureFileLoggerOptions>(options =>
{
options.FileName = "azure-diagnostics-";
options.FileSizeLimit = 50 * 1024;
options.RetainedFileCountLimit = 5;
});
builder.Services.Configure<AzureBlobLoggerOptions>(options =>
{
options.BlobName = "log.txt";
});
部署到 Azure 应用服务时,应用使用 Azure 门户的“应用服务”页面的应用服务日志部分中的设置。 更新以下设置后,更改立即生效,无需重启或重新部署应用。
- 应用程序日志记录(Filesystem)
- 应用程序日志记录(Blob)
日志文件的默认位置在 D:\\home\\LogFiles\\Application
文件夹中,默认文件名为 diagnostics-yyyymmdd.txt
。 默认文件大小上限为 10 MB,默认最大保留文件数为 2。 默认的 blob 名称是 {app-name}{timestamp}/yyyy/mm/dd/hh/{guid}-applicationLog.txt
。
仅当项目在 Azure 环境中运行时,此提供程序才记录日志。
Azure 日志流式处理
Azure 日志流式处理支持从以下位置实时查看日志活动:
- 应用服务器
- Web 服务器
- 请求跟踪失败
要配置 Azure 日志流式处理,请执行以下操作:
- 从应用的门户页导航到“应用服务日志”页。
- 将“应用程序日志记录(Filesystem)”设置为“开” 。
- 选择日志级别 。 此设置仅适用于 Azure 日志流式处理。
导航到“日志流”页面以查看日志。 记录的消息使用 ILogger
接口进行记录。
Azure Application Insights
Microsoft.Extensions.Logging.ApplicationInsights
提供程序包将日志写入 Azure Application Insights。 Application Insights 是一项服务,可监视 Web 应用并提供用于查询和分析遥测数据的工具。 如果使用此提供程序,则可以使用 Application Insights 工具来查询和分析日志。
日志记录提供程序作为 Microsoft.ApplicationInsights.AspNetCore
(这是提供 ASP.NET Core 的所有可用遥测的包)的依赖项包括在内。 如果使用此包,则无需安装提供程序包。
Microsoft.ApplicationInsights.Web
包适用于 ASP.NET 4.x,而非 ASP.NET Core。
有关更多信息,请参见以下资源:
- Application Insights 概述
- 用于 ASP.NET Core 应用程序的 Application Insights:如果想要实现各种 Application Insights 遥测以及日志记录,请从这里开始。
- .NET Core ILogger 日志的 ApplicationInsightsLoggerProvider:如果要在没有 Application Insights 遥测的 rest 的情况下实现日志记录提供程序,请从这里开始。
- Application Insights 日志记录适配器
- 安装、配置和初始化 Application Insights SDK 交互式教程。
第三方日志记录提供程序
适用于 ASP.NET Core 的第三方日志记录框架:
- elmah.io(GitHub 存储库)
- Gelf(GitHub 存储库)
- JSNLog(GitHub 存储库)
- KissLog.net(GitHub 存储库)
- Log4Net(GitHub 存储库)
- NLog(GitHub 存储库)
- PLogger(GitHub 存储库)
- Sentry(GitHub 存储库)
- Serilog(GitHub 存储库)
- Stackdriver(Github 存储库)
某些第三方框架可以执行语义日志记录(又称结构化日志记录)。
使用第三方框架类似于使用以下内置提供程序之一:
- 将 NuGet 包添加到你的项目。
- 调用日志记录框架提供的
ILoggerFactory
扩展方法。
有关详细信息,请参阅各提供程序的相关文档。 Microsoft 不支持第三方日志记录提供程序。
没有异步记录器方法
日志记录应该会很快,不值得牺牲性能来使用异步代码。 如果日志记录数据存储很慢,请不要直接写入它。 考虑先将日志消息写入快速存储,然后再将其移至慢速存储。 例如,登录到 SQL Server 时,请勿直接使用 Log
方法登录,因为 Log
方法是同步的。 相反,你会将日志消息同步添加到内存中的队列,并让后台辅助线程从队列中拉出消息,以完成将数据推送到 SQL Server 的异步工作。 有关详细信息,请参阅有关如何记录到慢速数据存储的消息队列的指南 (dotnet/AspNetCore.Docs #11801)。
更改正在运行的应用中的日志级别
不可使用日志记录 API 在应用运行时更改日志记录。 但是,一些配置提供程序可重新加载配置,这将对日志记录配置立即产生影响。 例如,文件配置提供程序默认情况下重载日志记录配置。 如果在应用运行时在代码中更改了配置,则该应用可调用 IConfigurationRoot.Reload 来更新应用的日志记录配置。
ILogger 和 ILoggerFactory
ILogger<TCategoryName> 和 ILoggerFactory 接口和实现都包含在 .NET Core SDK 中。 它们还可以通过以下 NuGet 包获得:
在代码中应用日志筛选器规则
设置日志筛选器规则的首选方法是使用配置。
下面的示例演示了如何在代码中注册筛选规则:
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Logging.Debug;
var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter("System", LogLevel.Debug);
builder.Logging.AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information);
builder.Logging.AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace);
logging.AddFilter("System", LogLevel.Debug)
指定 System
类别和日志级别 Debug
。 筛选器将应用于所有提供程序,因为未配置特定的提供程序。
AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)
指定以下项:
Debug
日志记录提供程序。- 日志级别
Information
及更高级别。 - 以
"Microsoft"
开头的所有类别。
使用 SpanId
、TraceId
、ParentId
、Baggage
和 Tags
自动记录范围。
日志记录库通过 SpanId
、TraceId
、ParentId
、Baggage
和 Tags
隐式创建范围对象。 此行为是通过 ActivityTrackingOptions 配置的。
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddSimpleConsole(options =>
{
options.IncludeScopes = true;
});
builder.Logging.Configure(options =>
{
options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
| ActivityTrackingOptions.TraceId
| ActivityTrackingOptions.ParentId
| ActivityTrackingOptions.Baggage
| ActivityTrackingOptions.Tags;
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
如果设置了 traceparent
http 请求头,则日志记录范围中的 ParentId
显示来自入站 traceparent
标头的 W3C parent-id
,日志记录范围中的 SpanId
显示下一个出站步骤/跨度的更新后的 parent-id
。 有关详细信息,请参阅改变 Traceparent 字段。
创建自定义记录器
若要创建自定义记录器,请参阅在 .NET 中实现自定义日志记录提供程序。
其他资源
- 使用源生成器提高日志记录性能
[LogProperties]
和新增遥测日志记录源生成器详述- GitHub 上的 Microsoft.Extensions.Logging 源
- 查看或下载示例代码(如何下载)。
- 高性能日志记录
- 日志记录 bug 应在
dotnet/runtime
GitHub 存储库中创建。 - ASP.NET Core Blazor 日志记录
作者:Kirk Larkin、Juergen Gutsch 和 Rick Anderson
本主题介绍了 .NET 中适用于 ASP.NET Core 应用的日志记录。 有关在 .NET 中进行日志记录的详细信息,请参阅 .NET 中的日志记录。 有关登录 Blazor 应用的详细信息,请参阅 ASP.NET Core Blazor 日志记录。
日志记录提供程序
日志记录提供程序存储日志,但显示日志的 Console
提供程序除外。 例如,Azure Application Insights 提供程序将日志存储在 Azure Application Insights 中。 可以启用多个提供程序。
默认 ASP.NET Core Web 应用模板:
- 使用通用主机。
- 调用 CreateDefaultBuilder,这将添加以下日志记录提供程序:
- 控制台
- 调试
- EventSource
- EventLog:仅限 Windows
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
上面的代码显示了使用 ASP.NET Core Web 应用模板创建的 Program
类。 接下来的几节提供基于使用通用主机的 ASP.NET Core Web 应用模板的示例。 本文档稍后将介绍非托管控制台应用。
若要替代Host.CreateDefaultBuilder
添加的默认日志记录提供程序集,请调用 ClearProviders
并添加所需的日志记录提供程序。 例如,以下代码:
- 调用 ClearProviders 以从生成器中删除所有 ILoggerProvider 实例。
- 添加控制台日志记录提供程序。
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
有关其他提供程序,请参阅:
创建日志
若要创建日志,请使用依赖项注入 (DI) 中的 ILogger<TCategoryName>对象。
如下示例中:
- 创建一个记录器
ILogger<AboutModel>
,该记录器使用类型为AboutModel
的完全限定名称的日志类别。 日志类别是与每个日志关联的字符串。 - 调用 LogInformation 以在
Information
级别登录。 日志“级别”代表所记录事件的严重程度。
public class AboutModel : PageModel
{
private readonly ILogger _logger;
public AboutModel(ILogger<AboutModel> logger)
{
_logger = logger;
}
public string Message { get; set; }
public void OnGet()
{
Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
_logger.LogInformation(Message);
}
}
有关 Blazor 的信息,请参阅 ASP.NET Core Blazor 日志记录。
在 Main 和 Startup 中创建日志介绍如何在 Main
和 Startup
中创建日志。
配置日志记录
日志配置通常由 appsettings.{Environment}.json
文件的 Logging
部分提供。 以下 appsettings.Development.json
文件由 ASP.NET Core Web 应用模板生成:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
在上述 JSON 中:
- 指定了
"Default"
、"Microsoft"
和"Microsoft.Hosting.Lifetime"
类别。 "Microsoft"
类别适用于以"Microsoft"
开头的所有类别。 例如,此设置适用于"Microsoft.AspNetCore.Routing.EndpointMiddleware"
类别。"Microsoft"
类别在日志级别Warning
或更高级别记录。"Microsoft.Hosting.Lifetime"
类别比"Microsoft"
类别更具体,因此"Microsoft.Hosting.Lifetime"
类别在日志级别“Information”和更高级别记录。- 未指定特定的日志提供程序,因此
LogLevel
适用于所有启用的日志记录提供程序,但 Windows EventLog 除外。
Logging
属性可以具有 LogLevel 和日志提供程序属性。 LogLevel
指定要针对所选类别进行记录的最低级别。 在前面的 JSON 中,指定了 Information
和 Warning
日志级别。 LogLevel
表示日志的严重性,范围为 0 到 6:
Trace
= 0、Debug
= 1、Information
= 2、Warning
= 3、Error
= 4、Critical
= 5 和 None
= 6。
指定 LogLevel
时,将为指定级别和更高级别的消息启用日志记录。 在前面的 JSON 中,记录了 Information
及更高级别的 Default
类别。 例如,记录了 Information
、Warning
、Error
和 Critical
消息。 如果未指定 LogLevel
,则日志记录默认为 Information
级别。 有关详细信息,请参阅日志级别。
提供程序属性可以指定 LogLevel
属性。 提供程序下的 LogLevel
指定要为该提供程序记录的级别,并替代非提供程序日志设置。 请考虑以下 appsettings.json
文件:
{
"Logging": {
"LogLevel": { // All providers, LogLevel applies to all the enabled providers.
"Default": "Error", // Default logging, Error and higher.
"Microsoft": "Warning" // All Microsoft* categories, Warning and higher.
},
"Debug": { // Debug provider.
"LogLevel": {
"Default": "Information", // Overrides preceding LogLevel:Default setting.
"Microsoft.Hosting": "Trace" // Debug:Microsoft.Hosting category.
}
},
"EventSource": { // EventSource provider
"LogLevel": {
"Default": "Warning" // All categories of EventSource provider.
}
}
}
}
Logging.{providername}.LogLevel
中的设置将替代 Logging.LogLevel
中的设置。 在前面的 JSON 中,Debug
提供程序的默认日志级别设置为 Information
:
Logging:Debug:LogLevel:Default:Information
前面的设置为每个 Logging:Debug:
类别(Microsoft.Hosting
除外)指定 Information
日志级别。 当列出特定类别时,该特定类别将替代默认类别。 在前面的 JSON 中,Logging:Debug:LogLevel
类别 "Microsoft.Hosting"
和 "Default"
替代 Logging:LogLevel
中的设置
可以为以下任何一项指定最低日志级别:
- 特定提供程序:例如,
Logging:EventSource:LogLevel:Default:Information
- 特定类别:例如,
Logging:LogLevel:Microsoft:Warning
- 所有提供程序和所有类别:
Logging:LogLevel:Default:Warning
低于最低级别的任何日志均不会执行以下操作:
- 传递到提供程序。
- 记录或显示。
要阻止所有日志,请指定 LogLevel.None。 LogLevel.None
的值为 6,该值高于 LogLevel.Critical
(5)。
如果提供程序支持日志作用域,则 IncludeScopes
将指示是否启用这些域。 有关详细信息,请参阅日志范围
以下 appsettings.json
文件包含默认情况下启用的所有提供程序:
{
"Logging": {
"LogLevel": { // No provider, LogLevel applies to all the enabled providers.
"Default": "Error",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
},
"Debug": { // Debug provider.
"LogLevel": {
"Default": "Information" // Overrides preceding LogLevel:Default setting.
}
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.AspNetCore.Mvc.Razor.Internal": "Warning",
"Microsoft.AspNetCore.Mvc.Razor.Razor": "Debug",
"Microsoft.AspNetCore.Mvc.Razor": "Error",
"Default": "Information"
}
},
"EventSource": {
"LogLevel": {
"Microsoft": "Information"
}
},
"EventLog": {
"LogLevel": {
"Microsoft": "Information"
}
},
"AzureAppServicesFile": {
"IncludeScopes": true,
"LogLevel": {
"Default": "Warning"
}
},
"AzureAppServicesBlob": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft": "Information"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
在上述示例中:
- 类别和级别不是建议的值。 提供该示例是为了显示所有默认提供程序。
Logging.{providername}.LogLevel
中的设置将替代Logging.LogLevel
中的设置。 例如,Debug.LogLevel.Default
中的级别将替代LogLevel.Default
中的级别。- 将使用每个默认提供程序别名。 每个提供程序都定义了一个别名;可在配置中使用该别名来代替完全限定的类型名称。 内置提供程序别名包括:
- 控制台
- 调试
- EventSource
- EventLog
- AzureAppServicesFile
- AzureAppServicesBlob
- ApplicationInsights
通过命令行、环境变量和其他配置设置日志级别
日志级别可以由任何配置提供程序设置。
所有平台上的环境变量分层键都不支持 :
分隔符。 例如,Bash 不支持 :
分隔符。 双下划线 __
是:
- 受所有平台支持。
- 自动替换为冒号,
:
。
以下命令:
- 在 Windows 上,将环境密钥
Logging:LogLevel:Microsoft
设置为值Information
。 - 使用通过 ASP.NET Core Web 应用模板创建的应用时,请测试设置。 使用
set
之后,必须在项目目录中运行dotnet run
命令。
set Logging__LogLevel__Microsoft=Information
dotnet run
前面的环境设置:
- 仅在进程中设置,这些进程是从设置进程的命令窗口启动的。
- 不由使用 Visual Studio 启动的浏览器读取。
以下 setx 命令还可以在 Windows 上设置环境键和值。 与 set
不同,setx
设置是持久的。 /M
开关在系统环境中设置变量。 如果未使用 /M
,则设置用户环境变量。
setx Logging__LogLevel__Microsoft Information /M
请考虑以下 appsettings.json
文件:
"Logging": {
"Console": {
"LogLevel": {
"Microsoft.Hosting.Lifetime": "Trace"
}
}
}
以下命令在环境中设置上述配置:
setx Logging__Console__LogLevel__Microsoft.Hosting.Lifetime Trace /M
在 Azure 应用服务上,选择“设置”>“配置”页面上的“新应用程序设置”。 Azure 应用服务应用程序设置:
- 已 rest 加密并通过加密通道进行传输。
- 已作为环境变量公开。
有关详细信息,请参阅 Azure 应用:使用 Azure 门户替代应用配置。
有关使用环境变量设置 ASP.NET Core 配置值的详细信息,请参阅环境变量。 有关使用其他配置源(包括命令行、Azure Key Vault、Azure 应用配置、其他文件格式等)的信息,请参阅 ASP.NET Core 中的配置。
如何应用筛选规则
创建 ILogger<TCategoryName> 对象时,ILoggerFactory 对象将根据提供程序选择一条规则,将其应用于该记录器。 将按所选规则筛选 ILogger
实例写入的所有消息。 从可用规则中为每个提供程序和类别对选择最具体的规则。
在为给定的类别创建 ILogger
时,以下算法将用于每个提供程序:
- 选择匹配提供程序或其别名的所有规则。 如果找不到任何匹配项,则选择提供程序为空的所有规则。
- 根据上一步的结果,选择具有最长匹配类别前缀的规则。 如果找不到任何匹配项,则选择未指定类别的所有规则。
- 如果选择了多条规则,则采用最后一条 。
- 如果未选择任何规则,则使用
MinimumLevel
。
记录来自 dotnet run 和 Visual Studio 的输出
将显示使用默认日志记录提供程序创建的日志:
- 在 Visual Studio 中
- 在调试时,在“调试输出”窗口中。
- 在“ASP.NET Core Web 服务器”窗口中。
- 使用
dotnet run
运行应用时,在控制台窗口中。
以“Microsoft”类别开头的日志来自 ASP.NET Core 框架代码。 ASP.NET Core 和应用程序代码使用相同的日志记录 API 和提供程序。
日志类别
创建 ILogger
对象时,将指定类别。 该类别包含在由此 ILogger
实例创建的每条日志消息中。 类别字符串是任意的,但约定将使用类名称。 例如,在控制器中,名称可能为 "TodoApi.Controllers.TodoController"
。 ASP.NET Core Web 应用使用 ILogger<T>
自动获取使用完全限定类型名称 T
作为类别的 ILogger
实例:
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
_logger.LogInformation("GET Pages.PrivacyModel called.");
}
}
要显式指定类别,请调用 ILoggerFactory.CreateLogger
:
public class ContactModel : PageModel
{
private readonly ILogger _logger;
public ContactModel(ILoggerFactory logger)
{
_logger = logger.CreateLogger("TodoApi.Pages.ContactModel.MyCategory");
}
public void OnGet()
{
_logger.LogInformation("GET Pages.ContactModel called.");
}
在多个方法中使用时,使用固定名称调用 CreateLogger
很有用,这样可以按类别组织事件。
ILogger<T>
相当于使用 T
的完全限定类型名称来调用 CreateLogger
。
日志级别
下表列出了 LogLevel 值、方便的 Log{LogLevel}
扩展方法以及建议的用法:
LogLevel | “值” | 方法 | 描述 |
---|---|---|---|
Trace | 0 | LogTrace | 包含最详细的消息。 这些消息可能包含敏感的应用数据。 这些消息默认情况下处于禁用状态,并且不应在生产中启用。 |
调试 | 1 | LogDebug | 用于调试和开发。 由于量大,请在生产中小心使用。 |
信息 | 2 | LogInformation | 跟踪应用的常规流。 可能具有长期值。 |
警告 | 3 | LogWarning | 对于异常事件或意外事件。 通常包括不会导致应用失败的错误或情况。 |
错误 | 4 | LogError | 表示无法处理的错误和异常。 这些消息表示当前操作或请求失败,而不是整个应用失败。 |
严重 | 5 | LogCritical | 需要立即关注的失败。 例如数据丢失、磁盘空间不足。 |
无 | 6 | 指定日志记录类别不应写入任何消息。 |
在上表中,LogLevel
按严重性由低到高的顺序列出。
Log 方法的第一个参数 LogLevel 指示日志的严重性。 大多数开发人员调用 Log{LogLevel} 扩展方法,而不调用 Log(LogLevel, ...)
。 Log{LogLevel}
扩展方法调用 Log 方法并指定 LogLevel。 例如,以下两个日志记录调用功能相同,并生成相同的日志:
[HttpGet]
public IActionResult Test1(int id)
{
var routeInfo = ControllerContext.ToCtxString(id);
_logger.Log(LogLevel.Information, MyLogEvents.TestItem, routeInfo);
_logger.LogInformation(MyLogEvents.TestItem, routeInfo);
return ControllerContext.MyDisplayRouteInfo();
}
MyLogEvents.TestItem
是事件 ID。 MyLogEvents
是示例应用的一部分,并显示在日志事件 ID 部分中。
MyDisplayRouteInfo 和 ToCtxString 由 Rick.Docs.Samples.RouteInfo NuGet 包提供。 这些方法会显示 Controller
和 Razor Page
路线信息。
下面的代码会创建 Information
和 Warning
日志:
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
return ItemToDTO(todoItem);
}
在前面的代码中,第一个 Log{LogLevel}
参数 MyLogEvents.GetItem
是日志事件 ID。 第二个参数是消息模板,其中的占位符用于填写剩余方法形参提供的实参值。 本文档后面的消息模板部分介绍了方法参数。
调用相应的 Log{LogLevel}
方法,以控制写入到特定存储介质的日志输出量。 例如:
- 生产中:
- 在
Trace
或Information
级别记录日志会产生大量详细的日志消息。 为了控制成本且不超过数据存储限制,请将Trace
和Information
级别消息记录到容量大、成本低的数据存储中。 考虑将Trace
和Information
限制为特定类别。 - 从
Warning
到Critical
级别的日志记录应该很少产生日志消息。- 成本和存储限制通常不是问题。
- 很少有日志可以为数据存储选择提供更大的灵活性。
- 在
- 在开发过程中:
- 设置为
Warning
。 - 在进行故障排除时,添加
Trace
或Information
消息。 若要限制输出,请仅对正在调查的类别设置Trace
或Information
。
- 设置为
ASP.NET Core 为框架事件写入日志。 例如,考虑以下对象的日志输出:
- 使用 ASP.NET Core 模板创建的 Razor Pages 应用。
- 日志记录设置为
Logging:Console:LogLevel:Microsoft:Information
- 导航到 Privacy 页面:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/2 GET https://localhost:5001/Privacy
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint '/Privacy'
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[3]
Route matched with {page = "/Privacy"}. Executing page /Privacy
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[101]
Executing handler method DefaultRP.Pages.PrivacyModel.OnGet - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[102]
Executed handler method OnGet, returned result .
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[103]
Executing an implicit handler method - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[104]
Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
Executed page /Privacy in 74.5188ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint '/Privacy'
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished in 149.3023ms 200 text/html; charset=utf-8
以下 JSON 设置了 Logging:Console:LogLevel:Microsoft:Information
:
{
"Logging": { // Default, all providers.
"LogLevel": {
"Microsoft": "Warning"
},
"Console": { // Console provider.
"LogLevel": {
"Microsoft": "Information"
}
}
}
}
日志事件 ID
每个日志都可指定一个事件 ID 。 示例应用使用 MyLogEvents
类来定义事件 ID:
public class MyLogEvents
{
public const int GenerateItems = 1000;
public const int ListItems = 1001;
public const int GetItem = 1002;
public const int InsertItem = 1003;
public const int UpdateItem = 1004;
public const int DeleteItem = 1005;
public const int TestItem = 3000;
public const int GetItemNotFound = 4000;
public const int UpdateItemNotFound = 4001;
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
return ItemToDTO(todoItem);
}
事件 ID 与一组事件相关联。 例如,与在页面上显示项列表相关的所有日志可能是 1001。
日志记录提供程序可将事件 ID 存储在 ID 字段中,存储在日志记录消息中,或者不进行存储。 调试提供程序不显示事件 ID。 控制台提供程序在类别后的括号中显示事件 ID:
info: TodoApi.Controllers.TodoItemsController[1002]
Getting item 1
warn: TodoApi.Controllers.TodoItemsController[4000]
Get(1) NOT FOUND
一些日志记录提供程序将事件 ID 存储在一个字段中,该字段允许对 ID 进行筛选。
日志消息模板
每个日志 API 都使用一个消息模板。 消息模板可包含要填写参数的占位符。 请在占位符中使用名称而不是数字。
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
return ItemToDTO(todoItem);
}
参数的顺序(而不是它们的占位符名称)决定了用于在日志消息中提供占位符值的参数。 在以下代码中,消息模板的占位符中的参数名称失序:
var apples = 1;
var pears = 2;
var bananas = 3;
_logger.LogInformation("Parameters: {pears}, {bananas}, {apples}", apples, pears, bananas);
但是,这些参数按以下顺序分配给占位符:apples
、pears
、bananas
。 日志消息反映参数的顺序:
Parameters: 1, 2, 3
此方法允许日志记录提供程序实现语义或结构化日志记录。 参数本身会传递给日志记录系统,而不仅仅是格式化的消息模板。 这使日志记录提供程序可以将参数值存储为字段。 例如,考虑使用以下记录器方法:
_logger.LogInformation("Getting item {Id} at {RequestTime}", id, DateTime.Now);
例如,登录到 Azure 表存储时:
- 每个 Azure 表实体都可以有
ID
和RequestTime
属性。 - 具有属性的表简化了对记录数据的查询。 例如,查询可以找到特定
RequestTime
范围内的所有日志,而不必分析文本消息中的时间。
记录异常
记录器方法的重载采用异常参数:
[HttpGet("{id}")]
public IActionResult TestExp(int id)
{
var routeInfo = ControllerContext.ToCtxString(id);
_logger.LogInformation(MyLogEvents.TestItem, routeInfo);
try
{
if (id == 3)
{
throw new Exception("Test exception");
}
}
catch (Exception ex)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound, ex, "TestExp({Id})", id);
return NotFound();
}
return ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo 和 ToCtxString 由 Rick.Docs.Samples.RouteInfo NuGet 包提供。 这些方法会显示 Controller
和 Razor Page
路线信息。
异常日志记录是特定于提供程序的。
默认日志级别
如果未设置默认日志级别,则默认的日志级别值为 Information
。
例如,考虑以下 Web 应用:
- 使用 ASP.NET Web 应用模板创建的应用。
- 已删除或重命名
appsettings.json
和appsettings.Development.json
。
使用上述设置,导航到 privacy 或 home 页会生成许多 Trace
、Debug
和 Information
消息,并在类别名称中包含 Microsoft
。
如果未在配置中设置默认日志级别,以下代码会设置默认日志级别:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
通常,日志级别应在配置中指定,而不是在代码中指定。
筛选器函数
对配置或代码没有向其分配规则的所有提供程序和类别调用筛选器函数:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddFilter((provider, category, logLevel) =>
{
if (provider.Contains("ConsoleLoggerProvider")
&& category.Contains("Controller")
&& logLevel >= LogLevel.Information)
{
return true;
}
else if (provider.Contains("ConsoleLoggerProvider")
&& category.Contains("Microsoft")
&& logLevel >= LogLevel.Information)
{
return true;
}
else
{
return false;
}
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
如果类别包含 Controller
或 Microsoft
,并且日志级别为 Information
或更高级别,以上代码会显示控制台日志。
通常,日志级别应在配置中指定,而不是在代码中指定。
ASP.NET Core 和 EF Core 类别
下表包含 ASP.NET Core 和 Entity Framework Core 使用的一些类别,并带有有关日志的注释:
类别 | 说明 |
---|---|
Microsoft.AspNetCore | 常规 ASP.NET Core 诊断。 |
Microsoft.AspNetCore.DataProtection | 考虑、找到并使用了哪些密钥。 |
Microsoft.AspNetCore.HostFiltering | 所允许的主机。 |
Microsoft.AspNetCore.Hosting | HTTP 请求完成的时间和启动时间。 加载了哪些承载启动程序集。 |
Microsoft.AspNetCore.Mvc | MVC 和 Razor 诊断。 模型绑定、筛选器执行、视图编译和操作选择。 |
Microsoft.AspNetCore.Routing | 路由匹配信息。 |
Microsoft.AspNetCore.Server | 连接启动、停止和保持活动响应。 HTTP 证书信息。 |
Microsoft.AspNetCore.StaticFiles | 提供的文件。 |
Microsoft.EntityFrameworkCore | 常规 Entity Framework Core 诊断。 数据库活动和配置、更改检测、迁移。 |
若要在控制台窗口中查看更多类别,请将 appsettings.Development.json
设置为以下各项:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Trace",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
日志作用域
“作用域”可对一组逻辑操作分组 。 此分组可用于将相同的数据附加到作为集合的一部分而创建的每个日志。 例如,在处理事务期间创建的每个日志都可包括事务 ID。
范围:
- 是 BeginScope 方法返回的 IDisposable 类型。
- 持续到处置完毕。
以下提供程序支持范围:
要使用作用域,请在 using
块中包装记录器调用:
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
TodoItem todoItem;
var transactionId = Guid.NewGuid().ToString();
using (_logger.BeginScope(new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("TransactionId", transactionId),
}))
{
_logger.LogInformation(MyLogEvents.GetItem, "Getting item {Id}", id);
todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
_logger.LogWarning(MyLogEvents.GetItemNotFound,
"Get({Id}) NOT FOUND", id);
return NotFound();
}
}
return ItemToDTO(todoItem);
}
内置日志记录提供程序
ASP.NET Core 包括以下日志记录提供程序作为共享框架的一部分:
以下日志记录提供程序由 Microsoft 提供,但不是共享框架的一部分。 它们必须作为附加 NuGet 安装。
ASP.NET Core 不包括用于将日志写入文件的日志记录提供程序。 若要将日志从 ASP.NET Core 应用写入文件,请考虑使用第三方日志记录提供程序。
有关 stdout
和使用 ASP.NET Core 模块调试日志记录的信息,请参阅对 Azure 应用服务和 IIS 上的 ASP.NET Core 进行故障排除和用于 IIS 的 ASP.NET Core 模块 (ANCM)。
控制台
Console
提供程序将输出记录到控制台。 如需详细了解如何在开发环境中查看 Console
日志,请参阅记录来自 dotnet run 和 Visual Studio 的输出。
调试
Debug
提供程序使用 System.Diagnostics.Debug 类写入日志输出。 对 System.Diagnostics.Debug.WriteLine
的调用写入到 Debug
提供程序。
在 Linux 上,Debug
提供程序日志位置取决于分发,并且可以是以下位置之一:
- /var/log/message
- /var/log/syslog
事件来源
EventSource
提供程序写入名称为 Microsoft-Extensions-Logging
的跨平台事件源。 在 Windows 上,提供程序使用的是 ETW。
dotnet 跟踪工具
dotnet-trace 工具是一种跨平台 CLI 全局工具,可用于收集正在运行的进程的 .NET Core 跟踪。 该工具会使用 LoggingEventSource 收集 Microsoft.Extensions.Logging.EventSource 提供程序数据。
有关安装说明,请参阅 dotnet-trace。
使用 dotnet 跟踪工具从应用中收集跟踪:
使用
dotnet run
命令运行此应用。确定 .NET Core 应用的进程标识符 (PID):
dotnet trace ps
找到进程的 PID,它与应用的程序集的名称相同。
执行
dotnet trace
命令。常规命令语法:
dotnet trace collect -p {PID} --providers Microsoft-Extensions-Logging:{Keyword}:{Provider Level} :FilterSpecs=\" {Logger Category 1}:{Category Level 1}; {Logger Category 2}:{Category Level 2}; ... {Logger Category N}:{Category Level N}\"
使用 PowerShell 命令行界面时,将
--providers
值用单引号 ('
) 引起来:dotnet trace collect -p {PID} --providers 'Microsoft-Extensions-Logging:{Keyword}:{Provider Level} :FilterSpecs=\" {Logger Category 1}:{Category Level 1}; {Logger Category 2}:{Category Level 2}; ... {Logger Category N}:{Category Level N}\"'
在非 Windows 平台上,添加
-f speedscope
选项,将输出跟踪文件更改为speedscope
。下表定义了关键字:
关键字 说明 1 记录有关 LoggingEventSource
的 meta 事件。 请不要从ILogger
记录事件。2 在调用 ILogger.Log()
时启用Message
事件。 以编程(未格式化)方式提供信息。4 在调用 ILogger.Log()
时启用FormatMessage
事件。 提供格式化字符串版本的信息。8 在调用 ILogger.Log()
时启用MessageJson
事件。 提供参数的 JSON 表示形式。下表列出了提供程序级别:
提供程序级别 说明 0 LogAlways
1 Critical
2 Error
3 Warning
4 Informational
5 Verbose
类别级别的分析可以是字符串或数字:
具有类别名称的值 数值 Trace
0 Debug
1 Information
2 Warning
3 Error
4 Critical
5 提供程序级别和类别级别:
- 顺序相反。
- 字符串常量并不完全相同。
如果未指定
FilterSpecs
,则EventSourceLogger
实现尝试将提供程序级别转换为类别级别,并将其应用于所有类别。提供程序级别 类别级别 Verbose
(5)Debug
(1)Informational
(4)Information
(2)Warning
(3)Warning
(3)Error
(2)Error
(4)Critical
(1)Critical
(5)如果提供了
FilterSpecs
,则列表中包含的任何类别都使用其中编码的类别级别,所有其他类别都将被筛选掉。下面的示例假定:
- 应用正在运行并调用
logger.LogDebug("12345")
。 - 进程 ID (PID) 已通过
set PID=12345
设置,其中12345
是实际的 PID。
请考虑以下命令:
dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5
上述命令:
- 捕获调试消息。
- 不应用
FilterSpecs
。 - 指定级别 5,该级别映射“调试”类别。
请考虑以下命令:
dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:5\"
上述命令:
- 不会捕获调试消息,因为类别级别 5 为
Critical
。 - 提供
FilterSpecs
。
以下命令捕获调试消息,因为类别级别 1 指定
Debug
。dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:1\"
以下命令捕获调试消息,因为类别指定
Debug
。dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:5:\"FilterSpecs=*:Debug\"
{Logger Category}
和{Category Level}
的FilterSpecs
条目表示其他日志筛选条件。 使用分号 (;
) 分隔FilterSpecs
条目。使用 Windows 命令 shell 的示例:
dotnet trace collect -p %PID% --providers Microsoft-Extensions-Logging:4:2:FilterSpecs=\"Microsoft.AspNetCore.Hosting*:4\"
上面的命令会激活:
- 事件源记录器,它用于为错误 (
2
) 生成格式化字符串 (4
)。 Informational
日志记录级别 (4
) 的Microsoft.AspNetCore.Hosting
日志记录。
通过按 Enter 键或 Ctrl+C 停止 dotnet 跟踪工具。
跟踪使用名称 trace.nettrace 保存在执行
dotnet trace
命令的文件夹中 。使用预览功能打开跟踪。 打开 trace.nettrace 文件并浏览跟踪事件 。
如果应用不使用 CreateDefaultBuilder
生成主机,则请向应用的日志记录配置添加事件源提供程序
有关详细信息,请参见:
- 跟踪性能分析实用工具 (dotnet-trace)(.NET Core 文档)
- 跟踪性能分析实用工具 (dotnet-trace)(dotnet/诊断 GitHub 存储库文档)
- LoggingEventSource 类(.NET API 浏览器)
- EventLevel
- LoggingEventSource 参考源 (3.0):要获得其他版本的参考源,请将分支更改为
release/{Version}
,其中{Version}
是所需的 ASP.NET Core 版本。 - Perfview:适用于查看事件源跟踪。
Perfview
使用 PerfView 实用工具收集和查看日志。 虽然其他工具也可以查看 ETW 日志,但在处理由 ASP.NET Core 发出的 ETW 事件时,使用 PerfView 能获得最佳体验。
要将 PerfView 配置为收集此提供程序记录的事件,请向 Additional Providers 列表添加字符串 *Microsoft-Extensions-Logging
。 请勿遗漏字符串起始处的 *
。
Windows 事件日志
EventLog
提供程序将日志输出发送到 Windows 事件日志。 与其他提供程序不同,EventLog
提供程序不继承默认的非提供程序设置。 如果未指定 EventLog
日志设置,则它们默认为 LogLevel.Warning。
若要记录低于 LogLevel.Warning 的事件,请显式设置日志级别。 以下示例将事件日志的默认日志级别设置为 LogLevel.Information:
"Logging": {
"EventLog": {
"LogLevel": {
"Default": "Information"
}
}
}
AddEventLog 重载可以传入 EventLogSettings。 如果为 null
或未指定,则使用以下默认设置:
LogName
:“Application”SourceName
:“.NET Runtime”MachineName
:使用本地计算机名称。
以下代码将 SourceName
从默认值 ".NET Runtime"
更改为 MyLogs
:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddEventLog(eventLogSettings =>
{
eventLogSettings.SourceName = "MyLogs";
});
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Azure 应用服务
Microsoft.Extensions.Logging.AzureAppServices 提供程序包将日志写入 Azure App Service 应用的文件系统,以及 Azure 存储帐户中的 blob 存储。
共享框架中不包括该提供程序包。 若要使用提供程序,请将提供程序包添加到项目。
要配置提供程序设置,请使用 AzureFileLoggerOptions 和 AzureBlobLoggerOptions,如以下示例所示:
public class Scopes
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging => logging.AddAzureWebAppDiagnostics())
.ConfigureServices(serviceCollection => serviceCollection
.Configure<AzureFileLoggerOptions>(options =>
{
options.FileName = "azure-diagnostics-";
options.FileSizeLimit = 50 * 1024;
options.RetainedFileCountLimit = 5;
})
.Configure<AzureBlobLoggerOptions>(options =>
{
options.BlobName = "log.txt";
}))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
部署到 Azure 应用服务时,应用使用 Azure 门户的“应用服务”页面的应用服务日志部分中的设置。 更新以下设置后,更改立即生效,无需重启或重新部署应用。
- 应用程序日志记录(Filesystem)
- 应用程序日志记录(Blob)
日志文件的默认位置是 D:\home\LogFiles\Application 文件夹,默认文件名为 diagnostics-yyyymmdd.txt。 默认文件大小上限为 10 MB,默认最大保留文件数为 2。 默认 blob 名为 {app-name}{timestamp}/yyyy/mm/dd/hh/{guid}-applicationLog.txt 。
仅当项目在 Azure 环境中运行时,此提供程序才记录日志。
Azure 日志流式处理
Azure 日志流式处理支持从以下位置实时查看日志活动:
- 应用服务器
- Web 服务器
- 请求跟踪失败
要配置 Azure 日志流式处理,请执行以下操作:
- 从应用的门户页导航到“应用服务日志”页。
- 将“应用程序日志记录(Filesystem)”设置为“开” 。
- 选择日志级别 。 此设置仅适用于 Azure 日志流式处理。
导航到“日志流”页面以查看日志。 记录的消息使用 ILogger
接口进行记录。
Azure Application Insights
Microsoft.Extensions.Logging.ApplicationInsights 提供程序包将日志写入 Azure Application Insights。 Application Insights 是一项服务,可监视 Web 应用并提供用于查询和分析遥测数据的工具。 如果使用此提供程序,则可以使用 Application Insights 工具来查询和分析日志。
日志记录提供程序作为 Microsoft.ApplicationInsights.AspNetCore(这是提供 ASP.NET Core 的所有可用遥测的包)的依赖项包括在内。 如果使用此包,则无需安装提供程序包。
Microsoft.ApplicationInsights.Web 包适用于 ASP.NET 4.x,而不适用于 ASP.NET Core。
有关更多信息,请参见以下资源:
- Application Insights 概述
- 用于 ASP.NET Core 应用程序的 Application Insights - 如果想要实现各种 Application Insights 遥测以及日志记录,请从这里开始。
- .NET Core ILogger 日志的 ApplicationInsightsLoggerProvider - 如果要在没有 Application Insights 遥测的 rest 的情况下实现日志记录提供程序,请从这里开始。
- Application Insights 日志记录适配器。
- 安装、配置和初始化 Application Insights SDK 交互式教程。
第三方日志记录提供程序
适用于 ASP.NET Core 的第三方日志记录框架:
- elmah.io(GitHub 存储库)
- Gelf(GitHub 存储库)
- JSNLog(GitHub 存储库)
- KissLog.net(GitHub 存储库)
- Log4Net(GitHub 存储库)
- NLog(GitHub 存储库)
- PLogger(GitHub 存储库)
- Sentry(GitHub 存储库)
- Serilog(GitHub 存储库)
- Stackdriver(Github 存储库)
某些第三方框架可以执行语义日志记录(又称结构化日志记录)。
使用第三方框架类似于使用以下内置提供程序之一:
- 将 NuGet 包添加到你的项目。
- 调用日志记录框架提供的
ILoggerFactory
扩展方法。
有关详细信息,请参阅各提供程序的相关文档。 Microsoft 不支持第三方日志记录提供程序。
非托管控制台应用
若要通过示例了解如何在非 Web 控制台应用中使用一般主机,请参阅后台任务示例应用的 Program.cs
文件(在 ASP.NET Core 中使用托管服务实现后台任务)。
对于没有通用主机的应用,日志记录代码在添加提供程序和创建记录器的方式上有所不同。
日志记录提供程序
在非主机控制台应用中,在创建 LoggerFactory
时调用提供程序的 Add{provider name}
扩展方法:
class Program
{
static void Main(string[] args)
{
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole()
.AddEventLog();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");
}
}
创建日志
若要创建日志,请使用 ILogger<TCategoryName> 对象。 使用 LoggerFactory
创建一个 ILogger
。
以下示例创建类别为 LoggingConsoleApp.Program
的记录器。
class Program
{
static void Main(string[] args)
{
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole()
.AddEventLog();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");
}
}
在以下示例中,记录器用于创建级别为 Information
的日志。 日志“级别”代表所记录事件的严重程度。
class Program
{
static void Main(string[] args)
{
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
.AddConsole()
.AddEventLog();
});
ILogger logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Example log message");
}
}
主机构造过程中的日志
不直接支持在主机构造期间进行日志记录。 但是,可以使用单独的记录器。 在以下示例中,Serilog 记录器用于登录 CreateHostBuilder
。 AddSerilog
使用 Log.Logger
中指定的静态配置:
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var builtConfig = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddCommandLine(args)
.Build();
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File(builtConfig["Logging:FilePath"])
.CreateLogger();
try
{
return Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddRazorPages();
})
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddConfiguration(builtConfig);
})
.ConfigureLogging(logging =>
{
logging.AddSerilog();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
catch (Exception ex)
{
Log.Fatal(ex, "Host builder error");
throw;
}
finally
{
Log.CloseAndFlush();
}
}
}
配置依赖于 ILogger 的服务
由于为 Web 主机创建了单独的 DI 容器,所以在 ASP.NET Core 的早期版本中,构造函数将记录器注入到 Startup
工作。 若要了解为何仅为通用主机创建一个容器,请参阅重大更改公告。
若要配置依赖于 ILogger<T>
的服务,请使用构造函数注入或提供工厂方法。 只有在没有其他选择的情况下,才建议使用工厂方法。 例如,假设某个服务需要由 DI 提供的 ILogger<T>
实例:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRazorPages();
services.AddSingleton<IMyService>((container) =>
{
var logger = container.GetRequiredService<ILogger<MyService>>();
return new MyService() { Logger = logger };
});
}
前面突出显示的代码是 Func<T,TResult>,该代码在 DI 容器第一次需要构造 MyService
实例时运行。 可以用这种方式访问任何已注册的服务。
在 Main 中创建日志
以下代码通过在构建主机之后从 DI 获取 ILogger
实例来登录 Main
:
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Host created.");
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
启动时创建日志
以下代码在 Startup.Configure
中写入日志:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
logger.LogInformation("In Development.");
app.UseDeveloperExceptionPage();
}
else
{
logger.LogInformation("Not Development.");
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
不支持在 Startup.ConfigureServices
方法中完成 DI 容器设置之前就写入日志:
- 不支持将记录器注入到
Startup
构造函数中。 - 不支持将记录器注入到
Startup.ConfigureServices
方法签名中
这一限制的原因是,日志记录依赖于 DI 和配置,而配置又依赖于 DI。 在完成 ConfigureServices
之前,不会设置 DI 容器。
有关配置依赖于 ILogger<T>
的服务或为什么在早期版本中可以使用构造函数将记录器注入 Startup
的信息,请参阅配置依赖 ILogger 的服务
没有异步记录器方法
日志记录应该会很快,不值得牺牲性能来使用异步代码。 如果日志记录数据存储很慢,请不要直接写入它。 考虑先将日志消息写入快速存储,然后再将其移至慢速存储。 例如,登录到 SQL Server 时,请勿直接使用 Log
方法登录,因为 Log
方法是同步的。 相反,你会将日志消息同步添加到内存中的队列,并让后台辅助线程从队列中拉出消息,以完成将数据推送到 SQL Server 的异步工作。 有关详细信息,请参阅此 GitHub 问题。
更改正在运行的应用中的日志级别
不可使用日志记录 API 在应用运行时更改日志记录。 但是,一些配置提供程序可重新加载配置,这将对日志记录配置立即产生影响。 例如,文件配置提供程序默认情况下重载日志记录配置。 如果在应用运行时在代码中更改了配置,则该应用可调用 IConfigurationRoot.Reload 来更新应用的日志记录配置。
ILogger 和 ILoggerFactory
ILogger<TCategoryName> 和 ILoggerFactory 接口和实现都包含在 .NET Core SDK 中。 它们还可以通过以下 NuGet 包获得:
- 这些接口位于 Microsoft.Extensions.Logging.Abstractions 中。
- 默认实现位于 Microsoft.Extensions.Logging 中。
在代码中应用日志筛选器规则
设置日志筛选器规则的首选方法是使用配置。
下面的示例演示了如何在代码中注册筛选规则:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
logging.AddFilter("System", LogLevel.Debug)
.AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)
.AddFilter<ConsoleLoggerProvider>("Microsoft", LogLevel.Trace))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
logging.AddFilter("System", LogLevel.Debug)
指定 System
类别和日志级别 Debug
。 筛选器将应用于所有提供程序,因为未配置特定的提供程序。
AddFilter<DebugLoggerProvider>("Microsoft", LogLevel.Information)
指定以下项:
Debug
日志记录提供程序。- 日志级别
Information
及更高级别。 - 以
"Microsoft"
开头的所有类别。
使用 SpanId、TraceId 和 ParentId 自动记录范围
日志记录库通过 SpanId
、TraceId
和 ParentId
隐式创建范围对象。 此行为是通过 ActivityTrackingOptions 配置的。
var loggerFactory = LoggerFactory.Create(logging =>
{
logging.Configure(options =>
{
options.ActivityTrackingOptions = ActivityTrackingOptions.SpanId
| ActivityTrackingOptions.TraceId
| ActivityTrackingOptions.ParentId;
}).AddSimpleConsole(options =>
{
options.IncludeScopes = true;
});
});
如果设置了 traceparent
http 请求头,则日志记录范围中的 ParentId
显示来自入站 traceparent
标头的 W3C parent-id
,日志记录范围中的 SpanId
显示下一个出站步骤/跨度的更新后的 parent-id
。 有关详细信息,请参阅改变 Traceparent 字段。
创建自定义记录器
若要创建自定义记录器,请参阅在 .NET 中实现自定义日志记录提供程序。
其他资源
- 高性能日志记录
- 记录错误应在 github.com/dotnet/runtime/ 存储库中创建。
- ASP.NET Core Blazor 日志记录