前端监控与错误追踪实战指南
在现代化的前端应用中,完善的监控和错误追踪系统是保障用户体验的关键。本文将深入探讨如何构建一套完整的前端监控体系,从错误捕获到性能分析,全方位守护你的应用。
一、错误捕获机制
1. 全局错误监听
// 捕获全局错误
window.addEventListener('error', (event) => {
const errorInfo = {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error?.stack,
type: 'error',
timestamp: Date.now()
};
// 发送到监控服务器
sendToMonitoring(errorInfo);
});
// 捕获未处理的Promise rejection
window.addEventListener('unhandledrejection', (event) => {
const errorInfo = {
message: event.reason?.message || 'Unhandled Promise Rejection',
stack: event.reason?.stack,
type: 'unhandledrejection',
timestamp: Date.now()
};
sendToMonitoring(errorInfo);
});
2. Vue应用中的错误处理
// Vue 3 全局错误处理器
app.config.errorHandler = (err, vm, info) => {
const errorInfo = {
message: err.message,
stack: err.stack,
component: vm?.$options?.name,
info: info,
type: 'vue-error',
timestamp: Date.now()
};
sendToMonitoring(errorInfo);
};
3. React应用中的错误边界
class ErrorBoundary extends React.Component {
componentDidCatch(error, errorInfo) {
const errorData = {
message: error.message,
stack: error.stack,
componentStack: errorInfo.componentStack,
type: 'react-error',
timestamp: Date.now()
};
sendToMonitoring(errorData);
}
render() {
return this.props.children;
}
}
二、性能监控
1. 核心性能指标
// 页面加载性能
const performanceData = {
// 页面加载时间
pageLoadTime: performance.timing.loadEventEnd - performance.timing.navigationStart,
// DOM解析时间
domParseTime: performance.timing.domComplete - performance.timing.domLoading,
// 资源加载时间
resourceLoadTime: performance.timing.domContentLoadedEventEnd - performance.timing.domContentLoadedEventStart,
// 首次内容绘制
firstContentfulPaint: performance.getEntriesByType('paint')
.find(entry => entry.name === 'first-contentful-paint')?.startTime,
// 最大内容绘制
largestContentfulPaint: performance.getEntriesByType('largest-contentful-paint')
.pop()?.startTime
};
// 发送性能数据
sendToMonitoring({ type: 'performance', data: performanceData });
2. API请求监控
// 拦截fetch请求
const originalFetch = window.fetch;
window.fetch = async (...args) => {
const startTime = performance.now();
const url = args[0];
try {
const response = await originalFetch(...args);
const endTime = performance.now();
// 记录成功的API请求
sendToMonitoring({
type: 'api-request',
url: url,
status: response.status,
duration: endTime - startTime,
success: true
});
return response;
} catch (error) {
const endTime = performance.now();
// 记录失败的API请求
sendToMonitoring({
type: 'api-request',
url: url,
error: error.message,
duration: endTime - startTime,
success: false
});
throw error;
}
};
三、用户行为追踪
1. 页面访问追踪
// 页面访问记录
function trackPageView() {
const pageInfo = {
url: window.location.href,
referrer: document.referrer,
userAgent: navigator.userAgent,
screenResolution: `${window.screen.width}x${window.screen.height}`,
viewport: `${window.innerWidth}x${window.innerHeight}`,
timestamp: Date.now()
};
sendToMonitoring({ type: 'page-view', data: pageInfo });
}
// 页面离开时记录停留时间
let pageStartTime = Date.now();
window.addEventListener('beforeunload', () => {
const stayTime = Date.now() - pageStartTime;
sendToMonitoring({
type: 'page-stay-time',
url: window.location.href,
duration: stayTime
});
});
2. 用户交互追踪
// 追踪用户点击
document.addEventListener('click', (event) => {
const target = event.target;
const clickInfo = {
element: target.tagName,
id: target.id,
className: target.className,
text: target.textContent?.substring(0, 50),
x: event.clientX,
y: event.clientY,
timestamp: Date.now()
};
sendToMonitoring({ type: 'user-click', data: clickInfo });
}, true);
// 追踪表单提交
document.addEventListener('submit', (event) => {
const formInfo = {
formId: event.target.id,
formAction: event.target.action,
timestamp: Date.now()
};
sendToMonitoring({ type: 'form-submit', data: formInfo });
});
四、监控数据上报
1. 数据上报策略
class MonitoringReporter {
constructor(config) {
this.config = {
endpoint: '/api/monitoring',
batchSize: 10,
flushInterval: 5000,
...config
};
this.queue = [];
this.init();
}
init() {
// 定时上报
setInterval(() => this.flush(), this.config.flushInterval);
// 页面关闭时上报
window.addEventListener('beforeunload', () => this.flush());
}
report(data) {
this.queue.push(data);
if (this.queue.length >= this.config.batchSize) {
this.flush();
}
}
async flush() {
if (this.queue.length === 0) return;
const dataToSend = [...this.queue];
this.queue = [];
try {
await navigator.sendBeacon(
this.config.endpoint,
JSON.stringify(dataToSend)
);
} catch (error) {
// 失败时重新加入队列
this.queue.unshift(...dataToSend);
}
}
}
// 使用示例
const reporter = new MonitoringReporter({
endpoint: 'https://your-monitoring-api.com/collect',
batchSize: 5,
flushInterval: 3000
});
function sendToMonitoring(data) {
reporter.report(data);
}
五、错误分析与告警
1. 错误聚合分析
class ErrorAnalyzer {
constructor() {
this.errorPatterns = new Map();
}
analyze(error) {
// 提取错误特征
const pattern = this.extractPattern(error);
// 统计错误频率
if (!this.errorPatterns.has(pattern)) {
this.errorPatterns.set(pattern, {
count: 0,
firstSeen: Date.now(),
lastSeen: Date.now(),
samples: []
});
}
const errorData = this.errorPatterns.get(pattern);
errorData.count++;
errorData.lastSeen = Date.now();
errorData.samples.push(error);
// 只保留最近的5个样本
if (errorData.samples.length > 5) {
errorData.samples.shift();
}
// 检查是否需要告警
this.checkAlert(errorData);
}
extractPattern(error) {
// 提取错误的关键特征
return error.message.split(':')[0] + '|' + error.type;
}
checkAlert(errorData) {
// 错误频率过高时触发告警
if (errorData.count > 10) {
this.triggerAlert({
type: 'high-frequency-error',
pattern: errorData.pattern,
count: errorData.count,
samples: errorData.samples
});
}
}
triggerAlert(alert) {
// 发送告警通知
console.warn('Alert triggered:', alert);
// 可以集成邮件、短信、钉钉等通知方式
}
}
六、最佳实践建议
- 采样策略:对于高流量应用,采用采样策略减少监控数据量
- 隐私保护:避免收集敏感用户信息,对数据进行脱敏处理
- 性能影响:监控代码本身要轻量,避免影响应用性能
- 数据安全:使用HTTPS传输监控数据,确保数据安全
- 分级告警:根据错误严重程度设置不同的告警级别
总结
构建完善的前端监控体系需要从错误捕获、性能监控、用户行为追踪等多个维度入手。通过实时监控和及时告警,我们可以快速发现和解决问题,持续提升用户体验。记住,好的监控系统是应用稳定运行的重要保障。
在实际项目中,可以考虑使用成熟的监控方案如Sentry、LogRocket等,它们提供了更完善的功能和更好的用户体验。但了解底层原理对于定制化需求仍然非常重要。