skywalking-client-js 前端配置与源码解析

4,213 阅读10分钟

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 种错误类型,每种错误类型的实现方式都非常巧妙,是前端埋点中常用的错误追踪方式,他们分别是:

错误名类别实现方式
JSErrorsJS 执行错误使用 window.onerror 监听 JS 执行错误并上报
PromiseErrorsPromise Reject 错误使用 unhandledrejection 事件监听未处理 reject 并上报
VueErrorsVue 内部错误使用 Vue.config.errorHandler 监听错误
AjaxErrorsAjax 网络请求错误XHR 请求类型使用 xhrReadyStateChange 事件拦截并判断是否发生错误;fetch 请求则是重写 fetch 方法拦截响应 response,根据 response.status 判断是否发生错误
ResourceErrors资源加载错误在 window 上设置 error 监听,并判断 error 事件是否来源于HTMLScriptElementHTMLLinkElementHTMLImageElement;如果是,则判断未资源加载错误
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原生方案,这也是大多数性能埋点的方案,其配置由setPerformanceperformance方法实现,追踪页面初次加载中的各项性能参数。

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队列,随后会生成xhrInterceptorwindowFetch拦截器,以后者 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);

    }
}

如此一来你的所有xhrfetch请求都会被记录并上报。但也提供了你排除一些请求,不进行追踪的方式,在拦截器内部会有个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.methodurl两个 tag。现在我们可以用setCustomTags配置方法在 span 中加入一些我们自己的 tag:

ClientMonitor.setCustomTags([
    { key: 'key1', value: 'value1' },
    { key: 'key2', value: 'value2' },
  ]);

总结

如果你打算采用 skywalking 作为你的分布式系统的应用程序性能监视工具,那么skywalking-client-js可以帮助你十分轻松地将浏览器 web 端接入其中,经过简单的十余项配置就能实现强大的埋点功能,迅速展现在 skywalking UI 上。

他十分轻量化,埋点代码侵入量小,核心代码量在千行左右,均采用原生 API 实现,且控制上报频率后不会有太大的性能影响,是性价比很高的埋点方案。

但目前的上报信息我们可以控制的部分比较少,都是固定的,且不方便对不同类型服务的请求做区分,在添加setCustomTags方法后有所改善,现在 skywalking 依旧在发展壮大,未来可期。

如有错误,欢迎指正