Skip to content
On this page

Anim 日志采集插件

Anim 提供了日志采集能力,可以将用户行为/小程序执行错误/业务接口错误通过本地日志与小程序实时日志的方式采集下来,方便后续开发者定位线上问题。Anim 日志采集插件除了支持原生小程序框架外,还可以支持 Uniapp/Taro 等第三方框架。

使用场景

当用户反馈小程序某些 Bug 的时候,如果没有日志辅助定位排查,可能需要耗费大量的时间。

而实时与本地日志插件可以让开发者通过日志快速定位,用户当时小程序所发生的事件,帮助开发者快速解决线上问题。

特别是在部分特殊场景,比如请求还没到网关和后端的时候,后端根本查不了当前用户的日志,

无法确定是用户本身网络问题,还是域名 DNS 解析有问题等等,

前端日志对于这一类问题可以提供非常关键的信息,比如用户请求失败内容,用户当时网络情况等。

本地日志甚至可以做到用户行为回溯,可以查看到用户打开了哪些页面,点击了哪些按钮等信息,快速模拟出 Bug 的复现路径。

与 RUM 的关系

在很多场景中,对于错误监控我们还会引入 RUM 前端性能监控。对于 anim-plugin-logger RUM,我们在实践中认为这两者更多是互补的关系,是需要一起使用来帮助开发者更好的定位问题。

RUM 更多的通用的大盘错误监控与性能监控,但是针对某个人在生产环境下的实时错误日志查询这里,并不能做到很好的闭环。RUM 对用户标识我们在实际业务下,更多的是设置为小程序的 openid,但是每个用户的 openid 对于小程序来说都是不一致的,而且需要通过后台的登录接口去换取该 openid。所以 RUM 实际上无法做到真正快速做到根据某个反馈人的微信账号,就可以快速查询到他在某个时间段的相关日志。一旦遇到类似 DNS 域名解析问题,前置网关问题导致换取 openid 的接口都发生了错误,那对于唯一用户的标识都无法获取,定位具体用户问题的难度就更大了。

所以针对这种情况,我们以往的经验都是基于 RUM 做错误监控大盘告警,基于小程序实时日志做到通过微信号直接查询用户的实时错误日志,结合一起来快速定位和判断线上环境的问题。

接入方式

安装插件

bash
npm install @ssv-lab/anim-plugin-logger --save

注意该 npm 包为 Coding Npm 的私有源,请先确定已经正确配置了 Coding Npm

初始化插件

js
// app.js
import Anim from '@ssv-lab/anim'
import LoggerPlugin from '@ssv-lab/anim-plugin-logger'

// options 配置会在下面详细阐述
Anim.use(LoggerPlugin, {
  reportRequestData: true, // 是否上报请求数据
  bisDomains: ["example.com"],
  errCodes: [
    {
      codeKey: "errcode",
      // 字符串或数字,按照实际接口返回来确定。
      // 这里填写的是正确的返回码,不符合这个返回码的都会被当作错误日志进行上报。
      errCode: 0
    },
    {
      codeKey: "code",
      // 支持多个返回码
      errCode: 200         
    }
  ]
})
  1. 点击开发者工具中的菜单栏:工具 --> 构建 npm
  2. 点击开发者工具中的菜单栏:设置 --> 项目设置 --> 勾选“使用 npm 模块”选项
  3. 构建完成后即可使用

当使用 Taro 框架时

js
// app.js

// React/Vue 同理
import { Component } from 'react'
import Anim from '@ssv-lab/anim'
import LoggerPlugin from '@ssv-lab/anim-plugin-logger'
import CryptoPlugin from '@ssv-lab/anim-plugin-api-encrypt'
import './app.css'
Anim
  .use(CryptoPlugin, {
    publicKeyUrl: 'https://dev-myheart.ssv.tencent.com/kong/requestEncryption/getPublicKey'
  })
  .use(LoggerPlugin, {
    // Vue,
    bisDomains: ["https://dev-myheart.ssv.tencent.com"],
    errCodes: [],
  })

class App extends Component {}

当使用 Uniapp 框架时

js
// main.js
import Vue from 'vue'
import App from './App.vue'
import Anim from '@ssv-lab/anim'
import LoggerPlugin from '@ssv-lab/anim-plugin-logger'

Anim.use(LoggerPlugin, {
  // 这里需要传入 Vue 构造函数
  Vue,
  bisDomains: ["dev-myheart.ssv.tencent.com"],
  errCodes: [
    {
      codeKey: "errcode",
      errCode: 0
    }
  ],
})
App.mpType = 'app'
const app = new Vue({
  ...App
})
app.$mount()
js

## 配置说明

### options.reportRequestData

数据类型:`boolean`

是否在命中业务错误时,将请求中的 Body 数据上报到微信实时日志平台。开启后,可以通过对业务接口的请求参数与返回结果,快速判断生产环境的问题。

### options.bisDomains

数据类型:`string[]`

业务白名单,只有命中该白名单的才会触发网络日志上报。

```js
Anim.use(LoggerPlugin, {
  bisDomains: ["https://example.com"]
})

options.errCodes

数据类型:{codeKey: string, errCode: string|number}[]

配置符合规范的接口规范,如果不符合错误码规则则会被当成错误日志进行上报。接口已经默认支持 API3.0 的业务上报规则。

js
Anim.use(LoggerPlugin, {
  // 示例解释:错误码为 0 时或者 200 时上报。具体字段根据实际业务来确定。
  errCodes: [
    {
      codeKey: "errcode",
      errCode: 0
    },
    {
      codeKey: "code",
      errCode: "200"
    },
    {
      codeKey: 'data.errcode', // 支持多层级
      errCode: 0
    },
    {
      codeKey: 'code',
      errCode: [0, 1, 2, -1001] // 支持多个错误码
    }
  ]
})

options.restfulApis

数据类型:stirng[]

支持统一的聚合接口配置,可以节省很大的配置量

js
Anim.use(LoggerPlugin, {
  "restfulApis": [
    "/authentication/realname-aut/v1/"
  ]
})

重要!restful 接口聚合说明重要!restful 接口聚合说明重要!restful 接口聚合说明 如果后端接口是拼接了用户参数的,为了避免上报上千万个不同 URL ,可以通过配置 restfulApis 参数,将多个接口聚合成一个。

options.Vue

数据类型:Vue Consturctor

对于 uniapp/Taro 等第三方框架,我们依然可以使用该插件,但是当他们的运行框架是 Vue 的时候,需要传入 Vue 构造函数,以便我们能够正确的获取到 Vue 的实例。

js
// main.js
import Vue from 'vue'

// uniapp 项目中需要传入 Vue 构造函数
Anim.use(LoggerPlugin, {
  Vue: Vue,
  bisDomains: ["digital.ssv.tencent.com"],
  errCodes: [
    {
      codeKey: "errcode",
      errCode: 0
    }
  ],
})

使用说明

1. 本地日志

如果用户有反馈过问题,可通过小程序管理后台 - 管理 - 用户反馈 选择对应用户的日志进行下载

image-20220607204139293image-20220520162539239

做到「用户行为回溯」,即查看用户去了哪些页面,点击了哪些按钮,并且有哪些请求是有异常。

2. 实时日志

未反馈过问题的用户,可通过小程序管理后台 - 开发 - 开发管理 根据用户的微信号或者 OpenId 进行实时查询

image-20220520115716492

上报事件和内容

上报事件上报标签线上实时日志本地日志(反馈后上传)
接口请求失败(超时)RequestFail
接口请求异常(CDN 配置,业务域名)RequestHttpException
RequestBusinessException
内存告警MemoryWarning
初始化设备信息ReportSystemInfo
JS 代码错误Error
JS 未处理 Promise 拒绝事件Reject
页面跳转Route
点击事件Tap
主动上报错误事件BusinessError

1. 接口请求失败

触发时机:当 wx.request 走到 fail 回调函数时会触发,通常在请求超时的时候触发

上报标签:RequestFail

上报内容:

js
{
  // 发起请求参数的信息
  "request": {
    "url": "https://example.com/ebus/photo/v3"
  },
  // 请求失败返回的错误信息
  "error": { "errno": 5, "errMsg": "request:fail timeout" },
  // 用户当前的网络情况
  "networkInfo": {
    "networkType": "wifi",
    "signalStrength": -100
  }
}

2. 接口请求异常

触发时机:当 wx.request 返回的「HTTP 状态码」或者「业务状态码」异常的时候触发,由线上 CDN 配置控制

上报标签:RequestHttpException HTTP 状态码,RequestBusinessException 业务状态码

上报内容:

js
{
  "request": { "url": "https://example.com/ebus/photo/v3" },
  "response": {
    "data": {
      "code": "500",
      "message": "fail",
      "data": null
    },
    "statusCode": 500,
    // 当前用户请求网络状态评估
    // https://developers.weixin.qq.com/miniprogram/dev/framework/performance/network.html
    "profile": {
      "domainLookup": 0,
      "connect": 0,
      "SSLconnection": 0,
      "request": 457,
      "response": 0,
      "rtt": 179,
      "estimate_nettype": 5,
      "httpRttEstimate": 581,
      "transportRttEstimate": 55,
      "downstreamThroughputKbpsEstimate": 1961,
      "throughputKbps": 0,
      "peerIP": "10.91.29.118",
      "socketReused": true,
      "sendBytesCount": 568,
      "receivedBytedCount": 635,
      "protocol": "http/1.1"
    }
  },
  "networkInfo": {
    "networkType": "wifi",
    "signalStrength": -100
  }
}

3. 内存告警

触发时机:当触发 wx.onMemoryWarning 监听回调函数时上报

相关文档:https://developers.weixin.qq.com/miniprogram/dev/api/device/memory/wx.onMemoryWarning.html

上报标签:MemoryWarning

上报内容:

js
{
  "level": {
    "level": 15
  },
  "route": "pages/xxx/jiankangma/index",
  "networkInfo": {
    "hasSystemProxy": true,
    "errMsg": "getNetworkType:ok",
    "networkType": "wifi",
    "signalStrength": -100
  }
}

4. 初始化设备信息

触发时机:当触发其他上报事件时上报,小程序从启动到最终被销毁(杀掉进程)期间只上报一次

上报标签:ReportSystemInfo

上报内容:

js
{
  "SDKVersion": "2.24.3",
  "benchmarkLevel": -1,
  "brand": "iPhone",
  "language": "zh_CN",
  "model": "iPhone 12<iPhone13,2>",
  "platform": "ios",
  "system": "iOS 15.4.1",
  "version": "8.0.20"
}

5. JS 代码错误

触发时机:当碰到 JS 代码报错时上报,通过 wx.onError 函数进行监听

上报标签:Error

上报内容:

js
{
  "error": "MiniProgramError\nundefined is not a function (near '...s.forEach...')\nTypeError: undefined is not a function (near '...s.forEach...')\nat forEach (pages/my/index/index.js:489:16)\nat success (utils/rateLimit.js:2192:30)\nat call (miniprogram_npm/aegis-mp-sdk/index.js:17:26336)\nat successHandler (miniprogram_npm/aegis-mp-sdk/index.js:17:27209)\nat (WASubContext.js:2:103485)\nat a (WASubContext.js:2:103689)\nat (WAServiceMainContext.js:2:2360195)\nat AX (WAServiceMainContext.js:2:1958874)\nat success (WAServiceMainContext.js:2:1960580)\nat <api request success callback function>\nat D (WAServiceMainContext.js:2:704105)\nat (WAServiceMainContext.js:2:904657)\nat <NetworkRequest930success callback function>\nat (WAServiceMainContext.js:2:882905)\nat forEach (native code)\nat emit (WAServiceMainContext.js:2:882800)\nat Vd (WAServiceMainContext.js:2:905547)\nat (WAServiceMainContext.js:2:906985)\nat (WAServiceMainContext.js:2:705120)\nat k (WAServiceMainContext.js:2:73065)\nglobal code@",
  "path": "pages/my/index/index"
}

6. JS 未处理 Promise 拒绝事件

触发时机:当碰到 JS 未处理 Promise 拒绝事件时上报,通过 wx.onUnhandledRejection 函数进行监听

上报标签:Reject

上报内容:

js
{
  "reason": "ReferenceError: Can't find variable: sfasdf",
  "path": "pages/xxx/jiankangma/index"
}

7. 页面跳转

触发时机:当用户进行了路由页面跳转时上报

上报标签:Route

上报内容:

js
{ 
  "openType": "redirectTo", 
  "path": "pages/xxx/jiankangma/index"
}

8. 点击事件

触发时机:当用户触发了点击事件时上报

上报标签:Tap

相关文档:https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html#事件对象

上报内容:

js
{
  "type": "tap",
  "timeStamp": 795451,
  "target": { "id": "", "offsetLeft": 116, "offsetTop": 152, "dataset": {} },
  "currentTarget": { "id": "", "offsetLeft": 0, "offsetTop": 0, "dataset": {} },
  "mark": {},
  "detail": { "x": 120, "y": 167 },
  "touches": [
    {
      "identifier": 996689290,
      "pageX": 120,
      "pageY": 167,
      "clientX": 120,
      "clientY": 167,
      "force": 0
    }
  ],
  "mut": false,
  "_userTap": true
}

其他用法

1. 手动上报错误日志 reportError

可使用 Anim.$logger.reportError(err) 上报错误日志,示例如下:

js
import Anim from '@ssv-lab/anim'

request({
  url: 'https://mock.cc/api'
})
.then(res => {
  // ... 业务逻辑代码
})
.catch(err => {
  // ... 错误逻辑代码
  Anim.$logger.reportError(err)
})

上报后,在实时日志上可根据 BusinessError 标签来筛选手动上报的错误日志

image-20220524170357330

2. 日志实例

可使用 Anim.$logger.localLog 上报「本地」日志,示例如下:

js
import Anim from '@ssv-lab/anim'
// 如果你挂载到了全局可以使用这种方式
// const rateLimit = getApp().rateLimit

Page({
  onLoad() {
    const localLog = Anim.$logger.localLog
    localLog.log('log log log')
    localLog.info('hello test hahaha')
    localLog.warn('warn')
    localLog.error('error')
  }
})

可使用 rateLimit.ReportErrorLog.realtimeLog 上报「实时」日志,示例如下:

js
import Anim from '@ssv-lab/anim'

Page({
  onLoad() {
    const realtimeLog = Anim.$logger.realtimeLog
    realtimeLog.info('hello test hahaha')
    realtimeLog.warn('warn')
    realtimeLog.error('error')
    realtimeLog.setFilterMsg('filterkeyword')
    realtimeLog.addFilterMsg('addfilterkeyword')
  }
})

信息安全说明

前端日志 SDK 主要上报用户在使用小程序遇到错误的情况下的第三方平台 API 请求信息,目的是为了帮助第三方开发者快速排查缺陷原因,快速修复线上问题。

不会上报请求时用户的输入参数,且错误时请求响应内容也仅包含错误的请求信息,不涉及用户个人信息。

存储上报信息的平台是微信小程序官方的管理后台,没有单独平台另存用户信息,因此不会对用户造成不良影响。

Released under the MIT License.