错误监控与可观测性

应用上线后,你看不到用户屏幕上发生了什么——某个页面白屏了?API 响应变慢了?支付流程中断了?没有监控的应用就像闭着眼睛开车。可观测性(Observability)让你在问题发生时第一时间知道、快速定位原因、在用户投诉之前修复。本章系统讲解 Next.js 应用的错误监控、性能追踪、日志管理和告警策略。

1. 可观测性的三大支柱

1.1 Logs、Metrics、Traces

支柱定义类比回答的问题
Logs(日志)离散的事件记录病历记录"发生了什么?"
Metrics(指标)聚合的数值度量体检报告"整体状态如何?"
Traces(链路追踪)请求的完整调用链快递追踪"请求经过了哪些环节?每个环节耗时多少?"

三者的关系

  • Metrics 告诉你"有问题"(错误率上升)
  • Logs 告诉你"什么问题"(具体错误信息)
  • Traces 告诉你"为什么有问题"(哪个环节慢了/出错了)

1.2 Next.js 的可观测性挑战

Next.js 的架构让可观测性比传统 SPA 更复杂:

挑战原因
多运行时Server Components(Node.js)+ Client Components(浏览器)+ Middleware(Edge)
Serverless每个请求可能在不同实例上执行,没有持久进程
SSR + CSR 混合同一个错误可能在服务端和客户端都出现
流式渲染Streaming SSR 的错误可能在渲染中途发生
构建时 vs 运行时某些错误只在构建时出现(ISR revalidation)

1.3 可观测性工具全景

工具类型特点价格
Sentry错误监控前端 + 后端,Source Maps,Replay免费层
Vercel Analytics性能指标Web Vitals,零配置Vercel Pro
Datadog全栈可观测APM + Logs + Metrics + Traces付费
Grafana Stack开源可观测Loki(日志)+ Prometheus(指标)+ Tempo(链路)自托管免费
New RelicAPM自动探针,AI 分析免费层
OpenTelemetry标准协议厂商无关,统一数据格式开源
BetterStack日志 + 监控Uptime + Logs,漂亮 UI免费层
Axiom日志分析Vercel 集成好,无限保留免费层

2. Sentry 集成

2.1 为什么 Sentry 是 Next.js 错误监控的首选

原因说明
官方 SDK@sentry/nextjs 专为 Next.js 优化
全栈覆盖Client + Server + Edge 三个运行时都支持
Source Maps自动上传,生产环境错误定位到源码行
Session Replay录制用户操作视频,复现问题
性能监控自动追踪路由变化、API 调用、数据库查询
App Router 支持Server Components、Server Actions 错误自动捕获
免费额度5K 错误/月、50 Replay/月

2.2 Sentry 在 Next.js 中的架构

浏览器(Client Components)
├── 未捕获异常 → Sentry 自动捕获
├── React Error Boundary → Sentry 自动上报
├── Console Errors → 可选捕获
└── Performance → 自动追踪路由、Web Vitals

服务端(Server Components / API Routes)
├── 未捕获异常 → Sentry 自动捕获
├── Server Action 错误 → 自动上报
├── 数据库查询错误 → 手动或自动捕获
└── Performance → 自动追踪 API 耗时

边缘(Middleware)
├── 运行时错误 → Sentry Edge SDK 捕获
└── 超时错误 → 自动上报

2.3 Sentry 核心配置要点

配置项推荐值说明
tracesSampleRate0.1(生产)采样 10% 的请求做性能追踪
replaysSessionSampleRate0.110% 的会话录制 Replay
replaysOnErrorSampleRate1.0出错时 100% 录制 Replay
tunnel/api/sentry-tunnel绕过广告拦截器
Source Maps构建时上传错误定位到源码行
ReleaseGit commit hash关联部署版本

2.4 Sentry Tunnel:绕过广告拦截器

很多广告拦截器会屏蔽 sentry.io 的请求,导致客户端错误丢失。解决方案——Sentry Tunnel

正常模式:
  浏览器 ──→ https://o123.ingest.sentry.io/... ← 被广告拦截器屏蔽

Tunnel 模式:
  浏览器 ──→ https://yourdomain.com/api/sentry-tunnel ──→ sentry.io
  广告拦截器不会屏蔽你自己域名的请求

在 Next.js 中创建 /api/sentry-tunnel Route Handler,将请求转发到 Sentry。

2.5 有效的错误上报

不是所有错误都值得上报——区分信号和噪音:

错误类型是否上报原因
未捕获异常✅ 必须可能导致页面崩溃
API 5xx 错误✅ 必须服务端问题
认证失败(401)❌ 不报正常业务行为
404 请求❌ 不报通常是用户输入错误
网络超时⚠️ 采样上报可能是用户网络问题
第三方脚本错误❌ 过滤不是你的代码问题

配置 beforeSend 过滤无用错误:

过滤规则:
1. 忽略已知的第三方脚本错误(Google Analytics、Facebook SDK)
2. 忽略网络错误(用户离线)
3. 忽略浏览器扩展引发的错误
4. 忽略爬虫触发的错误
5. 对重复错误去重(相同 fingerprint)

3. 性能监控

3.1 Web Vitals 监控

指标全称含义达标值
LCPLargest Contentful Paint最大内容绘制时间≤ 2.5s
INPInteraction to Next Paint交互到下一次绘制≤ 200ms
CLSCumulative Layout Shift累积布局偏移≤ 0.1
FCPFirst Contentful Paint首次内容绘制≤ 1.8s
TTFBTime to First Byte首字节时间≤ 800ms

3.2 Next.js 内置性能追踪

Next.js App Router 内置了 OpenTelemetry 支持,自动生成以下 Span:

Span说明
next.route路由处理总时间
next.renderServer Component 渲染时间
next.data数据获取时间
next.middlewareMiddleware 执行时间
fetch所有 fetch 请求(自动追踪)

3.3 Server Timing API

Server Timing 是一个 HTTP 头,允许服务端将性能数据传递到浏览器 DevTools:

Server-Timing: db;dur=23.5, render;dur=45.2, total;dur=120.0

浏览器 DevTools 的 Network 面板中可以直接看到每个环节的耗时,无需额外工具。

3.4 性能预算

指标预算值监控方式
JS Bundle Size< 200KB(首屏)@next/bundle-analyzer
LCP< 2.5sSentry / Vercel Analytics
TTFB< 500msServer Timing
API P99 延迟< 1sAPM 工具
错误率< 0.1%Sentry

CI 中强制执行预算:构建时检查 Bundle 大小,超出预算则构建失败。

4. 日志管理

4.1 结构化日志

非结构化日志(不推荐):

User john logged in from 192.168.1.1 at 2025-04-12T10:30:00Z

结构化日志(推荐):

{
  "level": "info",
  "event": "user.login",
  "userId": "john",
  "ip": "192.168.1.1",
  "timestamp": "2025-04-12T10:30:00Z",
  "requestId": "req_abc123"
}

结构化日志的优势:

  • 可以被日志系统索引和搜索
  • 可以按字段过滤(userId = "john"
  • 可以聚合分析(每小时登录次数)
  • 机器可读,支持自动化告警

4.2 日志级别

级别用途生产环境
error影响用户的错误✅ 始终记录
warn潜在问题、降级操作✅ 始终记录
info关键业务事件(登录、支付)✅ 始终记录
debug调试信息❌ 生产关闭
trace极细粒度的追踪❌ 生产关闭

4.3 请求上下文传递

每个请求应该有一个唯一的 requestId,贯穿所有日志——方便从一条错误日志追溯整个请求链路。

请求进入(Middleware)→ 生成 requestId
    ↓
Server Component → 日志包含 requestId
    ↓
API 调用 → 日志包含 requestId
    ↓
数据库查询 → 日志包含 requestId
    ↓
所有日志都可以通过 requestId 关联起来

4.4 日志平台选型

平台特点Vercel 集成价格
Vercel Logs零配置、实时✅ 内置Vercel Pro
AxiomVercel 官方推荐✅ 一键集成免费层(500GB/月)
BetterStack漂亮 UI、告警免费层
Datadog Logs企业级、全功能⚠️ 需配置付费
Grafana Loki开源、自托管免费(自托管)

4.5 Vercel Log Drain

Vercel 的 Log Drain 功能可以将所有日志实时转发到外部平台:

Next.js 应用(Vercel)
├── Serverless Function Logs
├── Edge Function Logs
├── Build Logs
└── Static File Access Logs
    ↓
Log Drain → 实时转发到
├── Axiom
├── Datadog
├── BetterStack
└── 自定义 HTTP 端点

5. OpenTelemetry

5.1 为什么需要 OpenTelemetry

OpenTelemetry(OTel)是可观测性的开放标准——由 CNCF 维护,厂商无关。

问题OTel 解决方案
各厂商数据格式不同统一的数据模型(Span、Metric、Log)
更换监控工具成本高只改 Exporter,不改采集代码
需要同时用多个工具一份数据发送到多个后端

5.2 Next.js 的 OTel 支持

Next.js 内置了 OpenTelemetry 的实验性支持。配置后,Next.js 自动生成:

自动生成的 Span说明
HTTP GET /api/usersAPI Route 处理
next.route /dashboard页面路由处理
next.renderServer Component 渲染
fetch https://api.example.com所有 fetch 请求
next.middlewareMiddleware 执行

5.3 OTel 架构

Next.js 应用
├── 自动探针(HTTP、fetch、Next.js 内部)
├── 手动 Span(自定义业务逻辑追踪)
└── OpenTelemetry SDK
    ↓
OTel Collector(可选,聚合 + 转发)
    ↓
├── Jaeger(链路追踪可视化)
├── Prometheus(指标存储)
├── Grafana Tempo(链路存储)
├── Datadog(商业 APM)
└── Honeycomb(商业分析)

5.4 手动 Span 的使用场景

自动探针覆盖了 HTTP 和 fetch,但业务逻辑需要手动追踪:

场景手动 Span 名称追踪内容
复杂计算calculate.pricing定价算法耗时
第三方 APIstripe.create-paymentStripe 调用耗时和结果
缓存操作cache.get / cache.set缓存命中率和耗时
队列处理queue.process-job后台任务处理时间
文件操作storage.upload文件上传耗时和大小

6. 告警策略

6.1 告警金字塔

         页面告警(PagerDuty 电话)     ← 严重:服务宕机
        /                          \
      紧急告警(Slack + 短信)         ← 高:错误率飙升
     /                              \
   警告告警(Slack 通知)              ← 中:性能下降
  /                                  \
 信息通知(Dashboard)                 ← 低:趋势变化

6.2 告警规则设计

告警条件级别通知渠道
服务不可用健康检查连续失败 3 次🔴 严重电话 + Slack
错误率飙升5xx 错误率 > 1%(5 分钟)🔴 严重Slack + 短信
API 延迟过高P99 > 3s(10 分钟)🟡 警告Slack
内存使用过高> 80%🟡 警告Slack
新错误类型出现从未见过的错误🔵 信息Slack
部署完成CD 流水线完成🔵 信息Slack

6.3 告警反模式

反模式问题解决方案
告警疲劳太多告警导致忽略只告警可行动的事件
阈值太敏感正常波动触发告警使用动态阈值或百分比变化
没有分级所有告警同等优先级严格分级(严重/警告/信息)
没有自动恢复通知告警触发后不知道何时恢复配置恢复通知
没有值班轮换一个人承担所有告警PagerDuty 轮换排班

6.4 SLO/SLI 驱动的告警

基于 SLO(服务等级目标)设定告警,而非基于绝对阈值:

SLISLO告警条件
可用性99.9%(每月停机 < 43 分钟)错误预算消耗 > 50%
API 延迟P99 < 1s超出 SLO 的请求 > 0.1%
页面加载LCP < 2.5sP75 LCP > 2.5s

这种方式的好处:不是"API 慢了就告警",而是"API 慢到影响用户承诺了才告警"。

7. 监控 Dashboard 设计

7.1 四层 Dashboard

层级受众关键指标
业务层产品/管理层DAU、转化率、收入
应用层开发团队错误率、P99 延迟、Web Vitals
基础设施层运维/SRECPU、内存、磁盘、网络
依赖层开发团队数据库延迟、第三方 API 状态

7.2 Next.js 应用的核心 Dashboard

面板指标
总览请求量、错误率、P50/P95/P99 延迟
Web VitalsLCP、INP、CLS 的 P75 趋势
API 性能各 Route Handler 的延迟和吞吐量
错误趋势错误数量、新增错误类型、Top 10 错误
SSR 性能Server Component 渲染时间、ISR revalidation
依赖健康数据库连接池、Redis 延迟、第三方 API 状态

8. 事故响应

8.1 事故响应流程

告警触发
    ↓
值班人响应(< 5 分钟)
    ↓
评估影响范围
├── 全站不可用 → P1(立即全员响应)
├── 核心功能受损 → P2(30 分钟内修复)
├── 非核心功能受损 → P3(4 小时内修复)
└── 性能下降 → P4(下一个工作日修复)
    ↓
定位原因(Traces + Logs + Metrics)
    ↓
修复或回滚
    ↓
事后复盘(Postmortem)

8.2 Postmortem 模板

模块内容
事件摘要什么时间、什么服务、影响了多少用户
时间线从发现到恢复的完整时间线
根因分析5 Why 分析法找到根本原因
影响评估受影响的用户数、收入损失
修复措施短期修复 + 长期预防
改进项可执行的改进任务(有负责人和截止日期)

8.3 混沌工程

主动制造故障来验证监控和告警是否有效:

实验方法验证目标
API 高延迟注入人工延迟告警是否及时触发
数据库宕机断开数据库连接应用是否优雅降级
内存泄漏模拟内存增长是否自动重启
依赖超时第三方 API 不响应超时和重试是否正常

本章小结

  • 可观测性三支柱:Logs(发生了什么)+ Metrics(整体状态)+ Traces(为什么出问题)
  • Sentry:Next.js 错误监控首选,覆盖 Client + Server + Edge,配置 Tunnel 绕过广告拦截
  • 性能监控:Web Vitals(LCP/INP/CLS)+ Server Timing + 性能预算,CI 中强制执行
  • 日志管理:结构化日志 + 请求 ID 关联 + Log Drain 到 Axiom/BetterStack
  • OpenTelemetry:厂商无关的可观测标准,Next.js 内置支持,自动追踪路由和 fetch
  • 告警策略:严格分级、基于 SLO 驱动、避免告警疲劳
  • Dashboard:四层设计(业务/应用/基础设施/依赖),核心关注错误率和 P99 延迟
  • 事故响应:5 分钟响应 + 分级处理 + Postmortem 持续改进