C# 应用程序监控与日志记录:从混乱到有序

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么你的 C# 应用程序在“尖叫”,而你却听不见?

\n

想象一下:你在午夜部署了一个新的 C# 微服务版本。起初的 10 分钟,一切运行完美……然后,砰!——用户开始抱怨卡顿,而你坐在一个 2GB 大小的日志文件前,试图大海捞针。熟悉吗?如果不熟悉——你要么是天才,要么从未真正做过监控。

\n

在本文中,我们将探讨如何将混乱的日志转变为有序的系统。你将了解如何配置 C# 日志记录,以便在部署时不会抓狂,以及如何构建真正有用的 应用程序监控,而不仅仅是绘制漂亮的图表。

\n\n

从何开始:正确日志记录的哲学

\n

许多开发者认为:“用 Console.WriteLine 就行了。”剧透:不,不行。真正的 C# 日志记录是结构化日志。不要使用这样的字符串:

\n
Log.Info("User " + userId + " bought item " + itemId);
\n

而应该这样写:

\n
Log.Information("User {UserId} bought item {ItemId}", userId, itemId);
\n

区别巨大。在第二种情况下,你可以按 UserId 过滤日志,构建仪表板,并快速找到问题。这是生产环境中 C# 错误诊断 的基础。

\n\n

选择库:Serilog vs NLog vs log4net

\n

.NET 市场上有三个主要竞争者。让我们根据实际项目的重要标准进行比较:

\n
    \n
  • Serilog — 现代 .NET 的宠儿。非常适合结构化日志,易于配置,支持 sinks(输出到文件、数据库、Elasticsearch)。推荐用于新项目。
  • \n
  • NLog — 老牌库,通过 XML/JSON 提供灵活配置。非常适合已经使用它的遗留系统。
  • \n
  • log4net — 老古董,除非万不得已,最好别碰。支持不佳,结构化日志需要变通方法。
  • \n
\n

对于现代应用程序中的 .NET 跟踪,Serilog 是第一选择。让我们在 5 分钟内完成配置。

\n\n

在 C# 中配置 Serilog:分步指南

\n

通过 NuGet 安装包:

\n
dotnet add package Serilog\ndotnet add package Serilog.Sinks.Console\ndotnet add package Serilog.Sinks.File\ndotnet add package Serilog.Sinks.Seq
\n

现在,在 ASP.NET Core 的 Program.cs 中进行最小配置:

\n
using Serilog;\n\nLog.Logger = new LoggerConfiguration()\n    .MinimumLevel.Information()\n    .WriteTo.Console()\n    .WriteTo.File("logs/app-.log", rollingInterval: RollingInterval.Day)\n    .WriteTo.Seq("http://localhost:5341") // 用于高级监控\n    .CreateLogger();\n\ntry\n{\n    Log.Information("Starting web application");\n    var builder = WebApplication.CreateBuilder(args);\n    builder.Host.UseSerilog(); // 与主机集成\n    // ... 其余配置\n    var app = builder.Build();\n    app.Run();\n}\ncatch (Exception ex)\n{\n    Log.Fatal(ex, "Application terminated unexpectedly");\n}\nfinally\n{\n    Log.CloseAndFlush();\n}
\n

注意 rollingInterval —— 日志将每天轮换,而不是无限增长。这是生产环境中 异步日志记录 的基础。

\n\n

结构化日志:如何最大化利用

\n

假设我们有一个处理订单的方法。没有结构化,你可能会写:

\n
logger.LogInformation("Processing order {OrderId} for user {UserId}", order.Id, user.Id);
\n

使用 Serilog,这会被转换为可解析的 JSON 对象。如果通过 ILogger<T> 添加上下文:

\n
public class OrderService\n{\n    private readonly ILogger<OrderService> _logger;\n\n    public OrderService(ILogger<OrderService> logger)\n    {\n        _logger = logge                

博客

书籍推荐