Mục lục
Giới thiệu về Ghi Log Có Cấu Trúc
Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách triển khai ghi log có cấu trúc trong ASP.NET Core Web API sử dụng Serilog.
Ghi log là một trong những tính năng quan trọng và thiết yếu trong phát triển phần mềm, cho phép các nhà phát triển và chủ sản phẩm khắc phục sự cố và phân tích lỗi ứng dụng.
Ghi log có cấu trúc là cách viết log sao cho chúng không chỉ là các tin nhắn văn bản thuần túy mà là dữ liệu có ngữ cảnh. Thay vì xử lý một mục log như một chuỗi, ghi log có cấu trúc thu thập thông tin quan trọng dưới dạng các trường (như JSON). Điều này làm cho log dễ lưu trữ, tìm kiếm và phân tích hơn với các công cụ quản lý log hiện đại.
Sử dụng Serilog hoặc bất kỳ nhà cung cấp logging nào khác, bất cứ khi nào ứng dụng của bạn ghi log toàn diện và rộng rãi, bạn sẽ có thể theo dõi bất kỳ lỗi hoặc vấn đề nào xảy ra và điều đó sẽ giúp ích rất nhiều trong việc tìm giải pháp cho vấn đề.
1. Import Gói NuGet Serilog và Các Gói Liên quan
Import các gói NuGet cần thiết bao gồm thư viện chính cho Serilog cùng với các thư viện khác mà Serilog phụ thuộc để làm giàu định dạng có cấu trúc cũng như dump log vào các đầu ra khác nhau thông qua sinks.
Bạn có thể sử dụng NuGet Package Manager GUI cho VS 2022, hoặc từ console NuGet Package Manager bạn có thể chạy các lệnh dưới đây:
dotnet add package Serilog.AspNetCore<br>
dotnet add package Serilog.Settings.Configuration<br>
dotnet add package Serilog.Sinks.File<br>
dotnet add package Serilog.Sinks.MSSqlServer<br>
dotnet add package Serilog.Enrichers.Environment<br>
dotnet add package Serilog.Enrichers.Thread
2. Cấu hình AppSettings.json
Để làm cho logging của bạn linh hoạt hơn, luôn được khuyến nghị giữ cấu hình logging bên trong các tệp appsettings.json của bạn để bạn có thể thay đổi cài đặt mà không cần triển khai lại toàn bộ dự án ASP.NET Core.
Các cài đặt như vậy có thể bao gồm mức log chung và cấu hình cụ thể cho sink như đường dẫn tệp và đối số, cấu trúc mẫu log, thông tin xác thực cho các nhà cung cấp có kiểm soát truy cập như cơ sở dữ liệu hoặc các nhà cung cấp dựa trên chỉ mục.
Dưới đây là ví dụ cho tệp Appsettings.json bao gồm cấu hình Serilog cho File và SQL Server Sinks:
{
"Serilog": {
"Using": ["Serilog.Sinks.File", "Serilog.Sinks.MSSqlServer"],
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"],
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "logs/app-.log",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
}
},
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=Home\\SQLEXPRESS;Database=TasksDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"tableName": "Logs",
"autoCreateSqlTable": true,
"columnOptionsSection": {
"addStandardColumns": ["LogEvent", "Properties"]
}
}
}
]
}
}
3. Thiết lập Program.cs
Trong bước này, chúng ta sẽ chỉ định nhà cung cấp logging trong dự án ASP.NET Core của chúng ta là Serilog, đồng thời chúng ta sẽ cấu hình Serilog để đọc cấu hình của nó từ tệp appsettings.json theo môi trường hiện tại (như được chỉ định trong tệp launch.json).
Dưới đây là mã mà bạn cần bao gồm như một phần của tệp Program.cs:
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Load Serilog configuration from appsettings.json
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.CreateLogger();
builder.Host.UseSerilog();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
4. Sử dụng ILogger Abstract
Điểm tốt về Serilog (và nhiều thư viện logging khác), là chúng có thể tận dụng giao diện ILogger
Đây là một ví dụ tuyệt vời về cách abstraction có thể cung cấp một cách mạnh mẽ để mở rộng chức năng thông qua các nhà cung cấp khác nhau mà không cần thay đổi triển khai mã của bạn.
Dưới đây là ví dụ về việc sử dụng ILogger
using Microsoft.AspNetCore.Mvc;
namespace StructuredLogging.Controllers
{
public record Task(int UserId, string Title, string Description);
[ApiController]
[Route("api/[controller]")]
public class TasksController(ILogger<TasksController> logger) : ControllerBase
{
[HttpPost]
public IActionResult CreateTask(Task task)
{
logger.LogInformation("User {UserId} created task {Title} with description {Description}",
task.UserId, task.Title, task.Description);
try
{
if (string.IsNullOrWhiteSpace(task.Title))
throw new ArgumentException("Task title cannot be empty");
return Ok(new { Status = "Task created" });
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to create task for {UserId} with title {Title}", task.UserId, task.Title);
return BadRequest("Task creation failed");
}
}
}
}
12 Quy tắc cho Ghi Log Có Cấu trúc trong ASP.NET Core
Đây là danh sách các quy tắc và thực tiễn tốt nhất cần tuân theo khi triển khai ghi log có cấu trúc trong ASP.NET Core:
- Sử dụng ILogger
để giữ mã của bạn tách biệt khỏi các nhà cung cấp. - Chọn mức log phù hợp (Debug, Info, Warning, Error, Critical).
- Ghi log exception một cách chính xác. Luôn bao gồm đối tượng exception và stack trace.
- Giữ log có cấu trúc bằng cách sử dụng các thư viện logging nổi bật như Serilog và sử dụng placeholders {}, không phải nối chuỗi.
- Không bao giờ ghi log dữ liệu nhạy cảm. Ẩn mật khẩu và thông tin cá nhân.
- Thêm ngữ cảnh & correlation IDs. Theo dõi yêu cầu, người dùng và hoạt động xuyên các dịch vụ.
- Cấu hình mức log trong appsettings.json và điều chỉnh theo môi trường (Debug trong Dev, Warning trong Prod).
- Tập trung log sử dụng Seq, ELK, Grafana, Azure Monitor hoặc CloudWatch.
- Thiết lập chính sách giữ lại & xoay vòng để ngăn các tệp log phát triển không kiểm soát.
- Làm giàu log với cảnh báo & giám sát. Hành động đối với cảnh báo lặp lại và lỗi nghiêm trọng.
- Tận dụng OpenTelemetry & async logging. Thống nhất log, traces, metrics và tăng hiệu suất.
- Bảo mật lưu trữ log với kiểm soát truy cập trên các tệp log và bảng điều khiển.
Kết luận
Ghi log có cấu trúc với Serilog trong ASP.NET Core làm cho log trở nên hữu ích hơn nhiều so với văn bản thuần túy.
Bằng cách thu thập dữ liệu dưới dạng cặp key–value, bạn có thể truy vấn, lọc và phân tích log với độ chính xác cao.
Sử dụng ILogger
Cách tiếp cận này đảm bảo log nhất quán, có thể tìm kiếm và có thể hành động trên console, tệp và SQL Server, giúp bạn giám sát và khắc phục sự cố ứng dụng một cách hiệu quả.


