background
Traditional mode after a front-end project to formal environment, all error message only by users when using screenshots, verbal description sent to developers, and developers to described according to the user scene to simulate the generation of the error, this must be super low efficiency, so a lot of open source or charge the front-end monitoring platform was born, Our company uses a WebFunny with encrypted code, which cannot be extended twice and can only access the Web Vue version. In this section, we first talk about the monitoring SDK built by wechat small program
Before doing this, I also investigated many other open source SDK and services, but none of them met our company’s requirements:
Monitor SDK: monitor-SDK
Let’s start with JS error collection
How to extend it to SDK? My method is to rewrite -> publish and subscribe to collect errors. Of course, there are many methods, everyone can try
Release subscription
const handlers = {} const appHandles = {} const pageHandles = {} /** * @param {*} handler * @param {*} handleType */ export function subscribeEvent(handler, handleType = '') { if (! handler) { return } switch (handleType) { case 'app': appHandles[handler.type] = appHandles[handler.type] || [] appHandles[handler.type].push(handler.callback) break case 'page': pageHandles[handler.type] = appHandles[handler.type] || [] pageHandles[handler.type].push(handler.callback) break default: handlers[handler.type] = handlers[handler.type] || [] handlers[handler.type].push(handler.callback) } } /** * @param {*} type * @param {*} data * @param {*} handleType */ export function triggerHandlers(type, data, handleType = '') { switch (handleType) { case 'app': if (! type || ! appHandles[type]) return appHandles[type].forEach((callback) => { callback(data) }) break case 'page': if (! type || ! pageHandles[type]) return pageHandles[type].forEach((callback) => { callback(data) }) break default: if (! type || ! handlers[type]) return handlers[type].forEach((callback) => { callback(data) }) } }Copy the code
Overrides a property on an object:
@param {*} source Specifies the object to be overwritten. @param {*} name Specifies the key of the object to be overwritten. @param {*} replacement replaces the original function. * @param {*} isForced */ export function replaceOld(source, name, replacement, isForced = false) { if (name in source || isForced) { const original = source[name] const wrapped = replacement(original) if (typeof wrapped === 'function') { source[name] = wrapped } } }Copy the code
Rewrite the APP:
const HandleWxPageEvents = { onLoad() { let vm = this.wxMonitor, toUrl = util.getPage() let data = { simpleUrl: toUrl, referrer: vm.referrerPage || "", } vm.logSave('page_pv', data) vm.referrerPage = toUrl } } export function replaceApp(wxMonitor) { if (! App) { return } HandleWxAppEvents.wxMonitor = wxMonitor const originApp = App App = function (appOptions) { let methods = config.APP_CONFIG methods.forEach((method) => { addReplaceHandler({ callback: (data) => HandleWxAppEvents[method.replace('AppOn', 'on')](data), type: method }, 'app') replaceOld( appOptions, method.replace('AppOn', 'on'), function (originMethod) { return function (... args) { triggerHandlers.apply(null, [method, ...args, 'app']) if (originMethod) { originMethod.apply(this, args) } } }, true ) }) return originApp(appOptions) } }Copy the code
Of course Page Page home Page PV and collection error is the same, here is not a paste code
How to collect wx.request to count the number of requests, and how long does the request take
Wx. request can use Object.defineProperty to reattach a description to the Object.
WxMonitor */ export function replaceNetwork(wxMonitor) {let vm = wxMonitor let WxHookMethods = config.WxHookMethods WxHookMethods.forEach(hook => { let originRequest = wx[hook]; Object.defineProperty(wx, hook, { writable: true, enumerable: true, configurable: true, value: function () { let args = []; let startTime = new Date().getTime() for (let _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } let options$1 = args[0]; let url = options$1.url || "" let reqData; if (hook === 'request') { reqData = options$1.data; } let successHandler = function (res) {try {if (!! res && res.statusCode && res.statusCode ! = 200) { let data = { simpleUrl: util.getPage(), httpUrl: options$1.url || "", httpUploadType: config.HTTP_ERROR, responseText: JSON.stringify(res), httpStatus: res.statusCode } if (!! url && url ! = `${vm.queue.baseUrl}${vm.queue.api}`) { vm.logSave('http_log', data) } } else { let endTime = new Date().getTime() let consumeData = { simpleUrl: util.getPage(), loadTime: endTime - startTime, httpUrl: options$1.url || "", httpUploadType: config.HTTP_SUCCESS, responseText: JSON.stringify(res), httpStatus: res.statusCode || 200 } if (!! url && url ! = `${vm.queue.baseUrl}${vm.queue.api}`) { vm.logSave('http_log', consumeData) } } } catch (e) { util.warn('[cloudMonitor] http error') } if (typeof options$1.success === 'function') { return options$1.success(res); }}; let failHandler = function (err) { try { let data = { simpleUrl: util.getPage(), httpUrl: options$1.url || "", httpUploadType: config.HTTP_ERROR, responseText: JSON.stringify(err), httpStatus: '0' } if (!! url && url ! = `${vm.queue.baseUrl}${vm.queue.api}`) { vm.logSave('http_log', data) } } catch (e) { util.warn('[cloudMonitor] http error') } if (typeof options$1.fail === 'function') { return options$1.fail(err); }}; let actOptions = util.__assign(util.__assign({}, options$1), { success: successHandler, fail: failHandler }); return originRequest.call(this, actOptions); }})})}Copy the code
Information collection platform display
I’ll talk about server-side scaffolding later in this article
Server-side Web:Github.com/fonitor/web…Server:Github.com/fonitor/web…