Open Genzhen opened 3 years ago
hi,老哥你好,自研的话,有办法定位到源码报错位置吗,我试过 node 起一个服务用来还原源文件,但是line与column不准确
hi,老哥你好,自研的话,有办法定位到源码报错位置吗,我试过 node 起一个服务用来还原源文件,但是line与column不准确
这个你得结合sourcemap吧?用开源的库source-map
hi,老哥你好,自研的话,有办法定位到源码报错位置吗,我试过 node 起一个服务用来还原源文件,但是line与column不准确
这个你得结合sourcemap吧?用开源的库source-map
是的呢,做法就是这样,能定位到错误文件,但是line与column不准确
扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。
一、需求背景
1.1 为什么要做
为了实现收集功能,我们需要一个前端监控平台,它能够收集数据、处理数据、存储数据、查询数据。其实就有很多现成的平台或者开源项目我们可以直接使用。
1.2 行内通用方案
前端技术发展至今,相信大家已经对前端监控的这件事情非常熟悉,或多或少都会在我们的项目中用上它。比如搭建使用开源项目 sentry、付费平台阿里的 ARMS、甚至小程序配套的前端监控服务。
在使用这些开源或者平台前端监控服务的时候,始终有一些不足。比如:
1.3 定制化
如果完全从 0 到 1 来打造一套前端监控系统,成本也是很高的。甚至在早期,都可能没人愿意用,系统是否能立项或者持续发展下去也是一个问题。于是从一些开源项目中去寻找,去找一个方便改造也有一定功能模块的项目。可以基于它的代码,进行长期的改造和迭代。慢慢的改造成为一个更适合公司内部环境的一个前端监控系统。
二、系统架构
2.1 基本构成
为了实现前端监控,第一要素是要收集客户端数据,为了方便客户端集成监控系统、我们需要首先开发封装一个统一的 SDK、去帮助我们收集数据。
SDK 收集了数据,我们还需要通过服务端接口来接收,在服务端,使用 node+EggJs,node 适合 i/o 密集型场景,符合前端技术栈。eggjs 简单易用、文档友好,大部分使用 node 的前端程序员都应该能很快上手。
服务端收集到数据并进行一些处理之后,我们需要存储到我们的数据库之中。在数据库方面,使用 mongo 做持久化存储,mongo 文档模型数据库,数据扩展方便,类 json 结构方便和 node 配合使用,天生适合日志系统。使用 redis 做数据缓存,redis 简单易用的高性能 key-value 数据库,市场上占据主流,被大部分人都熟知。
最后,还需要一个管理台,做数据查询与管理。管理台使用 Vue+ElementUI,简单快速。
客户端 SDK 收集数据上报,node 服务端获取到数据后,先存在 redis 中,node 服务会根据消费能力去拉取 redis 数据处理分析后存储到 mongo 之中,最后我们通过管理后台展示处理好的应用数据。
2.2 技术的可能的一些难点
可能整个系统比较复杂的就是如何高效合理的进行监控数据上传。除了异常报错信息本身,还需要记录用户操作日志,如果任何日志都立即上报,这无异于自造的 DDOS 攻击。那就需要考虑前端日志的存储,日志如何上传,上传前如何整理日志等问题。
对于日志的处理上报有这样的处理方案
我们并不单单采集异常本身日志,而且还会采集与异常相关的用户行为日志。单纯一条异常日志并不能帮助我们快速定位问题根源,找到解决方案。但如果要收集用户的行为日志,又要采取一定的技巧,而不能用户每一个操作后,就立即将该行为日志传到服务器,对于具有大量用户同时在线的应用,如果用户一操作就立即上传日志,无异于对日志服务器进行 DDOS 攻击。因此,我们先将这些日志存储在用户客户端本地,达到一定条件之后,再同时打包上传一组日志。
那么,如何进行前端日志存储呢?我们不可能直接将这些日志用一个变量保存起来,这样会挤爆内存,而且一旦用户进行刷新操作,这些日志就丢失了,因此,我们自然而然想到前端数据持久化方案。
目前,可用的持久化方案可选项也比较多了,主要有:Cookie、localStorage、sessionStorage、IndexedDB、webSQL 、FileSystem 等等。那么该如何选择呢?我们通过一个表来进行对比:
综合之后,IndexedDB 是最好的选择,它具有容量大、异步的优势,异步的特性保证它不会对界面的渲染产生阻塞。而且 IndexedDB 是分库的,每个库又分 store,还能按照索引进行查询,具有完整的数据库管理思维,比 localStorage 更适合做结构化数据管理。但是它有一个缺点,就是 api 非常复杂,不像 localStorage 那么简单直接。针对这一点,我们可以使用 hello-indexeddb 这个工具,它用 Promise 对复杂 api 进行来封装,简化操作,使 IndexedDB 的使用也能做到 localStorage 一样便捷。另外,IndexedDB 是被广泛支持的 HTML5 标准,兼容大部分浏览器,因此不用担心它的发展前景。
按照上报的频率(重要紧急度)可将上报分为四类
收集到日志后,立即触发上报函数。仅用于 A 类异常。而且由于受到网络不确定因素影响,A 类日志上报需要有一个确认机制,只有确认服务端已经成功接收到该上报信息之后,才算完成。否则需要有一个循环机制,确保上报成功。
将收集到的日志存储在本地,当收集到一定数量之后再打包一次性上报,或者按照一定的频率(时间间隔)打包上传。这相当于把多次合并为一次上报,以降低对服务器的压力。
将一次异常的场景打包为一个区块后进行上报。它和批量上报不同,批量上报保证了日志的完整性,全面性,但会有无用信息。而区块上报则是针对异常本身的,确保单个异常相关的日志被全部上报。
在界面上提供一个按钮,用户主动反馈 bug。这有利于加强与用户的互动。
或者当异常发生时,虽然对用户没有任何影响,但是应用监控到了,弹出一个提示框,让用户选择是否愿意上传日志。这种方案适合涉及用户隐私数据时。
即时上报虽然叫即时,但是其实也是通过类似队列的循环任务去完成的,它主要是尽快把一些重要的异常提交给监控系统,好让运维人员发现问题,因此,它对应的紧急程度比较高。
批量上报和区块上报的区别:批量上报是一次上报一定条数,比如每 2 分钟上报 1000 条,直到上报完成。而区块上报是在异常发生之后,马上收集和异常相关的所有日志,查询出哪些日志已经由批量上报上报过了,剔除掉,把其他相关日志上传,和异常相关的这些日志相对而言更重要一些,它们可以帮助尽快复原异常现场,找出发生异常的根源。
用户提交的反馈信息,则可以慢悠悠上报上去。