LogRocket 错误追踪 #
什么是错误追踪? #
错误追踪是捕获、记录和分析应用程序中错误的过程。LogRocket 提供了完整的错误追踪解决方案,帮助你快速定位和修复问题。
text
┌─────────────────────────────────────────────────────────────┐
│ 错误追踪的价值 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 传统方式: │
│ 用户报告问题 → 开发者尝试复现 → 查看日志 → 猜测原因 │
│ 问题: │
│ ❌ 依赖用户反馈 │
│ ❌ 信息不完整 │
│ ❌ 难以复现 │
│ ❌ 修复周期长 │
│ │
│ LogRocket 方式: │
│ 错误自动捕获 → 完整上下文 → 会话回放 → 快速定位 │
│ 优势: │
│ ✅ 自动捕获所有错误 │
│ ✅ 完整的错误上下文 │
│ ✅ 关联用户操作 │
│ ✅ 快速定位和修复 │
│ │
└─────────────────────────────────────────────────────────────┘
错误类型 #
JavaScript 错误 #
text
┌─────────────────────────────────────────────────────────────┐
│ JavaScript 错误类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. SyntaxError(语法错误) │
│ - 代码解析错误 │
│ - 通常在开发阶段发现 │
│ │
│ 2. ReferenceError(引用错误) │
│ - 访问未定义的变量 │
│ - 示例:Cannot read property 'x' of undefined │
│ │
│ 3. TypeError(类型错误) │
│ - 类型不匹配的操作 │
│ - 示例:undefined is not a function │
│ │
│ 4. RangeError(范围错误) │
│ - 值超出有效范围 │
│ - 示例:Maximum call stack size exceeded │
│ │
│ 5. URIError(URI 错误) │
│ - URI 编码/解码错误 │
│ │
│ 6. EvalError(Eval 错误) │
│ - eval() 相关错误 │
│ │
└─────────────────────────────────────────────────────────────┘
Promise 拒绝 #
javascript
// 未捕获的 Promise 拒绝
fetch('/api/data')
.then(response => response.json())
.then(data => {
console.log(data.nonexistent.property);
});
// 如果 fetch 失败或数据结构不符预期,会产生未捕获的拒绝
资源加载错误 #
html
<!-- 图片加载失败 -->
<img src="nonexistent.jpg" onerror="handleError()">
<!-- 脚本加载失败 -->
<script src="missing-script.js"></script>
<!-- 样式表加载失败 -->
<link rel="stylesheet" href="missing-styles.css">
控制台错误 #
javascript
console.error('Critical error occurred');
console.warn('Warning: deprecated API used');
自动错误捕获 #
LogRocket 自动捕获以下错误:
text
┌─────────────────────────────────────────────────────────────┐
│ 自动捕获的错误 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 未捕获的 JavaScript 错误 │
│ - window.onerror │
│ - window.addEventListener('error') │
│ │
│ ✅ 未处理的 Promise 拒绝 │
│ - window.onunhandledrejection │
│ - window.addEventListener('unhandledrejection') │
│ │
│ ✅ 控制台错误 │
│ - console.error() │
│ - console.warn() │
│ │
│ ✅ 网络请求错误 │
│ - XHR 错误 │
│ - Fetch 错误 │
│ │
│ ✅ 资源加载错误 │
│ - 图片加载失败 │
│ - 脚本加载失败 │
│ - 样式表加载失败 │
│ │
└─────────────────────────────────────────────────────────────┘
手动捕获错误 #
captureException #
javascript
import LogRocket from 'logrocket';
try {
riskyOperation();
} catch (error) {
LogRocket.captureException(error);
}
带额外信息 #
javascript
try {
processOrder(orderData);
} catch (error) {
LogRocket.captureException(error, {
extra: {
orderId: orderData.id,
userId: orderData.userId,
items: orderData.items
},
tags: {
feature: 'checkout',
severity: 'high'
}
});
}
捕获自定义错误 #
javascript
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
function validateForm(data) {
if (!data.email) {
const error = new ValidationError('Email is required', 'email');
LogRocket.captureException(error, {
extra: {
formData: data,
field: 'email'
}
});
throw error;
}
}
错误上下文 #
LogRocket 提供的上下文 #
text
┌─────────────────────────────────────────────────────────────┐
│ 错误上下文信息 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 环境信息: │
│ - 浏览器类型和版本 │
│ - 操作系统 │
│ - 设备类型 │
│ - 屏幕分辨率 │
│ - 语言设置 │
│ │
│ 用户信息: │
│ - 用户 ID │
│ - 用户属性 │
│ - 会话 ID │
│ │
│ 页面信息: │
│ - 当前 URL │
│ - 页面标题 │
│ - Referrer │
│ │
│ 技术信息: │
│ - 错误堆栈 │
│ - 源码位置 │
│ - 网络请求 │
│ - 控制台日志 │
│ - Redux/Vuex 状态 │
│ │
│ 操作历史: │
│ - 面包屑 │
│ - 用户交互 │
│ - 页面导航 │
│ │
└─────────────────────────────────────────────────────────────┘
错误详情示例 #
javascript
{
"error": {
"type": "TypeError",
"message": "Cannot read property 'id' of undefined",
"stacktrace": [
{
"filename": "https://example.com/static/js/main.js",
"lineno": 123,
"colno": 45,
"function": "getUserData"
}
]
},
"context": {
"user": {
"id": "user-123",
"email": "john@example.com"
},
"browser": {
"name": "Chrome",
"version": "120.0"
},
"os": {
"name": "Windows",
"version": "10"
},
"url": "https://example.com/dashboard",
"breadcrumbs": [
{ "type": "navigation", "message": "Navigate to /dashboard" },
{ "type": "http", "message": "GET /api/users" }
],
"networkRequests": [
{ "url": "/api/users", "status": 200, "duration": 245 }
]
}
}
错误分组 #
自动分组规则 #
text
┌─────────────────────────────────────────────────────────────┐
│ 错误分组规则 │
├─────────────────────────────────────────────────────────────┤
│ │
│ LogRocket 自动将相似错误分组: │
│ │
│ 分组依据: │
│ 1. 错误类型(TypeError, ReferenceError...) │
│ 2. 错误消息模式 │
│ 3. 堆栈指纹 │
│ 4. 源文件位置 │
│ │
│ 示例: │
│ │
│ Issue #1234: TypeError: Cannot read property 'id' │
│ ├── 发生次数: 1,234 次 │
│ ├── 影响用户: 567 人 │
│ ├── 首次发生: 2024-01-15 10:30:00 │
│ └── 最后发生: 2024-01-20 15:45:00 │
│ │
└─────────────────────────────────────────────────────────────┘
自定义分组 #
javascript
LogRocket.captureException(error, {
fingerprint: ['{{ default }}', 'checkout-flow'],
extra: {
customGroupingKey: 'checkout-error'
}
});
Source Map 配置 #
为什么需要 Source Map? #
text
┌─────────────────────────────────────────────────────────────┐
│ Source Map 的作用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 问题:生产环境代码被压缩和混淆 │
│ │
│ 压缩后的错误堆栈: │
│ TypeError: Cannot read property 'id' of undefined │
│ at a (main.min.js:1:2345) │
│ at b (main.min.js:1:3456) │
│ at c (main.min.js:1:4567) │
│ │
│ 使用 Source Map 后: │
│ TypeError: Cannot read property 'id' of undefined │
│ at getUserData (user.js:45:12) │
│ at fetchUsers (api.js:123:8) │
│ at componentDidMount (UserList.jsx:34:5) │
│ │
│ 优势: │
│ ✅ 看到原始文件名 │
│ ✅ 看到原始行号和列号 │
│ ✅ 看到原始函数名 │
│ ✅ 快速定位问题 │
│ │
└─────────────────────────────────────────────────────────────┘
上传 Source Map #
使用 CLI #
bash
npm install -g @logrocket/cli
logrocket upload <app-id> <path-to-sourcemaps> \
--release <version> \
--url-prefix <url-prefix>
使用 Webpack 插件 #
javascript
const LogRocketSourceMapPlugin = require('@logrocket/webpack-plugin');
module.exports = {
plugins: [
new LogRocketSourceMapPlugin({
appID: 'your-app-id',
release: process.env.npm_package_version,
publicPath: 'https://example.com/static/js/'
})
]
};
使用 CI/CD #
yaml
# GitHub Actions 示例
- name: Upload Source Maps to LogRocket
run: |
npm install -g @logrocket/cli
logrocket upload your-app-id ./dist/static/js \
--release ${{ env.VERSION }} \
--url-prefix https://example.com/static/js/
env:
LOGROCKET_API_KEY: ${{ secrets.LOGROCKET_API_KEY }}
Source Map 最佳实践 #
text
┌─────────────────────────────────────────────────────────────┐
│ Source Map 最佳实践 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 版本管理 │
│ - 每次发布使用唯一版本号 │
│ - Source Map 与版本对应 │
│ │
│ 2. 自动化上传 │
│ - 在 CI/CD 流程中自动上传 │
│ - 确保与部署同步 │
│ │
│ 3. URL 前缀 │
│ - 正确配置 URL 前缀 │
│ - 确保 Source Map 可被正确匹配 │
│ │
│ 4. 安全考虑 │
│ - 不要将 Source Map 部署到生产环境 │
│ - 只上传到 LogRocket │
│ - 保护 API Key │
│ │
└─────────────────────────────────────────────────────────────┘
错误分析 #
错误仪表板 #
text
┌─────────────────────────────────────────────────────────────┐
│ 错误仪表板 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 错误概览 │ │
│ │ │ │
│ │ 今日错误: 1,234 影响用户: 567 新增: 5 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 错误趋势 │ │
│ │ │ │
│ │ [错误数量趋势图] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 错误列表 │ │
│ │ │ │
│ │ 错误类型 消息 次数 用户 │ │
│ │ TypeError Cannot read... 567 123 │ │
│ │ ReferenceError x is not... 234 89 │ │
│ │ NetworkError Failed to... 123 45 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
错误详情分析 #
text
┌─────────────────────────────────────────────────────────────┐
│ 错误详情页面 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 错误信息: │
│ - 错误类型 │
│ - 错误消息 │
│ - 堆栈跟踪 │
│ │
│ 统计信息: │
│ - 发生次数 │
│ - 影响用户数 │
│ - 首次/最后发生时间 │
│ │
│ 分布信息: │
│ - 浏览器分布 │
│ - 操作系统分布 │
│ - 页面分布 │
│ - 版本分布 │
│ │
│ 相关会话: │
│ - 最近发生的会话列表 │
│ - 点击查看会话回放 │
│ │
└─────────────────────────────────────────────────────────────┘
错误过滤 #
text
┌─────────────────────────────────────────────────────────────┐
│ 错误过滤 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 按类型过滤: │
│ - TypeError │
│ - ReferenceError │
│ - NetworkError │
│ │
│ 按环境过滤: │
│ - 浏览器 │
│ - 操作系统 │
│ - 设备类型 │
│ │
│ 按时间过滤: │
│ - 最近 1 小时 │
│ - 最近 24 小时 │
│ - 最近 7 天 │
│ - 自定义范围 │
│ │
│ 按版本过滤: │
│ - 特定版本 │
│ - 版本范围 │
│ │
└─────────────────────────────────────────────────────────────┘
错误告警 #
配置告警规则 #
javascript
// 在 LogRocket 控制台配置告警
// 示例告警规则
{
"name": "高优先级错误告警",
"conditions": {
"errorType": "TypeError",
"threshold": 10,
"timeWindow": "1h",
"affectedUsers": 5
},
"actions": [
{
"type": "email",
"recipients": ["dev-team@example.com"]
},
{
"type": "slack",
"channel": "#alerts"
}
]
}
告警类型 #
text
┌─────────────────────────────────────────────────────────────┐
│ 告警类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 错误频率告警 │
│ - 错误次数超过阈值 │
│ - 影响用户数超过阈值 │
│ │
│ 2. 新错误告警 │
│ - 首次出现的错误 │
│ - 新版本引入的错误 │
│ │
│ 3. 错误回归告警 │
│ - 已解决的错误再次出现 │
│ │
│ 4. 趋势告警 │
│ - 错误率持续上升 │
│ - 与上一周期对比 │
│ │
└─────────────────────────────────────────────────────────────┘
错误处理最佳实践 #
1. 全局错误处理 #
javascript
// JavaScript 错误
window.onerror = function(message, source, lineno, colno, error) {
LogRocket.captureException(error || new Error(message), {
extra: {
source: source,
lineno: lineno,
colno: colno
}
});
return false;
};
// Promise 拒绝
window.addEventListener('unhandledrejection', function(event) {
LogRocket.captureException(event.reason, {
extra: {
type: 'unhandledrejection'
}
});
});
// 资源加载错误
window.addEventListener('error', function(event) {
if (event.target !== window) {
LogRocket.captureException(new Error('Resource load error'), {
extra: {
tagName: event.target.tagName,
src: event.target.src || event.target.href
}
});
}
}, true);
2. React 错误边界 #
javascript
import React from 'react';
import LogRocket from 'logrocket';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
LogRocket.captureException(error, {
extra: {
componentStack: errorInfo.componentStack,
props: this.props
},
tags: {
feature: 'react-error-boundary'
}
});
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
3. API 错误处理 #
javascript
async function fetchWithTracking(url, options = {}) {
try {
const response = await fetch(url, options);
if (!response.ok) {
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
LogRocket.captureException(error, {
extra: {
url: url,
method: options.method || 'GET',
status: response.status,
statusText: response.statusText
},
tags: {
type: 'api-error'
}
});
throw error;
}
return response;
} catch (error) {
LogRocket.captureException(error, {
extra: {
url: url,
method: options.method || 'GET'
},
tags: {
type: 'network-error'
}
});
throw error;
}
}
4. 表单验证错误 #
javascript
function validateForm(formData) {
const errors = [];
if (!formData.email) {
const error = new Error('Email is required');
LogRocket.captureException(error, {
extra: {
field: 'email',
formId: 'registration-form'
},
tags: {
type: 'validation-error'
},
level: 'warning'
});
errors.push({ field: 'email', message: 'Email is required' });
}
if (!formData.password || formData.password.length < 8) {
const error = new Error('Password must be at least 8 characters');
LogRocket.captureException(error, {
extra: {
field: 'password',
formId: 'registration-form'
},
tags: {
type: 'validation-error'
},
level: 'warning'
});
errors.push({ field: 'password', message: 'Password must be at least 8 characters' });
}
return errors;
}
错误解决流程 #
text
┌─────────────────────────────────────────────────────────────┐
│ 错误解决流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Step 1: 收到错误告警 │
│ ↓ │
│ Step 2: 查看错误详情 │
│ - 错误类型和消息 │
│ - 堆栈跟踪 │
│ - 影响范围 │
│ ↓ │
│ Step 3: 分析错误上下文 │
│ - 用户信息 │
│ - 浏览器/设备 │
│ - 操作历史 │
│ ↓ │
│ Step 4: 查看会话回放 │
│ - 观看错误发生过程 │
│ - 理解用户操作 │
│ ↓ │
│ Step 5: 定位问题根因 │
│ - 分析代码 │
│ - 检查数据 │
│ ↓ │
│ Step 6: 修复问题 │
│ - 编写修复代码 │
│ - 编写测试 │
│ ↓ │
│ Step 7: 验证修复 │
│ - 部署修复 │
│ - 监控错误是否消失 │
│ ↓ │
│ Step 8: 标记错误已解决 │
│ │
└─────────────────────────────────────────────────────────────┘
下一步 #
现在你已经掌握了错误追踪的使用方法,接下来学习 高级功能 了解 LogRocket 的更多高级特性!
最后更新:2026-03-29