In some cases, we need to count the behavior of some users of the applet, such as the UV of a page.
PV, etc., statistics of the use of a function, etc. So that the product can understand the whole function of the product.
In the website, many of us have used Google statistics. There are also some third-party databases in the applet, such as Tencent's MTA and so on.
However, third-party statistical databases are either too simple to meet the needs, or they are charged. (leaving tears of poverty.)
Wait a minute. It's not your money. What are you afraid of? It's more expensive.
Well, that's right. However, the company team wants to achieve a complete set of its own data statistics system to meet its own needs. So, there is no third party.
So, what are the specific statistics?
product manager
- Want to know how users get into our applets?
- Which page does the user spend the longest time in our applet? What is the average user stay time?
- How many people want to know what function we have recently developed?
- Want to count how many users clicked on some buttons in the applet
Develop Yourself
- It's always hard to reproduce bug s on the client side.
- If only you could know the type of mobile phone the user was using, the version of Wechat, the network environment, page parameters, and error messages when the user made a mistake.
- Want to know how long it takes for our applet to start?
- What is the average response time of the interface on the client side? Which interfaces reported errors?
According to the needs of product managers, we can know that what Ta wants is the function of data statistics. For development, we pay more attention to the performance of error mini-programs.
Okay, here we are, we understand what we need. It is to achieve a set of statistics not only for ordinary buried data, but also for some special triggered events in small programs, such as appLaunch, appHide and so on, as well as errors.
Okay, let's see how to meet the demand of the product first.
Users can get the scene value of the parameters in the onLaunch callback of the applet, so that they can know how the user enters the applet. Small case, it's hard for me.
Well, the first requirement is fulfilled, so how do you count the second? How to count the residence time of a page?
It's also hard for me. Users will trigger onShow events when they enter the page. Similarly, onHide events will trigger when they leave the page (or cut the background). I just need to record the time in onShow, and also in onHide. Just subtract the two times.
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 stays on this page. }, })
Wait a minute. This really fulfills the requirement. In case the product needs to count the length of stay of all the noodles? So don't we just write it this way on every page? Is there a better way?
Okay, next is the main point of data statistics implementation, that is, intercepting the original events of Weixin, so that when a particular event triggers, we can do some statistical things. At the same time, we also need to intercept the method of Wechat network requests, so that we can get the data related to the network requests. Finally, in order to be able to count the errors, we need to intercept the method of Wechat errors.
1. Monitoring of Special Events
App(Object object)
Registration applet. Accept an Object parameter that specifies the life cycle callback of the applet, etc.
App() must be invoked in app.js, and must be invoked only once. Otherwise, there will be unexpected consequences.
- Intercept global events:
- Following is the official widget document 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' })
If we want to print a hello Word in the small program onLaunch, what methods do we have to implement it?
Method 1:
Write it directly in onLaunch method
onLaunch (options) { console.log('hello World') }
Method 2:
Using monkey patch method Monkey patch
The monkey patch is mainly used for the following purposes:
- Replace methods, attributes, etc. at runtime
- Adding previously unsupported functionality without modifying third-party code
- Adding patch es to objects in memory at runtime rather than to disk source code
For example, if we print out 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) }
Similarly, we patched onLaunch with monkeys
var oldAp = App App = function(options) { var oldOnLaunch = options.onLaunch options['onLaunch'] = function(t) { // Do something we want to do ourselves console.log('hello word....') // Call the original onLaunch method oldOnLaunch.call(this, t) } // Call the original App method oldApp(options) // Imagine calling the onLaunch method inside the applet as follows: options.onLaunch(params) } // Question: Sometimes we may not register an event, such as onShow on the page, so we need to decide whether the parameter passed the corresponding method or not when replacing it. Page({ onLoad (options) {}, onHide (options) {} }) // In view of this situation, we need to write like this. var oldPage = Page Page = function(options) { if (options['onShow']) { // If registered onShow callback var oldOnShow = options.onShow // The onShow method calls all pass an object options['onShow'] = function(t) { // doSomething() oldOnShow.call(this, t) } } // Call the original Page method. oldPage.apply(null, [].slice.call(arguments)) // Note: Both of the following writings will report errors: VM23356:1 Options is not object: {"0": {} in pages/Badge.js, the specific cause of the problem has not been found yet. // oldPage.call(null, arguments) // oldPage(arguments) }
Through the above method, we can intercept some global methods of App method registration, such as onLaunch, onShow, onHide, and Page registration events such as onShow, onHide, onLoad, onPullDownRefresh, etc.
2. Monitoring of Network Requests
Idea: Intercept Wechat request events.
let Request = { request: function (e) { let success = e[0].success, fail = e[0].fail, beginTime = smaUtils.getTime(), endTime = 0 // Successful Interception Request 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)) } // Interception request failure 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)) } }, } // Replacement of 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
Question: Why replace the whole 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 } // The result was wrong: // TypeError: Cannot set property request of [object Object] which has only a getter
3. Error monitoring
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 ourselves console.log('Statistical errors....', t) // Call the original onLaunch method oldOnError.call(this, t) } // Call the original App method oldApp(options) }
3.2 Intercept conole.error
console.error = function() { var e = [].slice.call(arguments) if (!e.length) { return true } const currRoute = smaUtils.getPagePath() // Statistical error events // SMA.errorReport({event: eventMap.onError, route: currRoute, errrMsg: arguments[0]}) smaUtils.logInfo('Captured error Event,', e) oldError.apply(console, e) }
So far, we have the ability to do some of the statistical functions we want in the applet when it makes a request, when it makes an error, when it comes to life cycle or when it calls back a special function.
So many people are probably tired of talking about it. Given the length, the specific code is not posted here.
The final data statistics module realizes the following functions roughly:
- Common Buried Point Information Reporting Function
- Error Information Reporting Function
- Performance Data Reporting Function
- Specific reporting timing support configuration
- Support for specified network environment reporting
- Support statistical data caching to Wechat local function
The configuration file of the whole statistical code is as follows:
const wxaConfig = { project: 'myMiniProgram', // entry 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'], // Priority of sending requests, when sent, will be sent in turn useStorage: true, // Whether to turn on storage cache debug: false, // Whether to turn on debugging (display log) autoTrack: true, // Automatically report onShow, onHide, share and other built-in events errorReport: false, // Whether to open error reporting performanceReport: false, // Interface Performance Reporting maxReportNum: 20, // Maximum number of items reported intervalTime: 15, // The time interval of time reporting, unit s, is valid only when the time reporting is turned on. networkList: ['wifi', '4g', '3g'], // Network environment for reporting opportunity: 'pageHide' // Page Hide, appHide, Real Time and Timing are the best time to report. } export default wxaConfig
Specific reporting time, the data structure reported is roughly the same:
The project has been passed to GitHub - >. GitHub Portal-wxa
If this article helps you and feels good, order a Star.
How do you implement small program data statistics? Welcome to leave a message in the comments.~~