Logging Cấu Trúc Trong ASP.NET Core – Hướng Dẫn Chi Tiết Với Serilog

Cập nhật lần cuối: 30 tháng 8, 2025

Trong hướng dẫn này, chúng ta sẽ học cách triển khai logging cấu trúc trong ASP.NET Core Web API sử dụng Serilog.

Tại Sao Logging Quan Trọng?

Logging là một trong những tính năng quan trọng và thiết yếu nhất 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.

Logging Cấu Trúc Là Gì?

Logging cấu trúc là cách viết log sao cho chúng không chỉ là các thông báo văn bản thuần túy mà là dữ liệu có ngữ cảnh. Thay vì coi một mục log là một chuỗi ký tự, logging cấu trúc thu thập thông tin quan trọng dưới dạng các trường (giống như JSON). Điều này giúp 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 viết log toàn diện và chi tiết, 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 này sẽ giúp ích rất nhiều trong việc tìm giải pháp cho vấn đề.

Triển Khai Logging Cấu Trúc Với Serilog

Việc giới thiệu logging với Serilog trong ASP.NET Core Web API khá dễ dàng và đơn giản. Thực tế, có một gói NuGet cụ thể cho Serilog được thiết kế riêng cho các dự án ASP.NET Core.

Sức mạnh của Serilog được thể hiện qua số lượng lớn các Sink mà nó hỗ trợ. Những sink này sẽ giúp bạn ghi và đẩy log vào hầu hết bất kỳ kho lưu trữ bên ngoài nào, như file, cơ sở dữ liệu, chỉ mục, hoặc thậm chí các vị trí đám mây.

Hướng Dẫn Từng Bước

1. Nhập Gói NuGet Serilog Và Các Gói Liên Quan

Nhập 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 vào để làm phong phú định dạng cấu trúc cũng như ghi log vào các đầu ra khác nhau qua sink.

Bạn có thể sử dụng NuGet Package Manager GUI cho VS 2022, hoặc từ NuGet Package Manager console chạy các lệnh sau:

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 file appsettings.json để 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.

Những cài đặt này có thể bao gồm mức độ log chung, và cấu hình cụ thể cho sink như đường dẫn file 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 file Appsettings.json bao gồm cấu hình Serilog cho File và SQL Server Sinks:

{<br>  "Serilog":{<br>    "Using":["Serilog.Sinks.File","Serilog.Sinks.MSSqlServer"],<br>    "MinimumLevel":{<br>      "Default":"Information",<br>      "Override":{<br>        "Microsoft":"Warning",<br>        "System":"Warning"<br>      }<br>    },<br>    "Enrich":["FromLogContext","WithMachineName","WithThreadId"],<br>    "WriteTo":[<br>      {<br>        "Name":"File",<br>        "Args":{<br>          "path":"logs/app-.log",<br>          "rollingInterval":"Day",<br>          "retainedFileCountLimit":7,<br>          "outputTemplate":"[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"<br>        }<br>      },<br>      {<br>        "Name":"MSSqlServer",<br>        "Args":{<br>          "connectionString":"Server=Home\\SQLEXPRESS;Database=TasksDb;Trusted_Connection=True;MultipleActiveResultSets=true",<br>          "tableName":"Logs",<br>          "autoCreateSqlTable":true,<br>          "columnOptionsSection":{<br>            "addStandardColumns":["LogEvent","Properties"]<br>          }<br>        }<br>      }<br>    ]<br>  }<br>}

3. Thiết Lập Program.cs

Trong bước này, chúng ta sẽ gán 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ừ file appsettings.json theo môi trường hiện tại (như được chỉ định trong file launch.json).

Dưới đây là code mà bạn cần bao gồm như một phần của file Program.cs:

using Serilog;<br><br>var builder = WebApplication.CreateBuilder(args);<br><br>// Load Serilog configuration from appsettings.json<br>Log.Logger = new LoggerConfiguration()<br>    .ReadFrom.Configuration(builder.Configuration)<br>    .CreateLogger();<br><br>builder.Host.UseSerilog();<br><br>builder.Services.AddControllers();<br>var app = builder.Build();<br>app.MapControllers();<br>app.Run();

4. Sử Dụng ILogger<T> Abstract

Điểm tốt của Serilog (và nhiều thư viện logging khác) là chúng có thể tận dụng interface generic abstract ILogger<T> để cung cấp các tính năng logging dựa trên các hàm có sẵn trong ILogger<T>.

Đâ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 code của bạn.

Dưới đây là ví dụ về việc sử dụng ILogger<T> bên trong controller:

using Microsoft.AspNetCore.Mvc;<br><br>namespace StructuredLogging.Controllers<br>{<br>    public record Task(int UserId, string Title, string Description);<br><br>    [ApiController]<br>    [Route("api/[controller]")]<br>    public class TasksController(ILogger<TasksController> logger) : ControllerBase<br>    {<br>        [HttpPost]<br>        public IActionResult CreateTask(Task task)<br>        {<br>            logger.LogInformation("User {UserId} created task {Title} with description {Description}",<br>                task.UserId, task.Title, task.Description);<br><br>            try<br>            {<br>                if (string.IsNullOrWhiteSpace(task.Title))<br>                    throw new ArgumentException("Task title cannot be empty");<br><br>                return Ok(new { Status = "Task created" });<br>            }<br>            catch (Exception ex)<br>            {<br>                logger.LogError(ex, "Failed to create task for {UserId} with title {Title}", task.UserId, task.Title);<br>                return BadRequest("Task creation failed");<br>            }<br>        }<br>    }<br>}

5. Kiểm Thử API Qua Postman

Tôi sẽ sử dụng Postman để mô phỏng gọi endpoint CreateTask để kích hoạt việc chèn log theo mức độ log được định nghĩa và sẽ được ghi vào các sink như đã định nghĩa bên trong file log:

Sau khi ứng dụng chạy lần đầu tiên, nó sẽ tạo bảng trong SQL Server với các cài đặt được cung cấp.

SQL Server Sink (MSSqlServer)

Và một tìm kiếm nhanh trong bảng sẽ cho chúng ta log được thêm với đầy đủ chi tiết:

File Sink

Bạn cũng sẽ tìm thấy log được ghi bên trong file, theo cài đặt cấu hình:

Và khi mở file, bạn sẽ thấy log cấu trúc được ghi bên trong.

12 Quy Tắc Cho Logging Cấu Trúc Trong ASP.NET Core

Dưới đây là danh sách các quy tắc và thực hành tốt nhất cần tuân theo khi triển khai logging cấu trúc trong ASP.NET Core:

  • Sử dụng ILogger<T> để giữ code của bạn tách biệt với các nhà cung cấp.
  • Chọn mức độ log phù hợp (Debug, Info, Warning, Error, Critical).
  • Log ngoại lệ đúng cách. Luôn bao gồm đối tượng ngoại lệ 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 placeholder {}, không phải nối chuỗi.
  • Không bao giờ 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 & ID tương quan. Theo dõi yêu cầu, người dùng và các hoạt động qua 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 hóa log sử dụng Seq, ELK, Grafana, Azure Monitor, hoặc CloudWatch.
  • Thiết lập chính sách lưu giữ & xoay vòng để ngăn file log phát triển không kiểm soát.
  • Làm phong phú log với cảnh báo & giám sát. Hành động dựa trên các 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 file log và bảng điều khiển.

Kết Luận

Logging 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ác cặp khóa-giá trị, bạn có thể truy vấn, lọc và phân tích log một cách chính xác.

Sử dụng ILogger<T> generic abstract, bạn giữ các thực hành .NET tiêu chuẩn trong khi vẫn có được sức mạnh của Serilog: nhiều sink, enrichers và cấu hình thông qua appsettings.json.

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, file 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ả.

Tài Liệu Tham Khảo

Chỉ mục