The Realization of Data Statistics and Error Statistics of Wechat Small Program

Keywords: Javascript network github Google Mobile

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:

  1. Replace methods, attributes, etc. at runtime
  2. Adding previously unsupported functionality without modifying third-party code
  3. 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.~~

Posted by websesame on Tue, 25 Jun 2019 10:04:32 -0700