前端错误监控体系搭建:从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更有价值。



