
独立开发者的错误处理与监控体系从用户投诉才知道Bug到主动发现并修复错误监控的三个层次独立开发者的早期产品常犯一个错误没有错误监控用户遇到了Bug沉默然后离开。 等你发现时已经流失了一批用户。L1前端错误监控Client-side Error Tracking捕获用户在浏览器里遇到的JS错误、网络错误、渲染错误。关键问题用户看到了什么错误信息在哪个页面用的什么浏览器L2后端错误监控Server-side Error Tracking捕获API失败、数据库错误、第三方服务调用失败。关键问题哪个API出问题了失败率多少影响了多少用户L3业务异常监控Business Logic Monitoring不止技术错误还包括业务逻辑异常——如用户注册流程的某一步突然掉落率升高、支付成功率突然下降。这些不是代码错误但是产品健康问题。L1实战用Sentry监控前端错误为什么选SentrySentry有免费计划每月5K errors适合早期产品且支持错误分组相同类型的错误自动聚合、源码映射看到错误发生在源代码的哪一行而不是编译后的JS、用户上下文看到哪个用户遇到了这个错误。接入实战Next.js步骤一安装依赖npm install sentry/nextjs步骤二初始化Sentry// sentry.client.config.ts import * as Sentry from sentry/nextjs; Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN!, // 从Sentry后台获取 environment: process.env.NODE_ENV, tracesSampleRate: 1.0, // 性能监控采样率1.0 100% replaysSessionSampleRate: 0.1, // Session Replay采样率10% replaysOnErrorSampleRate: 1.0, // 发生错误时100%录制Replay // 过滤掉不重要的错误 ignoreErrors: [ ResizeObserver loop limit exceeded, // 浏览器兼容性问题不重要 Network request failed, // 用户断网不是Bug ], // 附加上下文 beforeSend(event) { // 可以在这里过滤或改写event if (event.user) { // 匿名化用户名保护隐私 event.user.username event.user.username ? hash(event.user.username) : null; } return event; }, });步骤三在next.config.js里配置Sentry// next.config.js const { withSentryConfig } require(sentry/nextjs); const nextConfig { // 你的Next.js配置 }; module.exports withSentryConfig(nextConfig, { // Sentry webpack插件配置 org: your-org, project: your-project, sentryUrl: https://sentry.io, authToken: process.env.SENTRY_AUTH_TOKEN, silent: true, });步骤四捕获未处理的Promise拒绝和渲染错误// app/global-error.tsx Next.js 14 App Router use client; import * as Sentry from sentry/nextjs; import { useEffect } from react; export default function GlobalError({ error, reset }: { error: Error; reset: () void }) { useEffect(() { Sentry.captureException(error); // 把错误上报到Sentry }, [error]); return ( html body h2出错了/h2 button onClick{() reset()}重试/button /body /html ); }L2实战用Sentry Winston监控后端错误后端错误监控需要结构化日志 错误追踪。WinstonNode.js的结构化日志库// lib/logger.ts import winston from winston; const logger winston.createLogger({ level: info, format: winston.format.combine( winston.format.timestamp(), winston.format.json() // 结构化JSON日志方便后续分析 ), transports: [ new winston.transports.File({ filename: error.log, level: error }), new winston.transports.File({ filename: combined.log }), ], }); // 生产环境也输出到控制台 if (process.env.NODE_ENV production) { logger.add(new winston.transports.Console({ format: winston.format.simple(), })); } export default logger;在API Route里使用// app/api/posts/route.ts import logger from /lib/logger; import * as Sentry from sentry/nextjs; export async function GET(req: Request) { try { const posts await db.select().from(postsTable); return Response.json(posts); } catch (error) { // 1. 记录结构化日志 logger.error(Failed to fetch posts, { error: error.message, stack: error.stack, endpoint: /api/posts, userId: req.headers.get(X-User-ID), }); // 2. 上报到Sentry Sentry.captureException(error, { tags: { endpoint: /api/posts, method: GET }, extra: { userId: req.headers.get(X-User-ID) }, }); return Response.json({ error: Internal Server Error }, { status: 500 }); } }Sentry的性能监控Performance MonitoringSentry不仅能捕获错误还能监控API响应时间。// 监控一个API端点的性能 import * as Sentry from sentry/nextjs; export async function POST(req: Request) { return Sentry.startSpan({ op: http.server, name: POST /api/posts, }, async (span) { const body await req.json(); // 记录自定义指标 span.setAttribute(post.title.length, body.title.length); const post await db.insert(postsTable).values(body).returning(); // 记录数据库查询时间 span.setAttribute(db.duration_ms, 123); // 实际应该从数据库驱动获取 return Response.json(post); }); }L3实战业务异常监控与告警技术错误如500错误容易监控但业务异常如注册掉落率升高需要自定义埋点。实战场景监控用户注册流程的每一步掉落率// lib/analytics.ts import posthog from posthog-js; // 或用Mixpanel、Amplitude export function trackRegistrationStep(step: string, userId?: string) { posthog.capture({ event: registration_step, properties: { step, // start, email_verified, profile_filled, completed $user_id: userId, }, }); }在注册流程的每个关键步骤调用// 用户开始注册 trackRegistrationStep(start); // 用户验证了邮箱 trackRegistrationStep(email_verified, user.id); // 用户填写了个人资料 trackRegistrationStep(profile_filled, user.id); // 注册完成 trackRegistrationStep(completed, user.id);设置告警当掉落率异常时通知你用Better Stack原LogTail或Grafana Cloud的告警功能。我的告警规则注册流程的email_verified到profile_filled掉落率 30% → 发送Slack消息支付成功率 90% → 立即打电话用PagerDutyAPI错误率 5% → 发送邮件 Slack消息错误响应的用户侧设计把崩溃变成信任当用户遇到错误时你的错误提示决定了用户是离开还是原谅你。原则一错误信息要人性化❌ 错误{error: ERR_DB_CONN_TIMEOUT, code: 5003}✅ 错误抱歉我们的数据库正在维护通常1-2分钟。请稍后重试或联系supportyourproduct.com原则二提供补救措施如果是支付失败提供重试按钮如果是页面加载失败提供返回首页链接。原则三用错误页面建立品牌个性很多产品的404页面和500页面是默认样式——这是浪费和用户沟通的机会。我的404页面// app/not-found.tsx export default function NotFound() { return ( div classmin-h-screen flex items-center justify-center div classtext-center h1 classtext-6xl font-bold text-gray-300404/h1 p classmt-4 text-xl text-gray-600页面好像迷路了/p p classmt-2 text-gray-400不过你可以回到首页继续探索/p a href/ classmt-6 inline-block bg-blue-600 text-white px-6 py-3 rounded-lg 返回首页 /a /div /div ); }结论错误监控不是出了问题再看日志而是建立一套体系让问题在影响用户之前就被发现。独立开发者的最小可行监控体系 Sentry前端后端错误 结构化日志Winston 业务埋点PostHog 告警Better Stack。这四件套做好你就能睡得着觉——因为即使出问题你会在用户投诉之前就知道。