Logging (ghi nhật ký) trong .NET và ASP.NET Core
Bài viết này mô tả logging (ghi nhật ký) trong các ứng dụng ASP.NET Core. Để có hướng dẫn chung về logging trong .NET, xem Logging trong C# và .NET.
Logging providers (nhà cung cấp ghi nhật ký)
ASP.NET Core hỗ trợ logging có hiệu năng cao, có cấu trúc thông qua API ILogger để giúp bạn theo dõi hành vi ứng dụng và chẩn đoán sự cố. Log được ghi vào các đích khác nhau bằng cách cấu hình logging providers. Một tập hợp các logging providers được tích hợp sẵn trong framework, và có nhiều providers của bên thứ ba. Nhiều providers có thể được bật trong một ứng dụng.
Hầu hết các logging providers ghi log vào một hệ thống lưu trữ dữ liệu. Ví dụ, provider Azure Application Insights lưu log trong Azure Application Insights. Provider Console chỉ hiển thị log ra màn hình console, hữu ích khi chạy ứng dụng local để theo dõi và debug theo thời gian thực.
Các ứng dụng tạo từ template ASP.NET Core web app gọi WebApplication.CreateBuilder trong file Program, thêm các logging providers mặc định sau:
ConsoleDebugEventSource- Windows
EventLog
var builder = WebApplication.CreateBuilder(args);
Để ghi đè các logging providers mặc định, gọi ClearProviders trên WebApplicationBuilder.Logging và dùng các extension methods của logging provider để thêm providers. Ví dụ sau chỉ thiết lập provider Console:
var builder = WebApplication.CreateBuilder(args); builder.Logging.ClearProviders(); builder.Logging.AddConsole();
Hoặc có thể viết như sau với ILoggingBuilder của ConfigureLogging:
var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
});Logging output (đầu ra nhật ký)
Log được tạo bởi các logging providers mặc định được hiển thị:
- Trong Visual Studio
- Trong cửa sổ Debug output khi debug.
- Trong cửa sổ ASP.NET Core Web Server.
- Trong command shell khi chạy ứng dụng với lệnh
dotnet run.
Tạo log messages
Để tạo log messages, dùng đối tượng ILogger<TCategoryName> từ dependency injection (DI) (chèn phụ thuộc).
Các ví dụ sau:
- Tạo một ILogger chỉ định một category (danh mục) log dựa trên tên đầy đủ của kiểu. Category log là một chuỗi được liên kết với mỗi log, hữu ích để xác định, sắp xếp và lọc log messages.
- Gọi LogInformation để ghi log ở mức Information. Level (mức độ) log chỉ ra mức độ nghiêm trọng của sự kiện được ghi.
Trong trang counter Razor Pages (Pages/Privacy.cshtml.cs):
public class PrivacyModel(ILogger<PrivacyModel> logger) : PageModel
{
public void OnGet() => logger.LogInformation("Privacy page visited at {DT}",
DateTime.UtcNow);
}Log message template (mẫu thông điệp nhật ký)
Log message template có thể chứa các placeholders (chỗ giữ chỗ) cho các đối số được cung cấp. Dùng tên cho các placeholders, không dùng số.
Logger.LogInformation(LogEvent.GetItem, "Getting item {Id}", id);Logger.LogWarning(LogEvent.GetItemNotFound, "Get({Id}) NOT FOUND", id);Thứ tự của các tham số, không phải tên placeholder, quyết định tham số nào được dùng để cung cấp giá trị cho placeholders trong log messages:
var apples = 1;
var pears = 2;
var bananas = 3;
Logger.LogInformation("{Pears}, {Bananas}, {Apples}", apples, pears, bananas);Kết quả: 1, 2, 3
Cách tiếp cận này cho phép các logging providers thực hiện semantic logging hoặc structured logging (ghi nhật ký ngữ nghĩa/có cấu trúc). Bản thân các đối số được truyền vào hệ thống logging, không chỉ là chuỗi message đã được format.
Log at app startup (ghi log khi khởi động ứng dụng)
Ví dụ sau gọi WebApplication.Logger trong file Program:
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();Configure logging (cấu hình ghi nhật ký)
Khi tạo đối tượng ILogger, một category được chỉ định. Category đó được bao gồm trong mỗi log message được tạo bởi instance đó của logger.
Log level xác định mức độ chi tiết cho log messages theo mức mặc định cho toàn bộ ứng dụng và cho các assembly cụ thể.
App settings (cài đặt ứng dụng)
Cấu hình logging thường được cung cấp bởi phần Logging của file appsettings.{ENVIRONMENT}.json. File appsettings.Development.json được tạo từ template:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}Trong JSON trên:
- Các category
"Default"và"Microsoft.AspNetCore"được chỉ định. - Category
"Microsoft.AspNetCore"áp dụng cho tất cả categories bắt đầu bằng"Microsoft.AspNetCore". - Category
"Microsoft.AspNetCore"ghi log ở mứcWarningvà cao hơn.
Thuộc tính Logging có thể có thuộc tính LogLevel và log provider. LogLevel chỉ định mức tối thiểu để ghi log cho các categories được chọn. Các mức LogLevel và giá trị enum tương ứng:
| Log Level | Value |
|---|---|
Trace | 0 |
Debug | 1 |
Information | 2 |
Warning | 3 |
Error | 4 |
Critical | 5 |
None | 6 |
Khi chỉ định LogLevel, logging được bật cho các messages ở mức đó và cao hơn.
Command shell (giao diện dòng lệnh)
Biến môi trường cho cấu hình logging có thể được đặt qua command shell.
Dấu hai chấm (:) không hoạt động với các khóa phân cấp biến môi trường trên tất cả platforms. Tất cả platforms hỗ trợ cú pháp gạch dưới đôi (__) và tự động thay thế bằng dấu hai chấm (:).
set Logging__LogLevel__Microsoft=Information
Configure Azure App Service
Trên Azure App Service, đặt biến môi trường logging theo hướng dẫn Configure an App Service app.
Log category (danh mục nhật ký)
Khi tạo đối tượng ILogger, một category được chỉ định. Category string là tùy ý, nhưng quy ước là dùng tên class đầy đủ. Các ứng dụng ASP.NET Core web dùng ILogger<T> để tạo logger instance dùng tên kiểu đầy đủ của T làm category.
Log messages với category bắt đầu bằng "Microsoft" là từ .NET. Thông thường, log messages bắt đầu bằng tên assembly của ứng dụng là từ ứng dụng.
Log event ID (ID sự kiện nhật ký)
Mỗi log message có thể chỉ định một event ID. Ví dụ tạo tập hợp event IDs tùy chỉnh:
public class LogEvent
{
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;
}Log level (mức độ nhật ký)
Bảng sau mô tả các mức logging từ thấp đến cao theo mức độ nghiêm trọng:
LogLevel | Value | Method | Mô tả |
|---|---|---|---|
Trace | 0 | LogTrace | Chứa các messages chi tiết nhất. Có thể chứa dữ liệu nhạy cảm. Bị tắt theo mặc định, không nên bật trong production. |
Debug | 1 | LogDebug | Dành cho debugging và development. Dùng cẩn thận trong production vì lượng messages lớn. |
Information | 2 | LogInformation | Theo dõi luồng chung của ứng dụng. |
Warning | 3 | LogWarning | Cho các sự kiện bất thường hoặc không mong đợi. Thường bao gồm các lỗi hoặc điều kiện không làm ứng dụng thất bại. |
Error | 4 | LogError | Thường dùng cho các lỗi và ngoại lệ chưa được xử lý. Các messages này chỉ ra lỗi trong thao tác hoặc request hiện tại, không phải lỗi toàn ứng dụng. |
Critical | 5 | LogCritical | Cho các lỗi cần chú ý ngay lập tức, như mất dữ liệu hoặc hết dung lượng đĩa. |
None | 6 | — | Chỉ định category logging không nên ghi messages. |
Change log levels in a running app (thay đổi mức log khi đang chạy)
Logging API không hỗ trợ thay đổi log levels trong khi ứng dụng đang chạy. Tuy nhiên, một số configuration providers có khả năng tải lại cấu hình, có hiệu lực ngay lập tức.
How filtering rules are applied (cách áp dụng quy tắc lọc)
Khi tạo đối tượng ILogger<TCategoryName>, đối tượng ILoggerFactory chọn một quy tắc duy nhất cho mỗi provider để áp dụng cho logger đó. Tất cả messages được ghi bởi instance ILogger được lọc dựa trên các quy tắc đã chọn.
Thuật toán sử dụng cho mỗi provider khi tạo ILogger cho một category cho trước:
- Chọn tất cả quy tắc khớp với provider hoặc alias của nó. Nếu không tìm thấy, chọn tất cả quy tắc với provider rỗng.
- Từ kết quả trước, chọn quy tắc có prefix category dài nhất khớp. Nếu không tìm thấy, chọn tất cả quy tắc không chỉ định category.
- Nếu chọn nhiều quy tắc, lấy quy tắc cuối cùng.
- Nếu không chọn quy tắc nào, dùng
MinimumLevel.
ILogger và ILoggerFactory
Các interface ILogger<TCategoryName> và ILoggerFactory và các implementations được bao gồm trong .NET SDK.
Log exceptions (ghi nhật ký ngoại lệ)
Các phương thức logger có overloads nhận tham số exception:
try
{
...
throw new Exception("Test exception");
}
catch (Exception ex)
{
Logger.LogWarning(LogEvent.GetItemNotFound, ex, "Test exception at {DT}",
DateTime.UtcNow);
}Default log level (mức log mặc định)
Nếu mức log mặc định không được đặt rõ ràng, mặc định là Information.
var builder = WebApplication.CreateBuilder(); builder.Logging.SetMinimumLevel(LogLevel.Warning);
Filter function (hàm lọc)
Hàm lọc được gọi cho tất cả providers và categories không có quy tắc được gán bởi cấu hình hoặc code:
var builder = WebApplication.CreateBuilder();
builder.Logging.AddFilter((provider, category, logLevel) =>
{
if (provider is not null && category is not null)
{
return provider.Contains("ConsoleLoggerProvider")
&& (category.Contains("Page") || category.Contains("Microsoft"))
&& logLevel >= LogLevel.Information;
}
return false;
});ASP.NET Core categories (danh mục ASP.NET Core)
Bảng sau chứa một số logging categories được dùng bởi ASP.NET Core:
| Category | Ghi chú |
|---|---|
Microsoft.AspNetCore | Chẩn đoán chung ASP.NET Core. |
Microsoft.AspNetCore.DataProtection | Các data protection keys đã được xem xét, tìm thấy và sử dụng. |
Microsoft.AspNetCore.HostFiltering | Hosts được cho phép. |
Microsoft.AspNetCore.Hosting | Thời gian hoàn thành HTTP requests và thời gian bắt đầu. Các hosting startup assemblies đã được tải. |
Microsoft.AspNetCore.Mvc | Chẩn đoán MVC và Razor. Model binding, filter execution, view compilation và action selection. |
Microsoft.AspNetCore.Routing | Thông tin route matching. |
Microsoft.AspNetCore.Server | Connection start, stop và keep alive responses. Thông tin chứng chỉ HTTPS. |
Microsoft.AspNetCore.StaticFiles | Files được phục vụ. |
Log scopes (phạm vi nhật ký)
Một scope có thể nhóm một tập hợp các thao tác logic. Việc nhóm này có thể dùng để đính kèm cùng dữ liệu vào mỗi log được tạo như một phần của tập hợp. Ví dụ, mỗi log được tạo như một phần của xử lý giao dịch có thể bao gồm ID giao dịch.
Dùng scope bằng cách bọc các lệnh gọi logger trong block using:
public async Task<TodoItem> GetTodoItem(long id)
{
TodoItem todoItem;
var transactionId = Guid.NewGuid().ToString();
using (Logger.BeginScope(new List<KeyValuePair<string, object>>
{
new("TransactionId", transactionId),
}))
{
Logger.LogInformation(LogEvent.GetItem, "Getting item {Id}", id);
todoItem = await TodoItemsService.FindAsync(id);
if (todoItem == null)
{
Logger.LogWarning(LogEvent.GetItemNotFound, "Get({Id}) NOT FOUND", id);
return NotFound();
}
}
return todoItem;
}Built-in logging providers (nhà cung cấp ghi nhật ký tích hợp sẵn)
ASP.NET Core bao gồm các logging providers sau:
ConsoleDebugEventSource- Windows
EventLog
Các logging providers sau được cung cấp bởi Microsoft, nhưng không phải là một phần của .NET shared framework. Chúng phải được cài đặt dưới dạng NuGet package:
AzureAppServicesFilevàAzureAppServicesBlobApplicationInsights
ASP.NET Core không bao gồm logging provider để ghi log vào files. Để ghi log vào files, hãy cân nhắc dùng third-party logging provider.
Console
Provider Console ghi output ra console.
Debug
Provider Debug ghi output log bằng cách dùng class System.Diagnostics.Debug.
EventSource
Provider EventSource ghi vào event source cross-platform với tên Microsoft-Extensions-Logging. Trên Windows, provider dùng ETW.
Công cụ dotnet-trace
Công cụ dotnet-trace là công cụ CLI cross-platform global cho phép thu thập .NET traces của process đang chạy.
Để thu thập trace từ ứng dụng:
- Chạy ứng dụng với lệnh
dotnet run. - Xác định process identifier (PID) của .NET app:
dotnet-trace ps - Chạy lệnh
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}\"Bảng keyword ({KEYWORD}):
| Keyword | Mô tả |
|---|---|
| 1 | Log meta events về LoggingEventSource. Không log events từ ILogger. |
| 2 | Bật event Message khi ILogger.Log() được gọi. Cung cấp thông tin theo cách lập trình (không được format). |
| 4 | Bật event FormatMessage khi ILogger.Log() được gọi. Cung cấp phiên bản chuỗi đã format. |
| 8 | Bật event MessageJson khi ILogger.Log() được gọi. Cung cấp JSON representation của các đối số. |
Bảng provider levels:
| Provider Level | Mô tả |
|---|---|
| 0 | LogAlways |
| 1 | Critical |
| 2 | Error |
| 3 | Warning |
| 4 | Informational |
| 5 | Verbose |
Windows EventLog
Provider Windows EventLog gửi log output vào Windows Event Log. Khác với các providers khác, provider EventLog không kế thừa cài đặt mặc định không phải provider. Nếu cài đặt EventLog không được chỉ định, mặc định là LogLevel.Warning.
Azure App Service
Package NuGet Microsoft.Extensions.Logging.AzureAppServices ghi log vào text files trong hệ thống file của Azure App Service app và vào blob storage trong tài khoản Azure Storage. Provider chỉ ghi log khi project chạy trong môi trường Azure.
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 Application Insights
Application Insights là dịch vụ theo dõi web app và cung cấp công cụ để truy vấn và phân tích dữ liệu telemetry.
Third-party logging providers (nhà cung cấp ghi nhật ký bên thứ ba)
Các third-party logging frameworks hoạt động với ASP.NET Core:
Dùng third-party framework tương tự như dùng built-in providers:
- Thêm NuGet package của provider vào project.
- Gọi extension method ILoggerFactory được cung cấp bởi logging framework.
No asynchronous logger methods (không có phương thức logger bất đồng bộ)
Logging phải nhanh đến mức không đáng phải trả chi phí hiệu năng của code async. Nếu data store của logging chậm, đừng ghi trực tiếp vào nó. Hãy cân nhắc ghi log vào store nhanh trước, sau đó di chuyển log sang store chậm hơn.
Apply log filter rules in code (áp dụng quy tắc lọc log trong code)
Cách tiếp cận ưu tiên là đặt quy tắc lọc log bằng cấu hình ứng dụng.
Ví dụ đăng ký filter rules trong code:
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);Specify trace context for logging scopes (chỉ định trace context cho logging scopes)
Các thư viện logging ngầm tạo đối tượng scope với ActivityTrackingOptions. Các trường sau chỉ ra các tùy chọn:
SpanIdTraceIdParentIdBaggageTags
SpanId, TraceId, ParentId được bật theo mặc định.
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddSimpleConsole(options =>
{
options.IncludeScopes = true;
});
builder.Logging.Configure(options =>
{
options.ActivityTrackingOptions =
ActivityTrackingOptions.SpanId | ActivityTrackingOptions.TraceId;
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();Create a custom logger (tạo logger tùy chỉnh)
Để tạo custom logger, xem Implement a custom logging provider in .NET.
Common log categories (danh mục log phổ biến)
Microsoft.AspNetCore: Logs từ các components của ASP.NET Core framework.
Authentication (xác thực)
Microsoft.AspNetCore.Authentication: Logs từ authentication middleware và services.Microsoft.AspNetCore.Authentication.Cookies: Logs cho cookie-based authentication.Microsoft.AspNetCore.Authentication.JwtBearer: Logs liên quan đến JWT Bearer token authentication.Microsoft.AspNetCore.Authentication.OpenIdConnect: Logs về OpenID Connect authentication.Microsoft.AspNetCore.Authentication.OAuth: Logs liên quan đến OAuth authentication.
Authorization (ủy quyền)
Microsoft.AspNetCore.Authorization: Logs liên quan đến các thao tác authorization.
CORS (chia sẻ tài nguyên cross-origin)
Microsoft.AspNetCore.Cors: Logs liên quan đến CORS middleware.
Data Protection (bảo vệ dữ liệu)
Microsoft.AspNetCore.DataProtection: Logs từ hệ thống data protection, bao gồm quản lý key và các thao tác mã hóa.
Hosting (lưu trữ)
Microsoft.AspNetCore.Hosting.Lifetime: Logs liên quan đến vòng đời web host.
Kestrel
Microsoft.AspNetCore.Server.Kestrel: Logs từ Kestrel web server.
MVC
Microsoft.AspNetCore.Mvc: Logs chung từ các components MVC framework.Microsoft.AspNetCore.Mvc.ModelBinding: Logs về model binding và data validation.
Routing (định tuyến)
Microsoft.AspNetCore.Routing.EndpointMiddleware: Logs liên quan đến routing HTTP requests đến endpoints.
SignalR
Microsoft.AspNetCore.SignalR: Logs từ SignalR framework.
Static files (tệp tĩnh)
Microsoft.AspNetCore.StaticFiles: Logs từ static files middleware.