Nguon: Microsoft Learn · .NET 8.0

Logging (ghi nhật ký) trong .NET và ASP.NET Core

Nguồn: Logging in .NET and 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:

csharp
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:

csharp
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:

csharp
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ị:

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:

Trong trang counter Razor Pages (Pages/Privacy.cshtml.cs):

csharp
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ố.

csharp
Logger.LogInformation(LogEvent.GetItem, "Getting item {Id}", id);
csharp
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:

csharp
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:

csharp
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:

json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}

Trong JSON trê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 LevelValue
Trace0
Debug1
Information2
Warning3
Error4
Critical5
None6

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 (:).

dotnetcli
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:

csharp
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:

LogLevelValueMethodMô tả
Trace0LogTraceChứ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.
Debug1LogDebugDành cho debugging và development. Dùng cẩn thận trong production vì lượng messages lớn.
Information2LogInformationTheo dõi luồng chung của ứng dụng.
Warning3LogWarningCho 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.
Error4LogErrorThườ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.
Critical5LogCriticalCho 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.
None6Chỉ đị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&lt;TCategoryName&gt;, đố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:

  1. 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.
  2. 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.
  3. Nếu chọn nhiều quy tắc, lấy quy tắc cuối cùng.
  4. Nếu không chọn quy tắc nào, dùng MinimumLevel.

ILoggerILoggerFactory

Các interface ILogger&lt;TCategoryName&gt;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:

csharp
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.

csharp
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:

csharp
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:

CategoryGhi chú
Microsoft.AspNetCoreChẩn đoán chung ASP.NET Core.
Microsoft.AspNetCore.DataProtectionCác data protection keys đã được xem xét, tìm thấy và sử dụng.
Microsoft.AspNetCore.HostFilteringHosts được cho phép.
Microsoft.AspNetCore.HostingThờ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.MvcChẩn đoán MVC và Razor. Model binding, filter execution, view compilation và action selection.
Microsoft.AspNetCore.RoutingThông tin route matching.
Microsoft.AspNetCore.ServerConnection start, stop và keep alive responses. Thông tin chứng chỉ HTTPS.
Microsoft.AspNetCore.StaticFilesFiles đượ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:

csharp
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:

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:

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:

  1. Chạy ứng dụng với lệnh dotnet run.
  2. Xác định process identifier (PID) của .NET app: dotnet-trace ps
  3. Chạy lệnh dotnet-trace:
dotnetcli
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}):

KeywordMô tả
1Log meta events về LoggingEventSource. Không log events từ ILogger.
2Bậ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).
4Bật event FormatMessage khi ILogger.Log() được gọi. Cung cấp phiên bản chuỗi đã format.
8Bậ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 LevelMô tả
0LogAlways
1Critical
2Error
3Warning
4Informational
5Verbose

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.

csharp
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:

  1. Thêm NuGet package của provider vào project.
  2. 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:

csharp
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:

SpanId, TraceId, ParentId được bật theo mặc định.

csharp
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)

Authorization (ủy quyền)

CORS (chia sẻ tài nguyên cross-origin)

Data Protection (bảo vệ dữ liệu)

Hosting (lưu trữ)

Kestrel

MVC

Routing (định tuyến)

SignalR

Static files (tệp tĩnh)