Next.js 生产环境监控完全指南:Sentry 集成、日志管理与告警配置实战

周五晚上 9 点 17 分,手机震了。
微信群里已经炸锅——“支付页面打不开”、“刚才下单失败了”、“白屏了白屏了”。我打开电脑连上 VPN,本地跑一遍,完美运行。查看服务器日志,除了一行”Internal Server Error”什么都没有。用户说点击支付按钮后页面就卡死,但我完全复现不了。
那个周末我几乎没睡。凌晨两点翻 Vercel 部署日志,早上六点重新部署测试版本,最后发现是一个第三方支付 SDK 在生产环境偶发性超时。整个排查过程像是在黑暗里找掉落的针。
说实话,这不是个例。你的 Next.js 应用在开发环境可以丝般顺滑,但上线后就像打开了潘多拉魔盒——服务端渲染偶尔 500、边缘函数莫名其妙报错、API 响应时间飙升却不知道瓶颈在哪。
问题的根源很简单:你缺少一套完整的生产环境监控体系。
这篇文章会手把手教你搭建 Next.js 监控系统,从 Sentry 错误追踪到结构化日志管理,从性能监控到告警配置。不是理论堆砌,全是能直接复制粘贴的配置代码。读完这篇,下次线上出问题,你会比用户更早知道。
为什么 Next.js 需要专门的监控方案
Next.js 的「三头怪」特性
传统前端应用只跑在浏览器,错误直接在 DevTools 控制台看到。Next.js 不一样——同一个应用同时跑在三个完全不同的地方:
- 客户端(Browser):用户浏览器里的 React 组件
- 服务端(Node.js):SSR 渲染、API Routes、Server Actions
- 边缘网络(Edge Runtime):中间件、边缘函数
一个支付功能可能涉及:客户端表单验证 → 中间件鉴权 → Server Action 调用 → API Route 查数据库 → 返回客户端展示结果。任何一个环节出错,传统的浏览器监控都看不到全貌。
去年我遇到过一个很诡异的bug:用户反馈”页面加载很慢,然后就显示 500”。浏览器 Network 面板显示请求确实慢,但具体慢在哪不知道。后来接入 Sentry 的分布式追踪,才发现是服务端渲染时调用了一个第三方 API,这个 API 响应时间从平时的 200ms 飙到了 8 秒。客户端监控永远发现不了这种问题。
SSR 的「黑盒效应」
服务端渲染出错时,用户看到的往往只有一个光秃秃的 500 页面。没有 stack trace,没有上下文,什么都没有。
更要命的是 Hydration 错误。你可能见过这个警告:
Warning: Expected server HTML to contain a matching <div> in <div>这种错误在开发环境可能不太明显,但在生产环境可能导致整个页面交互失效。没有监控系统,你只能靠用户反馈”页面点不动了”来被动发现。
根据 Vercel 的数据,SSR 相关的错误占 Next.js 生产环境问题的 35% 左右。这还只是错误,不包括性能问题——比如某个组件的 SSR 耗时突然变长,用户感觉页面”打开变慢了”,但你完全不知道瓶颈在哪。
完整监控的四个支柱
一个靠谱的 Next.js 监控方案需要覆盖这几点:
错误追踪
不只是捕获异常,还要知道:谁触发的错误(用户信息)、在什么环境(设备、浏览器、网络)、做了什么操作(面包屑追踪)、相关的请求参数是什么。
性能监控
LCP(最大内容绘制)有没有超过 2.5 秒? API 接口响应时间是不是变慢了? 哪个数据库查询拖慢了整个请求?
日志管理
结构化日志,能按时间、用户、请求 ID 快速检索。开发环境美化输出方便调试,生产环境接入日志平台统一分析。
告警配置
错误率超过阈值立即通知团队,新类型错误首次出现就推送 Slack,性能回归自动触发告警。
有了这四个,线上出问题时你不再是”盲人摸象”。接下来咱们一个个攻破。
Sentry 集成实战 - 从安装到深度配置
5 分钟快速接入
Sentry 对 Next.js 的支持已经很成熟了,官方提供了自动配置向导。真的只需要 5 分钟:
# 安装 SDK
npm install @sentry/nextjs
# 运行配置向导
npx @sentry/wizard@latest -i nextjs向导会问你几个问题(Sentry项目 DSN、是否上传 Source Maps等),然后自动创建三个配置文件:
sentry.client.config.ts- 浏览器环境sentry.server.config.ts- Node.js 服务端sentry.edge.config.ts- Edge Runtime
还会修改 next.config.js,加入 Sentry 的 webpack 插件。跑一遍向导,基础监控就通了。
但这只是开始。生产环境需要更精细的配置。
App Router 的错误捕获要点
如果你用的是 App Router,有几个地方需要特别注意:
全局错误处理
创建 app/global-error.tsx,这是 App Router 的最后一道防线:
'use client';
import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// 发送到 Sentry
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
<div style={{ padding: '2rem', textAlign: 'center' }}>
<h2>出了点问题</h2>
<p>我们已经记录了这个错误,会尽快修复</p>
<button onClick={() => reset()}>重试</button>
</div>
</body>
</html>
);
}Server Actions 错误捕获
Server Actions 是 App Router 的杀手级功能,但错误处理经常被忽略:
'use server';
import * as Sentry from '@sentry/nextjs';
export async function createOrder(formData: FormData) {
return await Sentry.withServerActionInstrumentation(
'createOrder', // action 名称,会显示在 Sentry
{
recordResponse: true, // 记录响应数据
},
async () => {
// 你的业务逻辑
const productId = formData.get('productId');
const order = await db.order.create({
data: { productId, userId: getCurrentUserId() },
});
return order;
}
);
}这样包装后,Server Action 里的任何错误都会自动上报,还能追踪执行时间。
生产环境优化配置
接入 Sentry 后,第一个月账单可能会吓你一跳——因为默认配置会上报所有事件。需要调整采样率:
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// 性能追踪采样率
// 开发环境 100%,生产环境 10%(根据流量调整)
tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
// Session Replay 采样
replaysSessionSampleRate: 0.1, // 10% 的正常会话录制
replaysOnErrorSampleRate: 1.0, // 100% 的错误会话录制
// 环境标识
environment: process.env.NEXT_PUBLIC_VERCEL_ENV || 'development',
// 忽略特定错误
ignoreErrors: [
// 浏览器扩展注入的错误
'ResizeObserver loop limit exceeded',
// 第三方脚本错误
/chrome-extension/,
/^Non-Error promise rejection/,
],
});tracesSampleRate 设置指南:
- 日 UV < 1 万: 0.2 - 0.5
- 日 UV 1-10 万: 0.1 - 0.2
- 日 UV > 10 万: 0.05 - 0.1
我们项目日 UV 3 万左右,设置 0.15,每个月大概用掉 Sentry 配额的 60%,既能覆盖足够样本,又不会超支。
Source Maps:可调试但不泄露代码
生产环境的 JavaScript 代码通常是压缩混淆的,错误堆栈看起来像这样:
at r.render (app.js:1:23456)完全看不懂。Source Maps 能把混淆代码映射回原始代码,但直接暴露 Source Maps 会泄露源码。
Sentry 的做法是:上传 Source Maps 到 Sentry 服务器,用户浏览器拿不到,只有 Sentry 内部用来还原堆栈。
在 CI/CD 中配置(以 GitHub Actions 为例):
# .github/workflows/deploy.yml
- name: Upload Source Maps to Sentry
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: your-org
SENTRY_PROJECT: your-project
run: npm run buildnext.config.js 里 Sentry 插件会自动处理上传。记得把 SENTRY_AUTH_TOKEN 加到 GitHub Secrets,别提交到代码库。
高级功能:Session Replay 和分布式追踪
Session Replay 是我最喜欢的功能——回放用户操作,像看录像一样还原现场。
某次有个用户反馈”支付按钮点不了”,我看了他的 Session Replay,发现他用的是 iPad横屏,支付按钮被虚拟键盘挡住了。这种问题单靠错误日志永远发现不了。
开启很简单,在客户端配置里加:
import * as Sentry from '@sentry/nextjs';
import { Replay } from '@sentry/nextjs';
Sentry.init({
integrations: [
new Replay({
maskAllText: false, // 是否隐藏所有文本
blockAllMedia: true, // 是否阻止所有媒体
maskAllInputs: true, // 隐藏表单输入(避免泄露敏感信息)
}),
],
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});分布式追踪能跟踪一个请求的完整生命周期。用户点击按钮 → 前端发请求 → API Route 查数据库 → 返回前端渲染,每一步的耗时都能看到。
配置也不复杂,确保前后端用同一个 Sentry.init 配置,Sentry SDK 会自动在请求头里传递 sentry-trace。
自定义上下文:让错误更有意义
默认情况下 Sentry 只知道”发生了一个错误”。通过自定义上下文,能让错误报告更有价值:
import * as Sentry from '@sentry/nextjs';
// 设置用户信息
Sentry.setUser({
id: user.id,
email: user.email,
username: user.username,
// 别放密码之类的敏感信息!
});
// 添加业务上下文
Sentry.setContext('purchase', {
orderId: '12345',
amount: 99.99,
paymentMethod: 'credit_card',
});
// 添加标签(方便筛选)
Sentry.setTag('feature', 'checkout');
Sentry.setTag('ab_test', 'variant_b');这样当错误发生时,你能立刻知道是哪个用户、在什么业务场景下触发的。
真实案例:我们有次发现一个支付错误的发生频率比预期高,查看 Sentry 上下文发现全是 ab_test: variant_b 的用户。定位到 A/B 测试的新版支付流程有 bug,立刻关闭了这个变体,避免了更大的损失。
日志管理 - 让日志为你工作
console.log 不够用了
早期我也喜欢到处 console.log。调试时看起来挺爽,但上线后就抓瞎了:
- 无法筛选: 10 万条日志里找一个用户的请求记录? 祝你好运。
- 无法聚合: 想知道过去一小时有多少个数据库查询慢于 1 秒? 没法统计。
- 无法告警: 日志里出现”Payment failed”? 没人知道。
结构化日志解决了这些问题。不是简单打印字符串,而是输出 JSON 对象,每个日志带上时间戳、日志级别、请求 ID、用户 ID 等元数据。后续可以按任意字段检索和聚合。
Pino vs Winston:怎么选
Node.js 生态两大日志库,各有千秋:
| 特性 | Pino | Winston |
|---|---|---|
| 性能 | 超快,异步日志几乎无开销 | 稍慢,但依然够用 |
| 易用性 | 配置简洁,开箱即用 | 功能丰富,插件生态好 |
| 可扩展性 | 通过 Transport 扩展 | 内置多种 Transport |
| 社区 | Next.js 官方推荐 | 老牌库,文档最全 |
我的建议:
- 高并发场景(QPS > 1000):选 Pino,性能优势明显
- 需要复杂日志处理(多格式、多目标):选 Winston
- 不知道选啥:选 Pino,Next.js 官方文档都在用它
Pino 实战配置
先安装:
npm install pino
npm install pino-pretty --save-dev # 开发环境美化输出创建全局 logger:
// lib/logger.ts
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
// 格式化日志级别
formatters: {
level: (label) => ({ level: label.toUpperCase() }),
},
// 开发环境使用 pino-pretty 美化输出
transport: process.env.NODE_ENV === 'development'
? {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'HH:MM:ss',
ignore: 'pid,hostname',
},
}
: undefined,
});
export { logger };开发环境输出会是彩色的、易读的格式,生产环境是 JSON,方便日志平台解析。
在 API Route 中使用
关键是给每个请求分配一个 correlationId(关联 ID),把这个请求相关的所有日志串起来:
// app/api/products/route.ts
import { logger } from '@/lib/logger';
import { randomUUID } from 'crypto';
export async function GET(request: Request) {
// 生成请求唯一 ID
const correlationId = request.headers.get('x-correlation-id') || randomUUID();
// 创建子 logger,自动带上 correlationId
const log = logger.child({ correlationId });
try {
log.info({ url: request.url }, 'Processing product request');
const products = await db.product.findMany();
log.info({ count: products.length }, 'Products fetched successfully');
return Response.json(products);
} catch (error) {
log.error({ error: error.message, stack: error.stack }, 'Failed to fetch products');
throw error;
}
}这样所有带同一个 correlationId 的日志都能关联起来,排查问题时直接搜这个 ID,整个请求链路一目了然。
日志级别最佳实践
日志太少没用,太多淹没关键信息。我的分级标准:
ERROR - 需要立即处理的问题
- 数据库连接失败
- 支付接口调用失败
- 关键业务逻辑抛异常
log.error({ error, userId, orderId }, 'Payment processing failed');WARN - 异常但可恢复的情况
- API 调用重试成功
- 降级逻辑触发
- 接近配额限制
log.warn({ retryCount: 3 }, 'External API retry succeeded');INFO - 关键业务节点
- 用户登录/登出
- 订单创建/完成
- 关键配置变更
log.info({ userId, ip }, 'User logged in');DEBUG - 详细调试信息
- 函数参数和返回值
- 中间状态
- 性能计时
log.debug({ params }, 'Calling external API');生产环境默认 INFO 级别,出问题时临时调到 DEBUG 排查。
日志聚合与分析
本地开发用 pino-pretty 就够了,生产环境需要接入日志平台。几个主流选择:
Vercel Logs
如果部署在 Vercel,内置日志系统,零配置。但只保留 7 天,搜索功能有限。
Datadog
企业级方案,APM + 日志 + 监控全家桶。配置:
import { datadogLogs } from '@datadog/browser-logs';
datadogLogs.init({
clientToken: process.env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN,
site: 'datadoghq.com',
forwardErrorsToLogs: true,
sampleRate: 100,
});Logtail/BetterStack
性价比高,专注日志分析。支持实时搜索、告警规则、自定义面板。
个人项目我用 Logtail,配置简单,每月 1G 日志免费。团队项目用 Datadog,虽然贵但功能强大。
关键日志字段设计
一个好的日志应该包含这些字段:
{
"timestamp": "2025-12-20T15:00:06.123Z", // 时间戳
"level": "INFO", // 日志级别
"correlationId": "abc-123-def", // 请求关联 ID
"userId": "user_456", // 用户 ID
"action": "create_order", // 业务动作
"duration": 234, // 执行时长(ms)
"status": "success", // 状态
"metadata": { // 额外元数据
"orderId": "order_789",
"amount": 99.99
}
}这样的日志能回答”谁在什么时间做了什么,结果如何”。
性能监控 - 数据驱动的优化
Core Web Vitals:Google 在乎的指标
Google 把 Core Web Vitals 作为搜索排名因素,你也应该关注:
- LCP (Largest Contentful Paint): 最大内容绘制时间,理想值 < 2.5s
- FID (First Input Delay) / INP (Interaction to Next Paint): 交互响应时间,< 100ms / < 200ms
- CLS (Cumulative Layout Shift): 累积布局偏移,< 0.1
Next.js 内置了 Web Vitals 上报,只需在 app/layout.tsx 里加几行:
'use client';
import { useReportWebVitals } from 'next/web-vitals';
export function WebVitalsReporter() {
useReportWebVitals((metric) => {
// 发送到 Sentry
if (window.Sentry) {
window.Sentry.captureMessage(`Web Vital: ${metric.name}`, {
level: 'info',
tags: {
web_vital: metric.name,
},
contexts: {
web_vitals: {
value: metric.value,
rating: metric.rating,
},
},
});
}
// 或发送到你的分析平台
fetch('/api/analytics/web-vitals', {
method: 'POST',
body: JSON.stringify(metric),
});
});
return null;
}然后在根布局里引入:
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html>
<body>
<WebVitalsReporter />
{children}
</body>
</html>
);
}API 性能追踪
前端性能只是一半,后端 API 慢用户一样等得难受。Sentry 的 Performance Monitoring 可以追踪每个 API 请求:
// app/api/products/[id]/route.ts
import * as Sentry from '@sentry/nextjs';
export async function GET(
request: Request,
{ params }: { params: { id: string } }
) {
// 创建一个 transaction
return await Sentry.startSpan(
{
op: 'api.request',
name: 'GET /api/products/[id]',
},
async () => {
// 追踪数据库查询
const product = await Sentry.startSpan(
{
op: 'db.query',
name: 'Fetch product from database',
},
async () => {
return await db.product.findUnique({
where: { id: params.id },
include: { reviews: true },
});
}
);
if (!product) {
return Response.json({ error: 'Not found' }, { status: 404 });
}
// 追踪外部 API 调用
const pricing = await Sentry.startSpan(
{
op: 'http.client',
name: 'Fetch pricing from external API',
},
async () => {
const res = await fetch(`https://pricing-api.com/product/${params.id}`);
return res.json();
}
);
return Response.json({ ...product, pricing });
}
);
}在 Sentry 面板上你能看到:
- 整个请求耗时 450ms
- 数据库查询 120ms
- 外部 API 调用 300ms
- 其他逻辑 30ms
一目了然,瓶颈在外部 API。
慢查询告警
数据库是性能瓶颈的常客。可以在 Prisma 中间件里加监控:
// lib/prisma.ts
import { PrismaClient } from '@prisma/client';
import { logger } from './logger';
const prisma = new PrismaClient();
// 监控慢查询
prisma.$use(async (params, next) => {
const before = Date.now();
const result = await next(params);
const after = Date.now();
const duration = after - before;
// 超过 1 秒的查询记录为 WARN
if (duration > 1000) {
logger.warn({
model: params.model,
action: params.action,
duration,
args: params.args,
}, 'Slow database query detected');
// 同时发送到 Sentry
Sentry.captureMessage('Slow database query', {
level: 'warning',
tags: { model: params.model, action: params.action },
extra: { duration, args: params.args },
});
}
return result;
});
export { prisma };这样一来,任何慢查询都逃不过你的眼睛。
真实用户监控 vs 合成监控
真实用户监控(RUM)
用 Sentry、Datadog 等采集真实用户的性能数据。优点是反映真实场景(不同网络、设备),缺点是被动,问题发生了才知道。
合成监控(Synthetic Monitoring)
用 Checkly、Pingdom 等定时从全球各地模拟访问你的网站。优点是主动发现问题,缺点是无法覆盖所有用户场景。
两者结合最佳:
- RUM 关注用户体验指标
- 合成监控负责可用性和关键流程(登录、支付)
我用 Checkly 每 5 分钟从 5 个地理位置访问首页和登录接口,任何一个超时或失败立即告警。
告警配置 - 第一时间发现问题
Slack 集成:让团队第一时间知道
Sentry 集成 Slack 很简单,Settings → Integrations → Slack,授权后选择推送到哪个频道。
但默认配置会把所有错误都推送,很快变成噪音。需要配置告警规则:
在 Sentry 项目设置里:
- Alerts → Create Alert Rule
- 选择触发条件:
- 错误率告警: “10 分钟内错误数 > 50”
- 新错误告警: “首次出现的错误立即通知”
- 性能回归: “API P95 响应时间 > 1s”
- 选择 Action: Send a notification via Slack
Slack 消息格式:
🚨 Production Error Spike
Project: my-nextjs-app
Environment: production
Error: TypeError: Cannot read property 'id' of undefined
Events: 127 events in 10 minutes
View in Sentry: https://sentry.io/...点击链接直接跳转 Sentry,查看详情和堆栈。
告警分级:避免疲劳
不是所有问题都一样紧急。我的分级策略:
P0 - 严重 (立即处理)
- 服务完全不可用
- 支付功能失败
- 数据库连接断开
触发方式:电话(PagerDuty) + Slack @channel
P1 - 重要 (1 小时内响应)
- 核心功能异常
- 错误率突增(10 分钟内 > 100 次)
- API 响应时间 P95 > 3s
触发方式:Slack 推送到开发频道
P2 - 一般 (工作时间处理)
- 小范围错误(< 10 次/小时)
- 非关键功能异常
- 第三方脚本错误
触发方式:邮件日报汇总
配置示例(Sentry Alert Rule):
// P0 告警:支付失败
{
conditions: [
{ type: 'event.tag', key: 'feature', value: 'payment' },
{ type: 'event.level', value: 'error' }
],
frequency: 'every event', // 每次都通知
actions: [
{ type: 'slack', channel: '#critical-alerts', mention: '@channel' },
{ type: 'pagerduty', service: 'payments' }
]
}
// P1 告警:错误率飙升
{
conditions: [
{ type: 'event.count', value: 100, interval: '10m' }
],
frequency: 'once per issue', // 每个问题只通知一次
actions: [
{ type: 'slack', channel: '#alerts-dev' }
]
}告警降噪技巧
刚接入监控时,你可能会被告警淹没。几个降噪技巧:
1. 忽略已知问题
开发环境的热更新错误、第三方脚本异常,这些噪音可以过滤:
// sentry.client.config.ts
Sentry.init({
ignoreErrors: [
// 浏览器扩展错误
/chrome-extension/,
/moz-extension/,
// 第三方脚本
/google-analytics/,
// 开发环境热更新
/HMR/,
],
denyUrls: [
// 忽略特定域名的脚本错误
/extensions\//i,
/^chrome:\/\//i,
],
});2. 合并重复告警
相同错误 10 分钟内只通知一次,避免频道被刷屏。Sentry 的 “Issue Grouping” 会自动合并相似错误。
3. 设置静默期
部署期间可能有短暂的错误尖峰,可以设置 “Mute for 10 minutes”。
4. 使用指纹(Fingerprint)
自定义错误分组规则,把相同根因的错误合并:
Sentry.captureException(error, {
fingerprint: ['database-connection-error', databaseName],
});这样不同数据库的连接错误会被分开,方便定位。
实战案例 - 完整监控方案落地
电商网站监控架构
去年帮一个电商网站做监控改造,分享下完整方案:
背景:
- 日均 UV 8 万
- 高峰期 QPS 3000+
- 主要问题:支付偶发失败、首页加载慢
监控架构:
┌─────────────┐
│ Next.js │
│ 前端/SSR │
└──────┬──────┘
│
├─ Sentry (错误 + 性能)
├─ Pino (结构化日志) → Datadog
├─ Web Vitals → Sentry
└─ Checkly (合成监控)关键配置:
- 用户行为追踪
// lib/tracking.ts
import * as Sentry from '@sentry/nextjs';
export function trackCheckoutStep(step: string, data: any) {
Sentry.addBreadcrumb({
category: 'checkout',
message: `Checkout step: ${step}`,
data,
level: 'info',
});
}
// 在购物流程中调用
trackCheckoutStep('add_to_cart', { productId, price });
trackCheckoutStep('proceed_to_payment', { cartTotal });
trackCheckoutStep('payment_submitted', { method: 'credit_card' });这样当支付失败时,能看到用户完整的购物路径。
- 支付监控
// app/api/payment/route.ts
export async function POST(request: Request) {
const log = logger.child({ action: 'payment' });
try {
const result = await processPayment(data);
log.info({ orderId, amount, method }, 'Payment succeeded');
return Response.json({ success: true, orderId });
} catch (error) {
log.error({ error, orderId, userId }, 'Payment failed');
// P0 告警
Sentry.captureException(error, {
tags: { feature: 'payment', severity: 'critical' },
level: 'fatal',
});
return Response.json({ error: 'Payment failed' }, { status: 500 });
}
}任何支付失败都会立即通知团队。
- 性能基线设定
用 Sentry Performance Monitoring 建立基线:
- 首页 LCP < 2s
- 商品详情页 LCP < 2.5s
- API /api/products P95 < 500ms
超过基线自动告警。
效果:
- 故障发现时间从平均 40 分钟降到 3 分钟
- 支付失败率从 0.8% 降到 0.2%
- 首页 LCP 优化后从 3.2s 降到 1.8s
监控 Checklist
最后给一个清单,照着检查你的项目:
**错误监控**
- [ ] Sentry 已配置并测试通过
- [ ] Source Maps 上传成功
- [ ] global-error.tsx 已创建(App Router)
- [ ] Server Actions 已包装错误处理
- [ ] 忽略规则已配置(过滤噪音)
**日志管理**
- [ ] 日志库已集成(Pino/Winston)
- [ ] 生产环境输出 JSON 格式
- [ ] 日志包含 correlationId
- [ ] 日志级别正确设置(生产环境 INFO)
- [ ] 日志已接入聚合平台
**性能监控**
- [ ] Web Vitals 上报已启用
- [ ] Core Web Vitals 达标(LCP<2.5s, INP<200ms, CLS<0.1)
- [ ] 关键 API 已添加性能追踪
- [ ] 慢查询监控已配置
- [ ] 合成监控已设置(可选)
**告警配置**
- [ ] Slack/邮件告警已测试
- [ ] 告警规则已按优先级分级
- [ ] 告警降噪规则已配置
- [ ] 团队成员都知道告警流程
- [ ] P0 事件有明确的响应人
**持续改进**
- [ ] 每周复盘监控数据
- [ ] 错误趋势分析(哪些错误在增加)
- [ ] 性能回归检测(哪些页面变慢了)
- [ ] 告警规则定期优化结论
从被动救火到主动发现,监控让你对生产环境有了掌控力。
回顾一下我们搭建的监控体系:
- Sentry负责错误追踪和性能监控,还能回放用户操作
- Pino提供结构化日志,按 correlationId 串联整个请求链路
- Web Vitals关注用户体验指标,直接影响 SEO 排名
- Slack 告警让团队第一时间知道问题,分级处理避免疲劳
更重要的是思维转变:监控不是”有了更好”,而是生产环境的安全气囊。你不会等到出车祸才装安全气囊,同样不应该等线上出问题才想起监控。
今天就行动起来。如果你的项目还没有任何监控:
- 这周末花 2 小时接入 Sentry,配置基础错误追踪
- 下周加上结构化日志和 correlationId
- 再下周设置 Slack 告警和性能基线
不要追求一步到位,先把最基础的错误监控跑起来,再逐步完善。每次线上故障后问自己:“监控能否更早发现这个问题?” 持续改进,监控会成为你最可靠的队友。
最后,如果这篇文章帮到你,转发给团队一起提升。毕竟监控是团队的事,不是一个人的战斗。
祝你的 Next.js 应用稳如老狗,永不宕机。(但现实往往事与愿违,所以监控真的很重要😄)
Next.js生产环境监控完整配置流程
从Sentry集成到日志管理、性能监控、告警配置的完整步骤
⏱️ 预计耗时: 3 小时
- 1
步骤1: 集成Sentry错误追踪
安装:
```bash
npm install @sentry/nextjs
```
初始化:
```bash
npx @sentry/wizard@latest -i nextjs
```
配置客户端:
```ts
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
配置服务端:
```ts
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
关键点:
• 客户端和服务端分开配置
• 设置tracesSampleRate控制采样率
• 配置环境变量 - 2
步骤2: 配置结构化日志
使用correlationId关联请求:
```ts
// middleware.ts
import { v4 as uuidv4 } from 'uuid'
export function middleware(request: NextRequest) {
const correlationId = request.headers.get('x-correlation-id') || uuidv4()
const response = NextResponse.next()
response.headers.set('x-correlation-id', correlationId)
return response
}
```
在日志中使用:
```ts
import { headers } from 'next/headers'
export async function handler() {
const headersList = headers()
const correlationId = headersList.get('x-correlation-id')
console.log({
correlationId,
message: 'User action',
timestamp: new Date().toISOString(),
})
}
```
关键点:
• 每个请求生成唯一ID
• 所有日志都带上correlationId
• 方便追踪整个请求链路 - 3
步骤3: 配置性能监控
Sentry APM:
```ts
Sentry.init({
tracesSampleRate: 1.0, // 100%采样
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
],
})
```
自定义性能监控:
```ts
const transaction = Sentry.startTransaction({
op: 'http.server',
name: 'API Route',
})
try {
// 业务逻辑
await processRequest()
} finally {
transaction.finish()
}
```
关键点:
• 设置tracesSampleRate控制采样率
• 监控API响应时间
• 识别性能瓶颈 - 4
步骤4: 配置告警
Sentry告警:
• 在Sentry Dashboard配置告警规则
• 设置错误阈值
• 配置通知渠道(Slack、邮件等)
Slack集成:
```ts
// 在Sentry Dashboard配置
// Webhook URL: https://hooks.slack.com/services/...
```
邮件告警:
• 在Sentry Dashboard配置
• 设置收件人
• 配置告警条件
关键点:
• 设置合理的告警阈值
• 避免告警疲劳
• 及时响应告警
常见问题
为什么Next.js需要专门的监控方案?
同一个应用同时跑在三个地方:
• 客户端(Browser):用户浏览器里的React组件
• 服务端(Node.js):SSR渲染、API Routes、Server Actions
• 边缘网络(Edge Runtime):中间件、边缘函数
传统前端监控只看到客户端错误,看不到服务端和边缘的错误。
SSR黑盒效应:
• 服务端渲染出错时,用户只看到500页面
• 没有stack trace、没有上下文
• 需要Sentry分布式追踪才能发现问题
真实案例:
• 用户反馈"页面加载很慢,然后就显示500"
• 浏览器Network面板显示请求慢,但不知道慢在哪
• 接入Sentry后才发现是服务端调用第三方API响应时间从200ms飙到8秒
解决方案:需要一套完整的监控体系,覆盖客户端、服务端、边缘网络。
如何集成Sentry?
```bash
npm install @sentry/nextjs
```
初始化:
```bash
npx @sentry/wizard@latest -i nextjs
```
配置客户端:
```ts
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
配置服务端:
```ts
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
})
```
关键点:
• 客户端和服务端分开配置
• 设置tracesSampleRate控制采样率
• 配置环境变量(NEXT_PUBLIC_SENTRY_DSN、SENTRY_DSN)
如何配置结构化日志?
在middleware中生成:
```ts
import { v4 as uuidv4 } from 'uuid'
export function middleware(request: NextRequest) {
const correlationId = request.headers.get('x-correlation-id') || uuidv4()
const response = NextResponse.next()
response.headers.set('x-correlation-id', correlationId)
return response
}
```
在日志中使用:
```ts
import { headers } from 'next/headers'
export async function handler() {
const headersList = headers()
const correlationId = headersList.get('x-correlation-id')
console.log({
correlationId,
message: 'User action',
timestamp: new Date().toISOString(),
})
}
```
优势:
• 每个请求生成唯一ID
• 所有日志都带上correlationId
• 方便追踪整个请求链路
• 快速定位问题
关键点:在middleware中生成,在日志中使用,方便关联。
如何配置性能监控?
```ts
Sentry.init({
tracesSampleRate: 1.0, // 100%采样(生产环境建议0.1)
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
],
})
```
自定义性能监控:
```ts
const transaction = Sentry.startTransaction({
op: 'http.server',
name: 'API Route',
})
try {
// 业务逻辑
await processRequest()
} finally {
transaction.finish()
}
```
监控指标:
• API响应时间
• 数据库查询时间
• 第三方API调用时间
• 页面加载时间
关键点:
• 设置tracesSampleRate控制采样率(生产环境建议0.1)
• 监控关键路径
• 识别性能瓶颈
如何配置告警?
• 在Sentry Dashboard配置告警规则
• 设置错误阈值(如:5分钟内错误数>10)
• 配置通知渠道(Slack、邮件等)
Slack集成:
• 在Sentry Dashboard配置Webhook URL
• 设置告警条件
• 测试告警
邮件告警:
• 在Sentry Dashboard配置
• 设置收件人
• 配置告警条件
告警规则建议:
• 错误率超过阈值
• 响应时间超过阈值
• 特定错误类型
• 新错误出现
关键点:
• 设置合理的告警阈值
• 避免告警疲劳
• 及时响应告警
建议:先把最基础的错误监控跑起来,再逐步完善。
监控的最佳实践是什么?
1. 这周末花2小时接入Sentry,配置基础错误追踪
2. 下周加上结构化日志和correlationId
3. 再下周设置Slack告警和性能基线
不要追求一步到位,先把最基础的错误监控跑起来,再逐步完善。
持续改进:
• 每次线上故障后问自己:"监控能否更早发现这个问题?"
• 根据实际情况调整告警阈值
• 定期审查监控配置
关键指标:
• 错误率
• 响应时间
• 用户影响范围
• 恢复时间
建议:
• 监控是团队的事,不是一个人的战斗
• 定期分享监控数据
• 持续改进监控体系
记住:监控不是一次性任务,而是持续的过程。
17 分钟阅读 · 发布于: 2025年12月20日 · 修改于: 2026年1月22日
相关文章
Next.js 电商实战:购物车与 Stripe 支付完整实现指南

Next.js 电商实战:购物车与 Stripe 支付完整实现指南
Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战

Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战
Next.js 单元测试实战:Jest + React Testing Library 完整配置指南


评论
使用 GitHub 账号登录后即可评论