In some cases we need to small program some user behavior data statistics, such as statistics of a page UV, PV, statistics of the use of a function and so on. So that the product can understand the whole function of the product. In the webpage, many of us have used Google statistics, there are also some third-party data statistics library in the small program, such as Tencent’S MTA and so on. However, third-party databases are either too simple to meet the needs, or they are charged. (Tears of poverty.) Wait, you’re not paying for it. What are you afraid of? A little more expensive, just a little more expensive.
Yeah, you’re right. However, the company team internally wants to achieve a complete set of their own data statistics system to meet their own needs. So, there’s no third party.
So, what are the statistics?
The product manager
- Want to know how users get into our applet?
- Which page in our applet does the user spend the most time on? What is the average user stay time?
- Do you want to know how many people are using the feature we recently developed?
- Want to count how many users click some buttons in the applet
To develop its
- It’s always hard to reproduce client-side bugs,
- It would be nice to know the user’s phone model, wechat version, network environment, page parameters, and error messages when errors occur on the user side
- Want to know our small program start time is how many?
- What is the average response time of the interface on the user side ms? Which interfaces report errors
According to the needs of product managers, we can know that what they want is the function to be realized by data statistics. For development, we focus more on the performance of the error system applet.
Ok, so at this point, we get the point. The goal is to achieve a set of statistics not only ordinary buried data, but also to be able to count small programs in some special triggered events, such as appLaunch, appHide, etc., but also can count errors.
Ok, let’s see how to fulfill the product requirements first
When entering the applet, the user can get the scene value of the parameter in the applet onLaunch callback. This will show how the user entered the applet. Little case, it’s hard for me.
Well, the first requirement is implemented, but how about the second one? How do you count the time spent on a page?
The onShow event is triggered when the user enters the page, and the onHide event is triggered when the user leaves the page (or cuts the background). All I need to do is record the time in the onShow and the time in the onHide.
Page({
data: {
beginTime: 0.endTime: 0
},
onShow: function() {
// Do something when page show.
this.setData({
beginTime: new Date().getTime()
})
},
onHide: function() {
// Do something when page hide.
let stayTime = new Date().getTime() - this.beginTime;
// This is how long the user has been on the page}})Copy the code
Wait, this does fulfill the requirement, what if the product has to count the length of time spent on all of them? Why don’t we do that on every page? Is there a better way?
Well, the next is the key point of data statistics implementation, that is, the interception of wechat native events, so that we can do some statistical things when a special event is triggered. At the same time, we also need to intercept the method of wechat network request, so that we can get the data related to network request. Finally, in order to count the errors, we also need to intercept the method of wechat error.
1. Monitoring of special events
App(Object object)
Register applets. Accepts an Object parameter that specifies the life cycle callback of the applet, etc.
App() must be called in app.js, and must be called only once. Or there will be unintended consequences.
- Intercepting global events:
- The following is the official documentation for the App registration method:
App({
onLaunch (options) {
// Do something initial when launch.
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
},
globalData: 'I am global data'
})
Copy the code
If we want to print a hello Word in onLaunch, what methods can we implement it?
Method 1:
Write it directly in the onLaunch method
onLaunch (options) {
console.log('hello World')}Copy the code
Method 2:
Using the Monkey Patch method
Monkey patches are mainly used for the following purposes:
- Replace methods, properties, and so on at run time
- Add functionality not previously supported without modifying third party code
- Add patches to objects in memory at run time rather than in disk source code
For example, if we first print the current timestamp in the console.log method, we can do this:
var oldLog = console.log
console.log = function() {
oldLog.call(this.new Date().getTime())
oldLog.apply(this.arguments)}Copy the code
Similarly, we did a monkey patch for onLaunch
var oldAp = App
App = function(options) {
var oldOnLaunch = options.onLaunch
options['onLaunch'] = function(t) {
// Do something we want to do
console.log('hello word.... ')
// Call the original onLaunch method
oldOnLaunch.call(this, t)
}
// Call the old App method
oldApp(options)
// Imagine an applet calling the onLaunch method internally like this:
options.onLaunch(params)
}
// Problem, sometimes, we may not register an event, such as the page onShow, so we need to check whether the parameter is passed the corresponding method when replacing
Page({
onLoad (options) {},
onHide (options) {}
})
// In this case, we need to write this
var oldPage = Page
Page = function(options) {
if (options['onShow']) {
// The onShow callback is registered
var oldOnShow = options.onShow
// the onShow method is called with an object
options['onShow'] = function(t) {
// doSomething()
oldOnShow.call(this, t)
}
}
// Call the original Page method.
oldPage.apply(null, [].slice.call(arguments))
Vm23356:1 Options is not object: {"0":{}} in pages/ badge.js
// oldPage.call(null, arguments)
// oldPage(arguments)
}
Copy the code
Using the above method, we can block some global methods registered by App methods, such as onLaunch, onShow, onHide, and Page registered events such as onShow, onHide, OnLoad, onPullDownRefresh, and other page registration events.
2. Network request monitoring
Interception of wechat request events.
let Request = {
request: function (e) {
let success = e[0].success,
fail = e[0].fail,
beginTime = smaUtils.getTime(),
endTime = 0
// Intercept the request success method
e[0].success = function () {
endTime = smaUtils.getTime()
const performance = {
type: constMap.performance,
event: eventMap.wxRequest,
url: e[0].url,
status: arguments[0].statusCode,
begin: beginTime,
end: endTime,
total: endTime - beginTime
}
smaUtils.logInfo('success performance:', performance)
// Do the reporting here
// SMA.performanceReport(performance)
success && success.apply(this, [].slice.call(arguments))}// Intercepting the request failed method
e[0].fail = function () {
endTime = smaUtils.getTime()
const performance = {
type: constMap.performance,
event: eventMap.wxRequest,
url: e[0].url,
status: arguments[0].statusCode,
begin: beginTime,
end: endTime,
total: endTime - beginTime
}
smaUtils.logInfo('fail performance:', performance)
// Do the reporting here
// SMA.performanceReport(performance)
fail && fail.apply(this, [].slice.call(arguments))}}}// Replace wechat related attributes
let oldWx = wx,
newWx = {}
for (var p in wx) {
if (Request[p]) {
let p2 = p.toString()
newWx[p2] = function () {
Request[p2](arguments)
// Call the original wx.request method
oldWx[p2].apply(oldWx, [].slice.call(arguments))}}else {
newWx[p] = oldWx[p]
}
}
// eslint-disable-next-line
wx = newWx
Copy the code
Confused: Why replace the entire WX object? Do not directly replace the wx.request method with our request method
var oldRequest = wx.request
wx.request = function(e) {
// doSomething();
console.log('Request interception operation... ')
oldRequest.call(this, e); // Call the old request method
}
// Error:
// TypeError: Cannot set property request of [object Object] which has only a getter
Copy the code
3. Wrong listening
3.1 Intercept onError events registered in App
var oldAp = App
App = function(options) {
var oldOnError = options.onErrr
options['onErrr'] = function(t) {
// Do something we want to do
console.log('Statistical error.... ', t)
// Call the original onLaunch method
oldOnError.call(this, t)
}
// Call the old App method
oldApp(options)
}
Copy the code
3.2 interceptor conole. Error
console.error = function() {
var e = [].slice.call(arguments)
if(! e.length) {return true }
const currRoute = smaUtils.getPagePath()
// Statistics error event
// SMA.errorReport({event: eventMap.onError, route: currRoute, errrMsg: arguments[0]})
smaUtils.logInfo('Error event caught,', e)
oldError.apply(console, e)
}
Copy the code
At this point, we have the ability to do whatever statistics we want in the applet whenever a request is made, when an error occurs, during the lifecycle, or when a special function is called back.
You’re probably tired of all this talking. Due to space, the specific code is not posted here.
The final data statistics module roughly realizes the following functions:
- Common buried point information reporting function
- Error message reporting function
- Report performance data
- The specific reporting time can be configured
- Supports reporting in a specified network environment
- Support statistics cache to wechat local function
The configuration file for the entire statistical code is as follows:
const wxaConfig = {
project: 'myMiniProgram'.// Project name
trackUrl: 'https://youhost.com/batch'.// Background data statistics interface
errorUrl: 'https://youhost.com/batch'.// Background error reporting interface
performanceUrl: 'https://youhost.com/batch'.// Background performance reporting interface
version: '0.1'.prefix: '_wxa_'.priority: ['track'.'performance'.'error'].// The priority of the request to be sent
useStorage: true.// Whether to enable storage cache
debug: false.// Whether to enable debugging (display log)
autoTrack: true.// Automatic reporting of onShow, onHide, share and other built-in events
errorReport: false.// Whether to enable error reporting
performanceReport: false.// Interface performance report
maxReportNum: 20.// Maximum number of entries to be reported at a time
intervalTime: 15.// Interval for periodic reporting, in seconds. This parameter is valid only when periodic reporting is enabled.
networkList: ['wifi'.'4g'.'3g'].// The network environment that can be reported
opportunity: 'pageHide' // pageHide, appHide, realTime, timing Report timing. Select one of the four
}
export default wxaConfig
Copy the code
The data structure to be reported looks like this:
The project is uploaded to GitHub -> GitHub portal – WXA
If this article helps you and you think it’s good, give it a Star
How do you implement applets statistics? Feel free to leave a comment in the comments