为什么需要结构化日志
传统日志是一行行拼接的字符串:时间、级别、消息堆在一起,出问题时靠肉眼和正则去抠字段。结构化日志把每条记录拆成「键值对」:用户标识、订单号、耗时、状态码各自独立成字段,查询、聚合、告警都建立在字段之上。
.NET 生态里最常用的结构化日志库是 Serilog:它把日志当作事件而非文本,每个事件可以附带任意数量的属性。配合控制台、文件、数据库、云日志服务等接收器,一套代码多处投递。
日志不是给人看的,是给机器分析的;结构化是分析的前提。
- 时间精确到毫秒。
- 级别Trace 到 Fatal。
- 字段业务键值对。
- 链路TraceId 贯穿。
Serilog 接入与配置
接入 Serilog 分三步:安装包、配置接收器、替换日志工厂。最小化配置只需要 NuGet 三个包:Serilog、Serilog.AspNetCore、Serilog.Sinks.Console。
// Program.cs 最小接入
using 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();
UseSerilog 会把框架自身日志、第三方库日志统一汇入 Serilog 管道,一次配置全站生效。配置文件里也能通过 appsettings.json 的 Serilog 节管理接收器,运维改配置不用重新编译。
结构化字段与过滤
写日志时用模板字符串占位符,Serilog 会把参数变成字段,而不是拼进消息文本。这样既能保持消息可读,又能让字段参与筛选。
// 用命名占位符,参数自动成为结构化字段
_logger.LogInformation(
"用户 {UserId} 完成订单 {OrderId},耗时 {ElapsedMs}ms",
userId, orderId, sw.ElapsedMilliseconds);
过滤靠 MinimumLevel 与子级别:开发环境开 Debug,生产只留 Information 以上;某个命名空间可以单独降噪,比如把框架自带的 HealthCheck 日志压到 Warning,避免每分钟一次的心跳刷屏。
OpenTelemetry 与指标链路
日志解决「发生了什么」,指标回答「有多少、有多快」,链路追踪解释「一次请求经过了谁」。OpenTelemetry 是三者统一的标准:同一套 SDK 采集 Trace、Metric、Log,统一导出到后端。
// OpenTelemetry 注册:链路 + 指标 + 日志
builder.Services.AddOpenTelemetry()
.WithTracing(t => t
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddOtlpExporter())
.WithMetrics(m => m
.AddAspNetCoreInstrumentation()
.AddOtlpExporter());
OTLP 导出器可以把数据送到 Prometheus、Jaeger、SkyWalking 等后端。关键是把 TraceId 注入日志,让日志与链路能在同一把钥匙下互相跳转。
健康检查与告警
应用有没有活着,靠健康检查探针说了算。ASP.NET Core 内置 HealthChecks,可以检查数据库连通、外部依赖可用、磁盘空间等,输出 JSON 供负载均衡与监控平台消费。
builder.Services.AddHealthChecks()
.AddDbContextCheck<AppDbContext>()
.AddCheck("disk", () =>
DriveInfo.GetDrives().All(d => d.AvailableFreeSpace > 1L << 30)
? HealthCheckResult.Healthy()
: HealthCheckResult.Unhealthy("磁盘空间不足"));
告警规则一般落在监控平台上:连续三次探针失败、错误日志五分钟内超过阈值、接口 P95 超时,各配一条通知渠道。告警要可执行,每条都指向一份处理手册,否则只是噪音。
日志治理与成本控制
日志量失控是常见的隐形事故:一次线上问题排查,日志平台先被自己撑爆。治理手段有三:分级采样、敏感字段脱敏、保留周期分层。
采样只在 Debug 或高频路径做,Error 以上永远全量;密码、令牌、身份证号在写入前必须脱敏;热数据保留三十天、冷数据归档一年,磁盘与费用都省下一大截。Serilog 的 Enrich 和 Destructure 机制可以统一处理脱敏,不用在每个调用点手写。
小结与延伸阅读
日志与监控是系统的仪表盘:Serilog 让日志可检索,OpenTelemetry 让指标链路统一,健康检查让存活状态可探知。三者配合,出问题才能从「翻日志」变成「点开面板」。开始搭建时从最小闭环起步:结构化日志落盘、探针上线、一条核心告警,再逐步补齐。
- 性能排查读《.NET 性能优化与内存管理实战》。
- 问题定位读《Windows 调试与诊断实战》。
- 批量运维读《组策略与批量部署实战》。