skywalking-client-js 前端配置与源码解析
序言
skywalking
是目前最炙手可热的分布式应用性能监控系统,且 Skywalking 从 8.2
版本开始支持浏览器端的监控,实现的方式便是引入skywalking-client-js
库,这是一个 skywalking 官方出品的一个前端埋点上报插件。轻量化,配置简单,提供了性能追踪,错误追踪,网络请求追踪三大功能。
本篇将基于其配置函数从源码层面来讲解skywalking-client-js
的工作流程,帮助学习如何使用的同时,理解前端监控埋点上报的一些思想。
skywalking-client-js 目前已经发布到 v0.9.0 版本,本文也基于此版本讲解,官方 GitHub 地址请点击这里,整体源码并不大,入口文件在 src/monitor.ts 下,鼓励大家可以阅读一下
基本使用
skywalking-client-js
定义了一个ClientMonitor
对象,并将其挂载到了window
全局对象上,该对象很重要,因为我们所有的配置操作都基于此对象的方法,我们可以在项目中任意页面引入该对象随时进行配置:
import ClientMonitor from 'skywalking-client-js';
ClientMonitor.register({
// 基础配置
collector: 'http://127.0.0.1:12800',
service: 'FE_instance',
serviceVersion: '1.0.0',
pagePath: window.location.href,
})
ClientMonitor
内部定义了以下八种方法,我们将其区分为配置方法和内部方法,汇总如下:
- 配置方法:
- register
- catchErrors
- setPerformance
- reportFrameErrors
- setCustomTags
- performance
- 内部方法:
- validateTags
- validateOptions
配置方法即由我们调用来进行配置的方法,内部方法我们虽然可以进行调用,但没有什么实际作用,在这里的两个内部方法都是由其它配置方法调用,辅助进行参数校验。
通用配置项
大部分配置方法都需要传入一个通用的配置对象CustomReportOptions
(如果该配置方法使用了全局配置,且之前你已经进行过全局配置了则不需要),其定义了我们接入 OAP 数据上报服务器的一些详细信息:
- collector (string):上报的的 OAP 服务器地址(一般固定 12800 端口)
- service (string):自定义的客户端服务名
- serviceVersion (string):自定义的服务端实例版本
- pagePath (string):自定义的服务端端点,常指页面路由
skywalking-client-js
中会存在一个全局的通用配置被所有功能模块使用,有些配置方法会改变它,而有些方法仅会改变自己模块的配置,后续介绍的时候会说明。此外还存在继承了CustomReportOptions
的更全面的配置对象CustomOptionsType
,可以进行更详细的配置。
接下来我们从错误追踪,性能追踪,网络追踪三个方面来进行讲解
错误追踪
skywalking 在浏览器端定义了 6 种错误类型,每种错误类型的实现方式都非常巧妙,是前端埋点中常用的错误追踪方式,他们分别是:
错误名 | 类别 | 实现方式 |
---|---|---|
JSErrors | JS 执行错误 | 使用 window.onerror 监听 JS 执行错误并上报 |
PromiseErrors | Promise Reject 错误 | 使用 unhandledrejection 事件监听未处理 reject 并上报 |
VueErrors | Vue 内部错误 | 使用 Vue.config.errorHandler 监听错误 |
AjaxErrors | Ajax 网络请求错误 | XHR 请求类型使用 xhrReadyStateChange 事件拦截并判断是否发生错误;fetch 请求则是重写 fetch 方法拦截响应 response,根据 response.status 判断是否发生错误 |
ResourceErrors | 资源加载错误 | 在 window 上设置 error 监听,并判断 error 事件是否来源于HTMLScriptElement ,HTMLLinkElement ,HTMLImageElement ;如果是,则判断未资源加载错误 |
FrameErrors | 框架错误 | 非全局自动监听,需要自己手动传入 error 对象 |
错误追踪功能会在发生以上错误时,收集error
信息,并以 1min 的固定频率进行上报,目前我们暂时还无法改变上报频率。在这些错误类型中,前 5 种由catchErrors
进行全局配置,而最后一种由reportFrameErrors
进行捕获
catchErrors 配置方法
该配置方法需要传入通用配置和监听的错误类型配置,且其基础配置不会改变全局通用配置,仅作用于错误追踪模块:
ClientMonitor.catchErrors({
// 基础配置(错误上报的地址)
collector: 'http://127.0.0.1:12800',
service: 'FE_instance',
serviceVersion: '1.0.0',
pagePath: window.location.href,
// 错误监听
jsErrors: true, // 启用JSErrors,PromiseErrors错误的监听
apiErrors: true, // 启用AjaxErrors错误的监听
resourceErrors: true, // 启用ResourceErrors错误的监听
vue: true, // 启用VueErrors错误的监听
})
reportFrameErrors
该配置方法用于标记框架产生的错误,skywalking
本身只支持了Vue
的错误捕获,其余框架可能的错误,需要我们手动调用该方法进行上报,并传入产生的error
对象,同样不会改变全局通用配置:
ClientMonitor.reportFrameErrors({
// 基础配置
collector: 'http://127.0.0.1:12800',
service: 'vue-demo',
pagePath: '/app',
serviceVersion: 'v1.0.0',
}, error);
性能追踪
skywalking
的性能追踪采取的是window.performance
原生方案,这也是大多数性能埋点的方案,其配置由setPerformance
和performance
方法实现,追踪页面初次加载中的各项性能参数。
performance
该配置方法做的事情很简单,他会判断调用时页面是否加载完毕,如果已加载完成会立即调用内部的tracePerf.getPerf
方法,传入配置项并立即进行性能数据的收集和上报,如果还未加载完成会添加window.onLoad
监听,等到加载完成后再执行上述操作。
performance
才是实现性能追踪的主要方法,其配置项直接作用于性能追踪模块,不会改变全局配置,配置如下:
ClientMonitor.performance({
// 基础配置
collector: 'http://127.0.0.1:12800',
service: 'FE_instance',
serviceVersion: '1.0.0',
pagePath: window.location.href,
// 性能追踪
autoTracePerf: true,
useFmp: true,
enableSPA: false,
})
仅有简单的三个配置项,他们的作用于tracePerf.getPerf
方法,使用如下:
字段 | 功能 |
---|---|
autoTracePerf | 是否开启自动追踪,开启后才会去 window.performance 拿取性能数据,否则上报的内容中仅有通用配置的数据 |
useFmp | 是否收集 FMP 首次有效绘制性能指标,需要 autoTracePerf 开启才有用,会向上报数据添加一个 fmpTime 字段 |
enableSPA | 是否开启单页应用模式,开启后会在每次 window.onhashchange 事件中均发生性能数据 |
setPerformance
该方法会调用performance
来配置错误追踪,但他做了更多的工作,首先其会改变全局通用配置(如果你没有设置 useFmp,该方法会将其置为 false),并对我们传入的配置参数进行校验,随后会调用 performance 方法,最后还会根据全局配置重新设置一遍错误追踪(不包括框架错误追踪)。
也就是说 setPerformance 可以同时配置错误追踪和性能追踪,且会改变全局配置:
ClientMonitor.register({
// 基础配置
collector: 'http://127.0.0.1:12800',
service: 'FE_instance',
serviceVersion: '1.0.0',
pagePath: window.location.href,
// 错误追踪
jsErrors: true,
apiErrors: true,
resourceErrors: true,
vue: true,
// 性能追踪
autoTracePerf: true,
useFmp: true,
enableSPA: true,
})
网络追踪
skywalking-client-js
中的网络请求追踪,会记录你的网络请求情况并上报,该项功能只能由register
配置项完成,其也是最综合的配置项,三个功能模块均能配置,贴一段源码理解其做了什么:
register(configs: CustomOptionsType) {
// 改变全局配置
this.customOptions = {
...this.customOptions,
...configs,
};
// 校验参数
this.validateOptions();
// 启用错误追踪
this.catchErrors(this.customOptions);
if (!this.customOptions.enableSPA) {
// 如果没有开启enableSPA,启用性能追踪
this.performance(this.customOptions);
}
// 启用网络追踪
traceSegment(this.customOptions);
}
其配置功能全面,错误追踪和性能追踪我们前面已经介绍了,配置项是一样的,唯一值得注意的是如果你开启了enableSPA
,并不会开启性能追踪,需要你额外调用performance
来开启,我并不知道作者在这里的意图是什么,或许有其它考虑。最后是由traceSegment
开启的网络追踪方法。
traceSegment
从该方法的名字,片段追踪,我们引出skywalking
世界中存在的span
概念,这并不是我们的前端标签 span,而是指一个用来追踪的完整调用过程,从客户端到服务端的网络请求就是一个Exit
类型的 span 过程(还有其它的类型的 span,前端不用了解)。一个时间片段以内可能会发生多次请求,skywalking 会将多个 span 封装到 segments 中进行上报。
traceSegment
是如何知道一段时间内你发送了网络请求并记录上报的呢?其实是采用了拦截器重写fetch
方法和xhr
方法实现的。首先会在顶层定义一个segments
队列,随后会生成xhrInterceptor
和windowFetch
拦截器,以后者 fetch 请求为例,其伪代码如下:
windowFetch(option,segments){
// 复制原生fetch请求方法
const originFetch = window.fetch;
// 重写
window.fetch = async (args) => {
// 使用copy方法拿取请求
const response = await originFetch(...args);
const segment = {
// 用response和option构造上报数据
}
// 将该次请求数据添加到队列
segments.push(segment);
}
}
如此一来你的所有xhr
和fetch
请求都会被记录并上报。但也提供了你排除一些请求,不进行追踪的方式,在拦截器内部会有个hasTrace
标记,其判断逻辑为:
const hasTrace = !noTraceOrigins || (isSDKInternal && customConfig.traceSDKInternal);
前者表示是否在排除列表中,后者表示十分追踪自己的上报请求。traceSegment 还会设置一个循环定时器,定时轮询 segments 中是否有数据,存在的话就进行上报并清空,同时也有beforeunload
事件监听在页面关闭的时候进行最后的上报。
总结以上功能,有如下的配置项:
- traceSDKInternal:是否追踪自己的上报请求
- detailMode:设置是否开启详细模式,开启后会在 span 中添加更多详细信息的 tag
- noTraceOrigins (array):排除追踪的请求列表
- traceTimeInterval:设置循环定时器轮询的时间,默认 1min,单位 ms
register
最后我们通过一个完整的配置示例来说明register
的使用,除了基础配置外均使用默认配置:
ClientMonitor.register({
// 基础配置
collector: 'http://127.0.0.1:12800',
service: 'FE_instance',
serviceVersion: '1.0.0',
pagePath: window.location.href,
// 错误追踪
jsErrors: true,
apiErrors: true,
resourceErrors: true,
vue: true,
// 性能追踪
autoTracePerf: true,
useFmp: true,
enableSPA: true,
// 网络追踪
traceSDKInternal:false,
detailMode:false,
noTraceOrigins:[],
traceTimeInterval:60000
})
值得注意的是 register 方法全局只能调用一次,因为 traceSegment 的网络追踪是重写全局 fetch 和 xhr 方法实现的,多次调用会多次重写发生错误
setCustomTags
此配置方法是最新版的 v0.9.0 新增的,还记得网络追踪的detailMode
配置项可以像 span 中添加详细信息的 tag 吗,如果开启后会默认添加http.method
和url
两个 tag。现在我们可以用setCustomTags
配置方法在 span 中加入一些我们自己的 tag:
ClientMonitor.setCustomTags([
{ key: 'key1', value: 'value1' },
{ key: 'key2', value: 'value2' },
]);
总结
如果你打算采用 skywalking
作为你的分布式系统的应用程序性能监视工具,那么skywalking-client-js
可以帮助你十分轻松地将浏览器 web 端接入其中,经过简单的十余项配置就能实现强大的埋点功能,迅速展现在 skywalking UI 上。
他十分轻量化,埋点代码侵入量小,核心代码量在千行左右,均采用原生 API 实现,且控制上报频率后不会有太大的性能影响,是性价比很高的埋点方案。
但目前的上报信息我们可以控制的部分比较少,都是固定的,且不方便对不同类型服务的请求做区分,在添加setCustomTags
方法后有所改善,现在 skywalking 依旧在发展壮大,未来可期。
如有错误,欢迎指正