Post

微信小程序的埋点监控实践

微信小程序的埋点监控实践

埋点监控主要的场景

在小程序开发中,埋点监控可以帮助我们回答以下问题:

  • 用户最常访问哪些页面?
  • 某个按钮的点击率如何?
  • 网络请求的成功率和耗时是多少?

设计思路

我们的目标是创建一个可复用的埋点工具,具有以下功能:

  1. 生命周期监控:自动记录 App、Page 和 Component 的生命周期事件。
  2. 网络请求统计:捕获请求的耗时和状态。
  3. 手动埋点:支持开发者自定义事件。
  4. 数据上报:将采集的数据发送到服务器。

实现步骤

1. 创建埋点工具

新建一个文件 wx-monitor.js,作为埋点监控的核心模块。以下是基本结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// wx-monitor.js
const Monitor = {
  config: function(options) {
    this.key = options.key; // 用于身份验证
    this.id = options.id;   // 小程序标识
    this.serverUrl = 'https://your-server.com/track'; // 上报地址
  },

  // 上报数据
  report: function(eventName, data) {
    wx.request({
      url: this.serverUrl,
      method: 'POST',
      data: {
        key: this.key,
        id: this.id,
        event: eventName,
        data: data,
        timestamp: Date.now()
      }
    });
  },

  // 手动埋点
  track: function(eventName, params) {
    this.report(eventName, params);
  }
};

module.exports = Monitor;

2. 生命周期埋点

微信小程序提供了 App、Page 和 Component 三种对象的生命周期,我们可以通过封装这些对象来实现自动埋点。

(1) App 生命周期

app.js 中引入并注册埋点工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app.js
const monitor = require('./wx-monitor.js');

monitor.config({
  key: 'your-api-key',
  id: 'your-app-id'
});

App(monitor.hookApp({
  onLaunch: function(options) {
    console.log('App launched');
  },
  onShow: function(options) {
    console.log('App shown');
  }
}));

wx-monitor.js 中添加 hookApp 方法:

1
2
3
4
5
6
7
8
9
10
11
12
// wx-monitor.js
Monitor.hookApp = function(appObj) {
  const lifecycleHooks = ['onLaunch', 'onShow', 'onHide', 'onError'];
  lifecycleHooks.forEach(hook => {
    const original = appObj[hook];
    appObj[hook] = function(...args) {
      Monitor.report(`App_${hook}`, { args });
      if (original) original.apply(this, args);
    };
  });
  return appObj;
};

(2) Page 生命周期

在页面文件中使用:

1
2
3
4
5
6
7
8
9
10
11
// pages/index/index.js
const monitor = require('../../wx-monitor.js');

Page(monitor.hookPage({
  onLoad: function(options) {
    console.log('Page loaded');
  },
  onShow: function() {
    console.log('Page shown');
  }
}));

wx-monitor.js 中实现 hookPage

1
2
3
4
5
6
7
8
9
10
11
12
// wx-monitor.js
Monitor.hookPage = function(pageObj) {
  const lifecycleHooks = ['onLoad', 'onShow', 'onHide', 'onUnload', 'onReady'];
  lifecycleHooks.forEach(hook => {
    const original = pageObj[hook];
    pageObj[hook] = function(...args) {
      Monitor.report(`Page_${hook}`, { page: this.route, args });
      if (original) original.apply(this, args);
    };
  });
  return pageObj;
};

(3) Component 生命周期

对于自定义组件:

1
2
3
4
5
6
7
8
9
10
// components/my-component/my-component.js
const monitor = require('../../wx-monitor.js');

Component(monitor.hookComponent({
  lifetimes: {
    attached: function() {
      console.log('Component attached');
    }
  }
}));

wx-monitor.js 中实现 hookComponent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// wx-monitor.js
Monitor.hookComponent = function(componentObj) {
  const lifecycleHooks = ['created', 'attached', 'ready', 'detached'];
  const lifetimes = componentObj.lifetimes || {};
  lifecycleHooks.forEach(hook => {
    const original = lifetimes[hook] || componentObj[hook];
    lifetimes[hook] = function(...args) {
      Monitor.report(`Component_${hook}`, { args });
      if (original) original.apply(this, args);
    };
  });
  componentObj.lifetimes = lifetimes;
  return componentObj;
};

3. 网络请求统计

监控网络请求的性能,封装 wx.request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// wx-monitor.js
Monitor.request = function(options) {
  const startTime = Date.now();
  const originalSuccess = options.success;
  const originalFail = options.fail;

  options.success = function(res) {
    const duration = Date.now() - startTime;
    Monitor.report('NetworkRequest', {
      url: options.url,
      status: res.statusCode,
      duration: duration
    });
    if (originalSuccess) originalSuccess(res);
  };

  options.fail = function(err) {
    const duration = Date.now() - startTime;
    Monitor.report('NetworkRequest', {
      url: options.url,
      error: err.errMsg,
      duration: duration
    });
    if (originalFail) originalFail(err);
  };

  wx.request(options);
};

使用示例:

1
2
3
4
5
6
7
8
9
10
11
12
// pages/index/index.js
const monitor = require('../../wx-monitor.js');

monitor.request({
  url: 'https://api.example.com/data',
  success: function(res) {
    console.log('Request succeeded:', res);
  },
  fail: function(err) {
    console.log('Request failed:', err);
  }
});

4. 数据缓存与优化

为了避免网络不佳时丢失数据,可以将事件暂存到 wx.setStorageSync 中,待网络恢复时批量上报。

使用示例

完整的小程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// app.js
const monitor = require('./wx-monitor.js');
monitor.config({
  key: 'your-api-key',
  id: 'your-app-id'
});
App(monitor.hookApp({
  onLaunch: function() {}
}));

// pages/index/index.js
const monitor = require('../../wx-monitor.js');
Page(monitor.hookPage({
  onLoad: function() {
    monitor.request({ url: 'https://api.example.com/data' });
  }
}));
This post is licensed under CC BY 4.0 by the author.