如何停止猜测,开始看透你的代码?
你是否曾在深夜坐在显示器前,看着那些大声报错却对原因保持沉默的日志?或者试图弄清楚为什么你的 C# 微服务响应需要 10 秒,而昨天一切还运行如飞?熟悉吗?欢迎来到一个没有 可观测性 (Observability) 你的代码就是一个黑箱的世界。
在这篇文章中,我们不会进行枯燥的讲座。我们将剖析可观测性的三大支柱:追踪、指标和日志——并展示如何让它们与 C# 协同工作。你将学会如何停止救火,开始预防火灾。我们开始吧!
什么是可观测性,为什么它不仅仅是“日志记录”?
许多人将可观测性与普通的日志收集混为一谈。但区别是巨大的。可观测性 是系统的一种属性,它允许你提出关于其状态的任何问题,而无需添加新代码。支撑一切的三大支柱是:
- 日志 (Logs) — 离散事件。“用户点击了按钮”,“连接错误”。这是“发生了什么?”。
- 指标 (Metrics) — 聚合数据。“每秒请求数”,“内存消耗”。这是“多少以及多久一次?”。
- 追踪 (Traces) — 请求在系统中的路径。“请求到达,进入数据库,然后到缓存,返回”。这是“为什么这么慢?”。
在 C# 的 .NET 生态系统中,这三个支柱通过像 OpenTelemetry 这样的库结合在一起。现在,我们将看看这在代码中是什么样子。
进行实验:编写一个具有可观测性的应用程序
想象一下,我们有一个基于 ASP.NET Core 的简单服务,用于处理订单。我们希望看到:
- 订单处理的每一步(追踪)。
- 处理了多少订单以及有多少错误(指标)。
- 异常的详细信息(日志)。
步骤 1:使用 Serilog 配置日志记录
我们从最直观的部分开始——日志。使用 Serilog(但也可以使用 NLog)。它能够编写结构化日志,方便后续解析。
// NuGet: Serilog, Serilog.AspNetCore, Serilog.Sinks.Consoleusing Serilog;
// 在 Program.cs 中配置Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day) .Enrich.WithProperty("Application", "OrderService") .CreateLogger();
var builder = WebApplication.CreateBuilder(args);builder.Host.UseSerilog(); // 替换默认日志记录器
// 在控制器中的使用示例[ApiController][Route("api/[controller]")]public class OrderController : ControllerBase{ private readonly ILogger<OrderController> _logger;
public OrderController(ILogger<OrderController> logger) => _logger = logger;
[HttpPost] public IActionResult CreateOrder(Order order) { _logger.LogInformation("正在为用户 {User} 创建订单 {OrderId}", order.Id, order.UserId); // ... 逻辑 ... _logger.LogWarning("由于库存问题,订单 {OrderId} 被延迟", order.Id); return Ok(); }}请注意:我们使用命名占位符({OrderId})。这不仅仅是文本——这是结构化数据。在 Elasticsearch 或 Grafana Loki 中,你可以根据特定的 OrderId 搜索所有日志。
步骤 2:使用 Prometheus 和 .NET 的指标
指标负责“数字”。每秒多少请求?有多少 500 错误?在 C# 中,我们使用 System.Diagnostics.Metrics 中的 Meters 或 prometheus-net 库。
让我们创建一个简单的已处理订单计数器:
// NuGet: prometheus-net.AspNetCoreusing Prometheus;
// 在 Program.cs 中添加指标var builder = WebApplication.CreateBuilder(args);