2024年Web前端最全前端监控sdk,最新资料大全

总结

技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

})

}

复制代码

React错误

react 通过componentDidCatch,声明一个错误边界的组件

class ErrorBoundary extends React.Component {

constructor(props) {

super(props);

this.state = { hasError: false };

}

static getDerivedStateFromError(error) {

// 更新 state 使下一次渲染能够显示降级后的 UI

return { hasError: true };

}

componentDidCatch(error, errorInfo) {

// 你同样可以将错误日志上报给服务器

logErrorToMyService(error, errorInfo);

}

render() {

if (this.state.hasError) {

// 你可以自定义降级后的 UI 并渲染

return

Something went wrong.

;

}

return this.props.children;

}

}

class App extends React.Component {

render() {

return (

)

}

}

复制代码

但error boundaries并不会捕捉以下错误:React事件处理,异步代码,error boundaries自己抛出的错误。

跨域问题

一般情况,如果出现 Script error 这样的错误,基本上可以确定是出现了跨域问题。

如果当前投放页面和云端JS所在不同域名,如果云端JS出现错误,window.onerror会出现Script Error。通过以下两种方法能给予解决。

  • 后端配置Access-Control-Allow-Origin、前端script加crossorigin。

const script = document.createElement(‘script’);

script.crossOrigin = ‘anonymous’;

script.src = ‘http://yun.tuia.cn/test.js’;

document.body.appendChild(script);

复制代码

  • 如果不能修改服务端的请求头,可以考虑通过使用 try/catch 绕过,将错误抛出。

<!doctype html>

Test page in http://test.com

复制代码

会发现如果不加try catch,console.log就会打印script error。加上try catch就能捕获到。 ​

我们捋一下场景,一般调用远端js,有下列三种常见情况。

  • 调用远端JS的方法出错

  • 远端JS内部的事件出问题

  • 要么在setTimeout等回调内出错

调用方法场景

可以通过封装一个函数,能装饰原方法,使得其能被try/catch。

<!doctype html>

Test page in http://test.com

复制代码

大家可以尝试去掉wrapErrors感受下。 ​

事件场景

可以劫持原生方法。

<!doctype html>

Test page in http://test.com
http://test.com

复制代码

大家可以尝试去掉封装EventTarget.prototype.addEventListener的那段代码,感受下。

上报接口

为什么不能直接用GET/POST/HEAD请求接口进行上报? ​

这个比较容易想到原因。一般而言,打点域名都不是当前域名,所以所有的接口请求都会构成跨域。 ​

为什么不能用请求其他的文件资源(js/css/ttf)的方式进行上报? ​

创建资源节点后只有将对象注入到浏览器DOM树后,浏览器才会实际发送资源请求。而且载入js/css资源还会阻塞页面渲染,影响用户体验。 ​

构造图片打点不仅不用插入DOM,只要在js中new出Image对象就能发起请求,而且还没有阻塞问题,在没有js的浏览器环境中也能通过img标签正常打点。

使用new Image进行接口上报。最后一个问题,同样都是图片,上报时选用了1x1的透明GIF,而不是其他的PNG/JEPG/BMP文件。 ​

首先,1x1像素是最小的合法图片。而且,因为是通过图片打点,所以图片最好是透明的,这样一来不会影响页面本身展示效果,二者表示图片透明只要使用一个二进制位标记图片是透明色即可,不用存储色彩空间数据,可以节约体积。因为需要透明色,所以可以直接排除JEPG。 ​

同样的响应,GIF可以比BMP节约41%的流量,比PNG节约35%的流量。GIF才是最佳选择。

  • 可以进行跨域

  • 不会携带cookie

  • 不需要等待服务器返回数据

使用1*1的gif

非阻塞加载

尽量避免SDK的js资源加载影响。

通过先把window.onerror的错误记录进行缓存,然后异步进行SDK的加载,再在SDK里面处理错误上报。

这是一个测试页面(new)

复制代码

采集聚合端(日志服务器)


这个环节,输入是借口接收到的错误记录,输出是有效的数据入库。核心功能需要对数据进行清洗,顺带解决了过多的服务压力。另一个核心功能是对数据进行入库。

总体流程可以看为错误标识 -> 错误过滤 -> 错误接收 -> 错误存储。

错误标识(SDK配合)

聚合之前,我们需要有不同维度标识错误的能力,可以理解为定位单个错误条目,单个错误事件的能力。 ​

单个错误条目

通过date和随机值生成一条对应的错误条目id。

const errorKey = ${+new Date()}@${randomString(8)}

function randomString(len) {

len = len || 32;

let chars = ‘ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678’;

let maxPos = chars.length;

let pwd = ‘’;

for (let i = 0; i < len; i++) {

pwd += chars.charAt(Math.floor(Math.random() * maxPos));

}

return pwd;

}

复制代码

单个错误事件

首先需要有定位同个错误事件(不同用户,发生相同错误类型、错误信息)的能力。

通过message、colno与lineno进行相加计算阿斯克码值,可以生成错误的errorKey。

const eventKey = compressString(String(e.message), String(e.colno) + String(e.lineno))

function compressString(str, key) {

let chars = ‘ABCDEFGHJKMNPQRSTWXYZ’;

if (!str || !key) {

return ‘null’;

}

let n = 0,

m = 0;

for (let i = 0; i < str.length; i++) {

n += str[i].charCodeAt();

}

for (let j = 0; j < key.length; j++) {

m += key[j].charCodeAt();

}

let num = n + ‘’ + key[key.length - 1].charCodeAt() + m + str[str.length - 1].charCodeAt();

if(num) {

num = num + chars[num[num.length - 1]];

}

return num;

}

复制代码

如下图,一个错误事件(事件列表),下属每条即为实际的错误条目。

错误过滤(SDK配合)

域名过滤

过滤本页面script error,可能被webview插入其他js。

我们只关心自己的远端JS问题,因此做了根据本公司域名进行过滤。

// 伪代码

if(!e.filename || !e.filename.match(/^(http|https)😕/yun./)) return true

复制代码

重复上报

怎么避免重复的数据上报?根据errorKey来进行缓存,重复的错误避免上报的次数超过阈值。

// 伪代码

const localStorage = window.localStorage;

const TIMES = 6; // 缓存条数

export function setItem(key, repeat) {

if(!key) {

key = ‘unknow’;

}

if (has(key)) {

const value = getItem(key);

// 核心代码,超过条数,跳出

if (value >= repeat) {

return true;

}

storeStorage[key] = {

value: value + 1,

time: Date.now()

}

} else {

storeStorage[key] = {

value: 1,

time: Date.now()

}

}

return false;

}

复制代码

错误接收

在处理接收接口的时候,注意流量的控制,这也是后端开发需要投入最多精力的地方,处理高并发的流量。

错误记录

接收端使用Koa,简单的实现了接收及打印到磁盘。

// 伪代码

module.exports = async ctx => {

const { query } = ctx.request;

// 对于字段进行简单check

check([ ‘mobile’, ‘network’, ‘ip’, ‘system’, ‘ua’, …], query);

ctx.type = ‘application/json’;

ctx.body = { code: ‘1’, msg: ‘数据上报成功’ };

// 进行日志记录到磁盘的代码,根据自己的日志库选择

};

复制代码

削峰机制

比如每秒设置2000的阈值,然后根据请求量减少上限,定时重置上限。

// 伪代码

// 1000ms

const TICK = 1000;

// 1秒上限为2000

const MAX_LIMIT = 2000;

// 每台服务器请求上限值

let maxLimit = MAX_LIMIT;

/**

  • 启动重置函数

*/

const task = () => {

setTimeout(() => {

maxLimit = MAX_LIMIT;

task();

}, TICK);

};

task();

const check = () => {

if (maxLimit <= 0) {

throw new Error(‘超过上报次数’);

}

maxLimit–;

// 执行业务代码。。。

};

复制代码

采样处理

超过阈值,还可以进行采样收集。

// 只采集 20%

if(Math.random() < 0.2) {

collect(data) // 记录错误信息

}

复制代码

错误存储

对于打印在了磁盘的日志,我们怎么样才能对于其进行聚合呢,这里得考虑使用存储方案。

一般选择了存储方案后,设置好配置,存储方案就可以通过磁盘定时周期性的获取数据。因此我们需要选择一款存储方案。

对于存储方案,我们对比了日常常见方案,阿里云日志服务 - Log Service(SLS)、ELK(Elastic、Logstash、Kibana)、Hadoop/Hive(将数据存储在 Hadoop,利用 Hive 进行查询) 类方案的对比。

从以下方面进行了对比,最终选择了Log Service,主要考虑为无需搭建,成本低,查询功能满足。

| 功能项 | ELK 类系统 | Hadoop + Hive | 日志服务 |

| — | — | — | — |

| 日志延时 | 1~60 秒 | 几分钟~数小时 | 实时 |

| 查询延时 | 小于 1 秒 | 分钟级 | 小于 1 秒 |

| 查询能力 | 好 | 好 | 好 |

| 扩展性 | 提前预备机器 | 提前预备机器 | 秒级 10 倍扩容 |

| 成本 | 较高 | 较低 | 很低 |

日志延时:日志产生后,多久可查询。 查询延时:单位时间扫描数据量。 查询能力:关键词查询、条件组合查询、模糊查询、数值比较、上下文查询。 扩展性:快速应对百倍流量上涨。 成本:每 GB 费用。

具体API使用,可查看日志服务

可视分析端(可视化平台)


这个环节,输入是借口接收到的错误记录,输出是有效的数据入库。核心功能需要对数据进行清洗,顺带解决了过多的服务压力。另一个核心功能是对数据进行入库。

主功能

这部分主要是产品功能的合理设计,做到小而美,具体的怎么聚合,参考阿里云SLS就可以。

  1. 首页图表,可选1天、4小时、1小时等等,聚合错误数,根据1天切分24份来聚合。

  2. 首页列表,聚合选中时间内的数据,展示错误文件、错误key、事件数、错误类型、时间、错误信息。

  3. 错误详情,事件列表、基本信息、设备信息、设备占比图表(见上面事件列表的图)。

排行榜

刚开始做了待处理错误列表、我的错误列表、已解决列表,错误与人没有绑定关系,过于依赖人为主动,需要每个人主动到平台上处理,效果不佳。 ​

后面通过错误作者排行榜,通过钉钉日报来提醒对应人员处理。紧急错误,通过实时告警来责任到人,后面告警会说。

具体原理:

  • webpack打包通过git命令把作者和作者邮箱、时间打包在头部。

  • 在可视化服务中,去请求对应的报错url匹配到对应作者,返回给展示端。

SourceMap

利用webpack的hidden-source-map构建。与 source-map 相比少了末尾的注释,但 output 目录下的 index.js.map 没有少。线上环境避免source-map泄露。

webpackJsonp([1],[

function(e,t,i){…},

function(e,t,i){…},

function(e,t,i){…},

function(e,t,i){…},

])

// 这里没有生成source-map的链接地址

复制代码

根据报错文件的url,根据团队内部约定好的目录和规则,定位之前打包上传的sourceMap地址。

const sourcemapUrl = (‘xxxfolder/’ + url + ‘xxxHash’ +‘.map’)

复制代码

获取上报的line、column、source,利用第三方库sourceMap进行定位。

const sourceMap = require(‘source-map’)

// 根据行数获取源文件行数

const getPosition = async(map, rolno, colno) => {

const consumer = await new sourceMap.SourceMapConsumer(map)

const position = consumer.originalPositionFor({

line: rolno,

column: colno

})

position.content = consumer.sourceContentFor(position.source)

return position

}

复制代码

感兴趣SourceMap原理的,可以继续深入,SourceMap 与前端异常监控

错误报警


报警设置

  1. 每条业务线设置自己的阈值、错误时间跨度,报警轮询间隔

  2. 通过钉钉hook报警到对应的群

  3. 通过日报形式报出错误作者排行榜

○ 四、扩展

======

行为搜集


通过搜集用户的操作,可以明显发现错误为什么产生。

分类

  • UI行为: 点击、滚动、聚焦/失焦、长按

  • 浏览器行为:请求、前进/后退、跳转、新开页面、关闭

  • 控制台行为:log、warn、error

搜集方式

  1. 点击行为

使用addEventListener监听全局上的click事件,将事件和DOM元素名字收集。与错误信息一起上报。

  1. 发送请求

监听XMLHttpRequest的onreadystatechange回调函数

  1. 页面跳转

监听window.onpopstate,页面进行跳转时会触发。

  1. 控制台行为

重写console对象的info等方法。 ​

有兴趣可以参考行为监控

遇到的问题


由于涉及到一些隐私,下述会做脱敏处理。

空日志问题

上线灰度运行后,我们发现SLS日志存在一些空日志😢 ,🦢,这是发生了啥?

首先我们回忆下这个链路上有哪些环节可能存在问题。

排查链路,SLS采集环节之前有磁盘日志收集,服务端接收,SDK上报,那我们依次排查。 ​

往前一步,发现磁盘日志就已经存在空日志,那剩下就得看一下接收端、SDK端。

开始利用控制变量法,先在SDK端进行空判断,防止空日志上报。结果:发现无效😅。 ​

再继续对Node接收端处理,对接收到的数据进行判空,如果为空不进行日志打印,结果:依然无效😳。 ​

所以开始定位是不是日志打印本身出了什么问题?研究了下日志第三方日志库的API,进行了各种尝试,发现依旧没用,我脸黑了🌚。

什么情况,“遇事不决”看源码。排查下日志库源码存在什么问题。对于源码的主调用流程走了一遍,并没有发现什么问题,一头雾水🙃。 ​

整个代码逻辑很正常,这让我们开始怀疑难道是数据的问题,于是开始缩减上报的字段,最终定义为了一个字段。发现上线后没有问题了😢。 ​

难道是有些字段存储的数据过长导致的?但从代码逻辑、流程日志中并没有反应这个错误的可能性。 ​

总结

技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

发送请求

监听XMLHttpRequest的onreadystatechange回调函数

  1. 页面跳转

监听window.onpopstate,页面进行跳转时会触发。

  1. 控制台行为

重写console对象的info等方法。 ​

有兴趣可以参考行为监控

遇到的问题


由于涉及到一些隐私,下述会做脱敏处理。

空日志问题

上线灰度运行后,我们发现SLS日志存在一些空日志😢 ,🦢,这是发生了啥?

首先我们回忆下这个链路上有哪些环节可能存在问题。

排查链路,SLS采集环节之前有磁盘日志收集,服务端接收,SDK上报,那我们依次排查。 ​

往前一步,发现磁盘日志就已经存在空日志,那剩下就得看一下接收端、SDK端。

开始利用控制变量法,先在SDK端进行空判断,防止空日志上报。结果:发现无效😅。 ​

再继续对Node接收端处理,对接收到的数据进行判空,如果为空不进行日志打印,结果:依然无效😳。 ​

所以开始定位是不是日志打印本身出了什么问题?研究了下日志第三方日志库的API,进行了各种尝试,发现依旧没用,我脸黑了🌚。

什么情况,“遇事不决”看源码。排查下日志库源码存在什么问题。对于源码的主调用流程走了一遍,并没有发现什么问题,一头雾水🙃。 ​

整个代码逻辑很正常,这让我们开始怀疑难道是数据的问题,于是开始缩减上报的字段,最终定义为了一个字段。发现上线后没有问题了😢。 ​

难道是有些字段存储的数据过长导致的?但从代码逻辑、流程日志中并没有反应这个错误的可能性。 ​

总结

技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

[外链图片转存中…(img-4L38HcTF-1714844100814)]

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值