前端错误监控体系搭建:从console.error到Sentry全链路追踪的实践
一、console.error的幻象:用户看到的错误,你一条都没收到
前端错误监控的传统方式是在关键位置放置try-catch并console.error。这种方式在用户量达到2000+时暴露了三个致命缺陷:第一,console.error只记录在用户本地控制台,开发者看不到;第二,try-catch只能捕获同步错误,Promise rejection和事件监听器中的异常完全丢失;第三,每个开发者在各自的位置添加日志,没有统一的错误分类和优先级。
在AI日记工具的某次发布中,一个图片上传的Unhandled Promise Rejection在生产环境运行了整三天,导致约1200次上传失败,但没有任何告警触发——因为没有错误被发送到任何监控系统。
二、前端错误监控的四层金字塔
第一层确保不遗漏任何错误类型。第二层在错误发生时为Sentry事件附加足够的上下文(用户ID、当前路由、浏览器版本),使得排查不需要"能复现吗"的反复追问。第三层由Sentry SDK完成错误去重和聚合。第四层是基于错误率的自动告警。
三、Next.js项目中Sentry的集成实践
// sentry.client.config.ts — 客户端配置 import * as Sentry from '@sentry/nextjs'; Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, environment: process.env.NODE_ENV, // 采样率:生产环境30%,开发环境100%,控制成本 tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.3 : 1.0, // 设计意图:只采样慢请求(>500ms),避免全量trace的成本爆炸 tracePropagationTargets: [], beforeSend(event) { // 过滤已知的浏览器扩展错误,避免噪音 if (event.exception?.values?.[0]?.type?.includes('chrome-extension')) { return null; } return event; }, });// components/error-boundary.tsx — React Error Boundary 'use client'; import { Component, type ReactNode } from 'react'; import * as Sentry from '@sentry/nextjs'; interface Props { children: ReactNode; fallback?: ReactNode; componentName?: string; } interface State { hasError: boolean; error?: Error; } /** * 自定义Error Boundary * * 设计意图: * 1. 组件树错误不导致整个页面白屏 * 2. 错误自动上报Sentry,附带组件名信息 * 3. Fallback UI区分严重程度:可恢复 vs 需刷新 */ export class AppErrorBoundary extends Component<Props, State> { constructor(props: Props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error: Error): State { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { Sentry.withScope((scope) => { scope.setTag('component', this.props.componentName || 'unknown'); scope.setExtra('componentStack', errorInfo.componentStack); Sentry.captureException(error); }); } render() { if (this.state.hasError) { return this.props.fallback || ( <div className="p-6 text-center"> <p className="text-gray-500">页面出现了错误</p> <button onClick={() => this.setState({ hasError: false })} className="mt-2 text-blue-500 underline" > 重试 </button> </div> ); } return this.props.children; } }四、错误监控的成本控制与告警疲乏
Sentry的付费按事件数计费。AI日记工具在日活3000时每天产生约15000个错误事件,其中60%是相同的第三方脚本错误。beforeSend过滤器和ignoreErrors配置将事件量降至每天约4200个有效事件,月度成本控制在80美元内。
告警阈值设置不当导致"告警疲乏"是一个被低估的风险。经过一个月的调优,告警阈值设定为:新类型错误≥3次/10分钟触发告警,已知错误≥50次/10分钟触发告警(避免偶发的已知错误频繁告警)。
五、总结
本次前端错误监控体系搭建的核心结论:
全局捕获三件套缺一不可:
window.onerror+unhandledrejection+Error Boundary,分别覆盖同步、异步和组件级错误。错误富化消解"能复现吗"的沟通成本:用户ID+路由+环境信息在错误发生时自动附加。
beforeSend过滤减少60%的事件噪音:浏览器扩展错误和已知的第三方脚本错误应静默丢弃。
告警阈值分级防疲乏:新错误低阈值(3次/10分钟),已知错误高阈值(50次/10分钟)。
Error Boundary的恢复能力比错误捕获本身更重要:保留用户的部分UI比展示全白屏的fallback更有价值。