前端错误监听与上报框架工作原理,如:Sentry

06-01 1357阅读

文章目录

  • 前言
    • 🔧 一、核心监听方式(浏览器层)
      • 1. 拦截同步错误:`window.onerror`
      • 2. 拦截异步错误:`window.addEventListener('unhandledrejection')`
      • 3. 覆写全局 API:如 `console.error`、`XMLHttpRequest.prototype.send`
      • ⚙️ 二、框架适配层(Vue/React/Angular)
        • Vue 示例(Vue 2 / Vue 3)
        • React 示例(ErrorBoundary)
        • 🧪 三、错误信息序列化 & 上报
          • 错误标准格式:
          • 上报方式:
          • 🔄 四、额外能力(增强稳定性与分析能力)
            • 1. Source Map 支持
            • 2. Breadcrumbs(用户行为轨迹)
            • 3. 采样与过滤
            • 📦 五、Sentry SDK 封装架构简要流程
            • ✅ 总结一句话:
            • 🧩 一、前端 SDK 最小实现
              • 📁 文件结构
              • 🔧 `error-sdk.js`
              • 🧪 二、模拟错误触发(`index.html`)
              • 🧰 三、后端错误日志接收(Node.js + Express)
                • 📁 文件结构
                • 🔧 `index.js`
                • 📈 四、运行方式(测试用)
                • 🚀 五、进阶扩展建议
                • ✅ 总结
                • Vue 3 错误查看平台
                  • 🧱 一、项目结构概览(Vue 3 + Vite)
                  • 🚀 二、主要技术点实现
                    • 1. 获取错误日志列表(支持时间过滤)
                    • 2. 日志聚类(前端聚类示例)
                    • 3. 时间过滤 UI 示例
                    • 4. 日志卡片组件(堆栈、行为轨迹回放)
                    • 5. 主视图:分页+聚类展示
                    • 📦 三、运行环境和后端配合
                      • 后端 `/api/logs` 响应格式:
                      • ✅ 四、进一步可扩展能力

                        前言

                        像 Sentry 这样的前端错误监听与上报框架,其核心是通过劫持浏览器原生错误处理机制,并拦截框架生命周期中的异常,最终将错误信息序列化后发送到后端进行归档与聚合。

                        以下是它的底层工作原理剖析:


                        🔧 一、核心监听方式(浏览器层)

                        1. 拦截同步错误:window.onerror

                        window.onerror = function (message, source, lineno, colno, error) {
                          // 捕获运行时错误(语法/引用错误等)
                          sendToServer({ message, source, lineno, colno, stack: error?.stack });
                        };
                        

                        作用:

                        • 捕获未被 try/catch 包裹的错误
                        • 包含错误信息、脚本来源、行列号、错误堆栈

                          2. 拦截异步错误:window.addEventListener('unhandledrejection')

                          了解更多 :unhandledrejection | Web api MDN

                          window.addEventListener("unhandledrejection", event => {
                            const reason = event.reason;
                            sendToServer({ type: 'PromiseError', reason });
                          });
                          

                          作用:

                          • 捕获未处理的 Promise 错误
                          • 包括 fetch(...).then().then() 链中报错但未 .catch() 的情况

                            前端错误监听与上报框架工作原理,如:Sentry


                            3. 覆写全局 API:如 console.error、XMLHttpRequest.prototype.send

                            部分监控库还会:

                            • 重写 console.error,记录开发者手动抛出的信息
                            • Hook fetch / XMLHttpRequest 以监听请求失败

                              ⚙️ 二、框架适配层(Vue/React/Angular)

                              Vue 示例(Vue 2 / Vue 3)

                              Vue.config.errorHandler = (err, vm, info) => {
                                sendToServer({
                                  message: err.message,
                                  stack: err.stack,
                                  component: vm.$options.name || '(anonymous)',
                                  info
                                });
                              };
                              
                              • Vue 把组件渲染和事件处理等错误暴露给 errorHandler
                              • Sentry 会自动注册这个钩子进行错误接管

                                React 示例(ErrorBoundary)

                                class ErrorBoundary extends React.Component {
                                  componentDidCatch(error, info) {
                                    sendToServer({ error, info });
                                  }
                                  ...
                                }
                                
                                • React 17+ 推荐使用 ErrorBoundary 组件包裹所有 UI 节点
                                • Sentry 提供开箱即用的 withErrorBoundary 高阶组件

                                  🧪 三、错误信息序列化 & 上报

                                  错误标准格式:

                                  {
                                    "message": "Cannot read property 'x' of undefined",
                                    "type": "TypeError",
                                    "stack": "at Object. (main.js:10:15)",
                                    "timestamp": 1684453410000,
                                    "browser": "Chrome 113",
                                    "userAgent": "...",
                                    "url": "https://xxx.com/page",
                                    "breadcrumbs": [...], // 用户行为轨迹
                                    "extra": {...}
                                  }
                                  

                                  上报方式:

                                  • Sentry 使用beacon / fetch / xhr等方式发送错误日志到后端
                                  • 示例:
                                    navigator.sendBeacon('/api/log', JSON.stringify(error));
                                    
                                    • Sentry SDK 支持异步缓冲、重试、采样率控制等机制

                                      🔄 四、额外能力(增强稳定性与分析能力)

                                      1. Source Map 支持

                                      • Sentry 可上传构建时生成的 .map 文件
                                      • 将压缩代码中的错误还原为源码中的具体文件、行号、方法名等

                                        2. Breadcrumbs(用户行为轨迹)

                                        • 自动记录用户行为链,如点击、输入、页面跳转、XHR 请求等
                                        • 每条错误日志都会带一份"历史行为快照"

                                          3. 采样与过滤

                                          • 默认并不记录所有错误,防止高频错误占满带宽
                                          • 可配置采样比例(如 10% 上报)、忽略特定错误类型或路径

                                            📦 五、Sentry SDK 封装架构简要流程

                                            浏览器/框架异常
                                                  ↓
                                            捕获器(window.onerror / unhandledrejection / Vue.errorHandler 等)
                                                  ↓
                                            中间层(格式标准化 + 过滤 + 日志构造)
                                                  ↓
                                            缓冲池(采样 + 批量 + 异步)
                                                  ↓
                                            HTTP 上报(beacon/fetch/XHR)
                                                  ↓
                                            Sentry 服务端聚合处理
                                            

                                            ✅ 总结一句话:

                                            Sentry 的底层是基于浏览器和框架提供的全局异常钩子,结合源码映射、用户行为追踪和智能采样,完成完整的“采集→转化→上报→可视化”流程。


                                            下面是一个最小可用的“类 Sentry 前端错误上报系统”示例,包括:

                                            1. ✅ 前端 SDK(监听、采集、上报)
                                            2. ✅ 后端服务(接收、保存、可视化展示)
                                            3. ✅ 进阶扩展建议(sourceMap、用户行为轨迹、异常采样)

                                            🧩 一、前端 SDK 最小实现

                                            📁 文件结构

                                            /client/
                                              ├── index.html
                                              ├── error-sdk.js   ← 错误监听与上报逻辑
                                            

                                            🔧 error-sdk.js

                                            (function () {
                                              const endpoint = 'https://your-server.com/api/log';
                                              function report(error) {
                                                const payload = {
                                                  message: error.message || error,
                                                  type: error.name || 'UnknownError',
                                                  stack: error.stack || '',
                                                  url: location.href,
                                                  userAgent: navigator.userAgent,
                                                  time: Date.now()
                                                };
                                                navigator.sendBeacon(endpoint, JSON.stringify(payload));
                                              }
                                              // 捕获同步错误
                                              window.onerror = function (msg, src, line, col, err) {
                                                report(err || msg);
                                              };
                                              // 捕获 Promise 错误
                                              window.addEventListener('unhandledrejection', event => {
                                                report(event.reason);
                                              });
                                              // 封装为全局对象供外部手动调用
                                              window.$ErrorSDK = {
                                                capture: report
                                              };
                                            })();
                                            

                                            🧪 二、模拟错误触发(index.html)

                                            
                                            
                                              Test Error
                                              
                                            
                                            
                                              

                                            点击按钮触发错误

                                            抛错

                                            🧰 三、后端错误日志接收(Node.js + Express)

                                            📁 文件结构

                                            /server/
                                              ├── index.js           ← 主服务
                                              ├── db.json            ← 模拟数据库
                                            

                                            🔧 index.js

                                            const express = require('express');
                                            const fs = require('fs');
                                            const app = express();
                                            const logs = [];
                                            app.use(express.json({ limit: '1mb' }));
                                            app.use(express.static(__dirname + '/public'));
                                            app.post('/api/log', (req, res) => {
                                              let raw = '';
                                              req.on('data', chunk => (raw += chunk));
                                              req.on('end', () => {
                                                try {
                                                  const log = JSON.parse(raw);
                                                  logs.push(log);
                                                  fs.writeFileSync('db.json', JSON.stringify(logs, null, 2));
                                                  res.sendStatus(204);
                                                } catch {
                                                  res.sendStatus(400);
                                                }
                                              });
                                            });
                                            // 简单页面查看日志
                                            app.get('/logs', (req, res) => {
                                              const data = fs.readFileSync('db.json', 'utf-8');
                                              res.send(`
                                            ${data}
                                            `); }); app.listen(3000, () => { console.log('🚀 Error log server running on http://localhost:3000'); });

                                            📈 四、运行方式(测试用)

                                            1. 安装依赖:

                                              npm install express
                                              
                                            2. 启动后端服务:

                                              node index.js
                                              
                                            3. 打开 client/index.html,点击按钮模拟异常

                                            4. 浏览器访问 http://localhost:3000/logs 查看错误信息


                                            🚀 五、进阶扩展建议

                                            功能建议实现方式
                                            source map 解析使用 Sentry CLI 或 source-map npm 包
                                            用户行为 Breadcrumb记录点击、跳转、输入事件至数组 window.$SDK.track(event) 并附加上报
                                            请求异常采集Hook XMLHttpRequest 与 fetch,记录失败请求
                                            错误去重与采样哈希 message+stack 内容并设置 TTL;使用采样率避免刷爆日志
                                            多端接入支持提供 init({ appKey }) 和上传接口文档,兼容 React/Vue
                                            数据持久化使用 SQLite / MongoDB / Elasticsearch 替代 db.json
                                            面板可视化使用 Vue3/React + ECharts 可视化报错趋势、影响用户数等指标

                                            ✅ 总结

                                            你现在已经拥有了一个:

                                            • ✨ 监听错误、捕获堆栈、上报后端的前端 SDK
                                            • 🧾 可接收并持久化日志的 Node 后端
                                            • 📊 简单的错误列表 UI 页面

                                              这就是最小版 Sentry 的工作模型。

                                              Vue 3 错误查看平台

                                              功能包括:

                                              • ✅ 错误列表展示(分页 / 时间过滤)
                                              • ✅ 错误聚类(按 message+stack 聚类)
                                              • ✅ 堆栈信息展开查看
                                              • ✅ 行为轨迹回放(breadcrumbs)
                                              • ✅ 基于 Element Plus 组件库 + Pinia 状态管理(可选)

                                                🧱 一、项目结构概览(Vue 3 + Vite)

                                                error-dashboard/
                                                ├── public/
                                                ├── src/
                                                │   ├── api/           ← 接口调用
                                                │   ├── components/    ← UI 组件(日志卡片、时间过滤等)
                                                │   ├── views/         ← 页面(ErrorList.vue)
                                                │   ├── App.vue
                                                │   └── main.ts
                                                ├── index.html
                                                ├── vite.config.ts
                                                

                                                🚀 二、主要技术点实现

                                                1. 获取错误日志列表(支持时间过滤)

                                                // src/api/error.ts
                                                import axios from 'axios';
                                                export interface ErrorLog {
                                                  id: string;
                                                  message: string;
                                                  stack: string;
                                                  type: string;
                                                  time: number;
                                                  url: string;
                                                  userAgent: string;
                                                  breadcrumbs: string[];
                                                }
                                                export const getErrorLogs = (params: { startTime?: number; endTime?: number }) =>
                                                  axios.get('/api/logs', { params });
                                                

                                                2. 日志聚类(前端聚类示例)

                                                // 简化版聚类函数:根据 message + stack 做分组
                                                export function clusterLogs(logs: ErrorLog[]) {
                                                  const map = new Map();
                                                  logs.forEach(log => {
                                                    const key = log.message + log.stack?.split('\n')[0]; // 可加 hash
                                                    if (!map.has(key)) map.set(key, []);
                                                    map.get(key)!.push(log);
                                                  });
                                                  return [...map.entries()].map(([key, group]) => ({
                                                    key,
                                                    count: group.length,
                                                    latest: group.sort((a, b) => b.time - a.time)[0],
                                                    samples: group
                                                  }));
                                                }
                                                

                                                3. 时间过滤 UI 示例

                                                
                                                  
                                                
                                                
                                                import { ref } from 'vue';
                                                const emit = defineEmits(['filter']);
                                                const range = ref([]);
                                                function emitFilter() {
                                                  if (range.value.length === 2) {
                                                    emit('filter', {
                                                      startTime: new Date(range.value[0]).getTime(),
                                                      endTime: new Date(range.value[1]).getTime()
                                                    });
                                                  }
                                                }
                                                
                                                

                                                4. 日志卡片组件(堆栈、行为轨迹回放)

                                                
                                                  
                                                    
                                                {{ log.message }} {{ log.type }}
                                                {{ new Date(log.time).toLocaleString() }}
                                                查看堆栈 行为轨迹
                                                {{ log.stack }}
                                                • {{ b }}
                                                import { ref } from 'vue'; defineProps(['log']); const showStack = ref(false); const showBreadcrumb = ref(false);

                                                5. 主视图:分页+聚类展示

                                                
                                                  
                                                  
                                                共 {{ group.count }} 次
                                                import { ref, onMounted } from 'vue'; import { getErrorLogs } from '@/api/error'; import { clusterLogs } from '@/utils/cluster'; import ErrorCard from '@/components/ErrorCard.vue'; import TimeFilter from '@/components/TimeFilter.vue'; const logs = ref([]); const clusters = ref([]); async function fetchLogs(params = {}) { const res = await getErrorLogs(params); logs.value = res.data; clusters.value = clusterLogs(logs.value); } function onFilter(params) { fetchLogs(params); } onMounted(() => fetchLogs());

                                                📦 三、运行环境和后端配合

                                                后端 /api/logs 响应格式:

                                                [
                                                  {
                                                    "id": "uuid",
                                                    "message": "Uncaught TypeError: Cannot read property 'x'",
                                                    "stack": "at main.js:1:123",
                                                    "type": "TypeError",
                                                    "time": 1684928000000,
                                                    "url": "https://xxx.com/page",
                                                    "userAgent": "...",
                                                    "breadcrumbs": ["click button", "fetch /api/user fail", ...]
                                                  }
                                                ]
                                                

                                                ✅ 四、进一步可扩展能力

                                                功能实现方式建议
                                                搜索 / 排序加入输入框 + 下拉框(Element UI Table 支持)
                                                权限访问登录鉴权 + token 验证
                                                图表展示错误趋势Vue + ECharts 绘制 bar/line 图
                                                map 映射源码后端集成 source-map npm 包,转堆栈回原文件
                                                行为轨迹可视化类似 DevTools 的 Timeline,做 step-by-step 回放

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码