关于前端:北斗监控概述之SDK篇二

41次阅读

共计 4451 个字符,预计需要花费 12 分钟才能阅读完成。

监控 SDK 的作用是收集客户端产生的日志,如何全面的收集日志是本篇探讨的重点。监控日志能够分为 3 类,异样日志、失常日志、性能日志,每次日志上报时还会上报 1 类通用的信息:

日志类型 二级分类 阐明
异样日志 JS 谬误、Server/Native 接口异样、资源下载异样 监控要害,需实时上报
失常日志 用户行为、log 信息、路由信息 日志量大,由用户被动上报
性能日志 首屏工夫、耗时明细、PV/UV 上报一次,同时统计 PV/UV
通用信息 我的项目标识、用户标识、环境信息 其余 3 类日志附加的通用信息

异样日志

JS 谬误是最常见的异样日志,但并不是所有异样都是 JS 谬误。接下来会介绍可能被大家疏忽的但对线上问题定位很重要的 三类异样的捕捉办法,包含

  1. Server 接口异样的捕捉办法
  2. Native 接口异样的捕捉办法
  3. 资源下载异样的捕捉办法

如何收集 Server 接口异样?

在第一篇中,咱们顺带介绍过通过 onerrorunhandledrejection 收集全局 JS 谬误。然而在咱们的理论业务中,其实是一些谬误或异样不会抛到全局,也就不会被 onerrorunhandledrejection 收集到。比方,Server 接口异样,就不会被抛到全局。

const serverAPI = '58.com/api'
const response = await fetch(serverAPI)

if(response.status < 400) {setState(() => ({data: response.json()}))   
} else {
  // 手动上报异样
  errorReport({serverAPI, status: response.status})
}

else 这块代码,有些业务同学可能会不写。如果没有手动上报,这些 Server 异样就会被疏忽,然而要求所有业务同学将每个 Server 异样都手动上报,也又不事实。怎么办呢?在监控 SDK 中对立上报。

重写 fetch 办法

Server 接口异样的捕捉办法,就是重写 window.fetch

const originalFetch = window.fetch

window.fetch = function wrapperFetch(...args) {return originalFetch.apply(window, args).then((response) => {  
           // 主动上报异样
          if (response.status >= 400) {errorReport({ serverApi: args[0], status: response.status })
          }
          return response;
      })
}

应用相似的办法:

  • 咱们也能够 wrapper XMLHttpRequest,捕捉 status >= 400 的状况。
  • 捕捉 fetch 走到 catch 中的状况。
  • 捕捉 fetch 超时的状况。

绕过 Hybrid SDK 与 Native 交互

咱们再往前想一步,调用 Server 接口异样不会被抛到全局,Native 接口异样也不会被抛到全局。Native 接口异样,也能够由监控 SDK 专门捕捉上传。思路和 wrapperFetch 办法思路相似,咱们能够 wrapperHybrid

这里先介绍一下业务怎么应用 Hybrid SDK 手动上报。接下来再说怎么主动上报。

const request = {action: 'getUser', params: 'useName'}
const response = await hybrid.action(request)
// 手动上报
if(response.code === 1) {errorReport({ ...request, code: response.code})
}

然而咱们有些老页面,一些业务自定义的交互协定,业务间接通过协定就和 Native 进行交互了,并没有应用通用的 Hybrid SDK。通过重写 Hybrid SDK 的形式就不失效了。怎么办呢?间接监听最底层的 JSBridge。

jsbridge('wbmain://hybrid/jsbridge?action=getUser&parmas=userName&callback=windowGetUser')

监听 JSBridge

JSBridge 包含申请和响应两个局部:

  • Web 申请 Native

    • 申请形式有多种,这些形式是由 Native 和 Web 当时进行约定的,也根本不会改变,因而比下层接口更为稳固。
    • 罕用办法一:Web 调用全局办法,Native 重写该办法进行拦挡。如重写拦挡 window.prompt()、自定义全局函数。
    • 罕用办法二:Web 通过 iframe 发送申请,Native 拦挡 iframe 申请。
  • Native 响应 Web

    • Web 当时自定义全局函数,并把全局函数名通过 schemacallback 参数传过来
    • Native 调用该全局函数,Web 就能拿到 Native 响应的参数了

以 iframe 计划为例,实现 Native 接口异样的捕捉办法是监控 iframe src 的变动,如下:

// 创立监听
const observer = new MutationObserver((mutationList) => {mutationList.forEach((mutation) => {
    // 获取申请 的 schema
    const schema = mutation.target.src
    // 获取当时定义的全局函数名
    const callback = getURLSearchParams(schema,'callback');
    // 通过 wrapper 拦挡响应,获取 native params,当 params 异样时上报
    // params 异样,由标准决定,如 errorCode = 1
    window[callback] = wrapperCallback(window[callback])
  })
});
// 开始监听 iframe src 变动
observer.observe(iframe, {attributes: true,attributeFilter: ['src']});

应用监听的形式获取更多信息

另外 2 类异样的监听形式:

  • 跨域报错(左):应用 CDN 托管 JS 资源,JS 和 Web url 不在同一个域,跨域 JS 的报错浏览器只会给出 script error 的提醒。script error 的提醒并不是真的报错信息,也没有谬误堆栈。通过重写监听函数,就能通过 try catch 捕捉这些函数的报错了
  • 资源报错(右):加载资源报错不会被 window.onerror 捕捉到,然而 资源异样能够被 window.addEventListener('error') 捕捉到。

性能收集

性能收集罕用的有两种计划,一种是业务自定义的性能规范,一种是业内通用的性能规范。

业务自定义的性能规范,须要入侵业务代码进行埋点收集,各个业务计划之间的都有一些差异,业务之间也不能横向比照,可用性较差。本篇重点探讨业内通用的性能规范,并 创新性地实现了 FP、LCP 指标在 RN 端的收集办法。

性能规范

另一种是 W3C 的性能规范,因为是浏览器的规范实现,能够不入侵业务代码,就能获取到页面加载耗时。W3C 的规范包含了 Navigation Timing 和 Navigation Timing Level 2,两份规范。第一份规范浏览器曾经反对很好了,第二份新规范支持性差一些,但规范之间差异不大,收集的时候做下向下兼容即可。

性能收集包含两块

  • 耗时明细
  • 白屏工夫

其中耗时明细的 Level 2 定义如下,所有耗时明细都须要收集:

白屏工夫统计

相比耗时明细,大家可能更关注白屏工夫,也就是页面整体渲染耗时。白屏工夫大家定义各不相同,这是因为大家业务场景不一样导致的,大抵能够分为两种定义。

  • 一种是后端间接生成模板,白屏工夫的定义为 DOMContentLoaded(DCL) 或 Load(L) 这种老指标
  • 一种是前端渲染页面,比方 React/Vue 为代表的 JS 生成页面,白屏工夫的定义为 FP、FCP、LCP 这类新指标

获取 FP、FCP、LCP 新指标的形式是 performance.getEntries(),然而这些新指标并未纳入 W3C 标准,只是 Google 提出来的一种标准,目前兼容性比拟差,可用性咱们也在验证中。

FP (first paint)指的是第一个像素渲染到屏幕上所用的工夫,FCP(first contentful paint)指的是第一个文字、图片等渲染到屏幕上所用的工夫。在大多数场景下,二者根本相等。

LCP(largest contentful paint) 指的是显示面积最大的文字或图片渲染到屏幕上所用的工夫。Google 提出的以 LCP 指标,曾经能够在最新 Chrome 和 Android 机型上收集到了,大家设计 SDK 时无妨一起收集上来,作为一种辅助指标来掂量页面性能。

RN 收集 FP LCP 指标

FP、LCP 指标非常适合 React Web 页面,那么也同样适宜 React Native 页面。业内并未有 FP、LCP 在 RN 上的实现,北斗 SDK 参考了 W3C 的 FP 和 LCP 规范,在 RN 中实现了 FP、LCP 指标的收集。

实现思路如下,在 RN 中监听所有 Text Image 组件的 onLayout 事件,就能获取该组件的渲染工夫点。这样 FP 第一个像素的渲染耗时,就能够算进去。onLayout 中蕴含渲染元素的 widthheight,就能够晓得那个是渲染面积最大的文字或图片,从而计算出 LCP 的耗时。 伪代码如下:

class RNVitals {
  // 记录 FP
  private fp;
  
  // 记录 LCP
  private lcp;

  // 监听所有 Image 的 onLayout 事件
  private setWrapperImage() {}
  
  // 监听所有 Text 的 onLyaout 事件
  private setWrapperText () {
    const TextRender = Text.render
    Text.render =  (...args) => {const originImage = TextRender.apply(this, args);
      const {onLayout} = originImage.props ;
      return React.cloneElement(originImage, {onLayout: (event: LayoutChangeEvent) => {this.track(event)
          onLayout && onLayout(event)
        }
      });
    }
  }
  
  // 计算 FP、LCP 指标
  private track(event: LayoutChangeEvent): void {
    const size = event.height * event.width
    
    // 记录第一个元素渲染的工夫戳
    if(this.fp == null) {
     this.fp = {
        size,
        layoutTime: Date.now()}
    }
    
    // 记录 & 更新最大面积元素渲染的工夫戳
    if (this.lcp.size < size) {
        this.lcp = {
          size,
          layoutTime: Date.now()}
    }
  }
  
  // 如果用户点击了页面或 lcp 2s 都没有更新,则进行性能上报
  publish report(){}
}

正文完
 0