C# 应用程序中的日志记录:最佳实践
日志记录不仅仅是向文件写入消息。在现代 .NET 应用程序中,它是用于监控、调试和审计的关键工具。正确配置的日志记录可以让您快速找到故障原因、分析性能并确保符合安全要求。在本文中,我们将介绍 C# 中日志记录的最佳实践,帮助您构建可靠的诊断信息收集系统。
选择日志记录库:Serilog vs NLog vs 内置 ILogger
在 .NET 中,有几种流行的解决方案。让我们看看它们的优缺点。
- Microsoft.Extensions.Logging (ILogger) — 内置抽象接口。适用于简单项目。开箱即用不支持结构化日志记录。
- Serilog — 市场领导者。以其易用性、强大的结构化日志支持和广泛的接收器(Sinks)而著称。
- NLog — 成熟的框架,可通过 XML 或代码灵活配置。非常适合遗留系统和复杂的路由场景。
对于新项目,推荐使用 Serilog。它易于与 ILogger 集成,并提供简洁的 API。配置示例:
// 安装:dotnet add package Serilog.AspNetCoreusing Serilog;
Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .WriteTo.Console() .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day) .CreateLogger();
var builder = WebApplication.CreateBuilder(args);builder.Host.UseSerilog(); // 替换默认日志记录器正确使用日志级别
不要将所有消息混入同一级别。请使用以下分级:
- Trace (0) — 最详细的调试信息。包含每个函数的执行细节。仅在开发环境中启用。
- Debug (1) — 对开发者有用的数据:变量值、方法执行结果。
- Information (2) — 业务事件:"用户已登录"、"订单已创建"。应该不仅程序员能理解。
- Warning (3) — 不会中断操作的异常情况:执行时间超限、重试连接尝试。
- Error (4) — 需要干预的异常和故障。务必记录完整调用堆栈。
- Critical (5) — 致命错误:数据库连接丢失、内存溢出。需要立即通知。
控制器中正确日志记录的示例:
[ApiController][Route("api/orders")]public class OrdersController : ControllerBase{ private readonly ILogger<OrdersController> _logger;
public OrdersController(ILogger<OrdersController> logger) { _logger = logger; }
[HttpPost] public IActionResult CreateOrder(OrderDto order) { _logger.LogInformation("Creating order {OrderId} for user {UserId}", order.Id, order.UserId); try { // 业务逻辑 _logger.LogInformation("Order {OrderId} successfully created", order.Id); return Ok(); } catch (Exception ex) { _logger.LogError(ex, "Error creating order {OrderId}", order.Id); return StatusCode(500); } }}结构化日志记录与上下文
避免在日志中进行字符串拼接。不要使用 Log.Information("User: " + user.Name),而应使用带参数的模板:
_logger.LogInformation("User {UserName} performed