【数据可视化之采集】如何设计一个后端监控系统

优采云 发布时间: 2020-08-09 17:36

  ④ 页面逗留时间(web不一定确切)

  ⑤ 前端错误日志(这个比较庞大,后面阐述)

  ⑥ 首屏载入速率

  ⑦ 用户环境搜集(一般来说这个是附送的)

  ⑧ 跨域资源检测(监测所有非白名单脚本,发现脚本注入行为,附件特点)

  而由于现今一套H5代码会用于不同的平台入口,所以这种数据又会额外具有“渠道信息”的标志。

  再我们有了以上数据的情况下,我们能挺轻易的得出某个渠道的转化率:

  因为不同渠道表现或许会有所不同,有可能陌陌渠道的入口在首页,他的转化率估算通常会经过那么一个过程:

  首页pv -> 列表页pv -> 订单填写页pv -> 下单按键点击pv -> server最终成双数

  而搜索引擎入口,可能直接就到了订单填写页,所以转化率估算公式又弄成了:

  订单填写页pv -> 下单按键点击pv-> server最终成双数

  这里结合首屏载入速率与页面逗留时间,辅以用户点击轨迹,就能从个别程度上,追踪剖析一个用户的行为了。

  曾今有一次我们发觉我们订单转化率增长了50%,于是老总使我们马上给出缘由,我们当时怀疑过BUG,怀疑过运营商插口有问题,但是我们所有的结论都没有挺好的旁证,于是各类查询数据库,最后与整个打点的pv数据,我们便得出了一个推论:

  因为,多数用户的优惠券过期了,所以转化率大幅增长!!!

  为了证明这个推测,我们由将某一个渠道的优惠券加上,第二天转化率就回归了,我们这儿能判定出转化率增长的缘由和我们平常建立的打点是息息相关的。

  错误日志

  另一方面,当代码迭代到一定量的时侯,code review也就只能解决太小一部分问题了,前端预警和后端错误日志形成的蛛丝马迹就会将一些隐藏的太深的BUG揪下来,所有的这一切都须要从数据采集开始。

  我原先也碰到一个BUG,潜伏期太长,而且只有在特定的场景才能触发,这种BUG一般来说测试是无力的,当时我发觉2个版本的日志有些奇怪的错误,再一步步抽丝剥茧,终于定位到了那种错误,当我们代码量大了后,合理的错误埋点+前端监控能够使系统显得更健康。

  这里引用一张错误监控图():

  

  

  这里将上一周的错误数与本周做对比,如果没有大的迭代,稍微有异常都会形成报案,一般来说用户才是最好的测试,上线后没有报案就没有BUG。

  PS:原来我们每次大版本发布,60%的概率要回滚......

  错误捕捉

  前端错误捕捉,一般使用onerror,这个时常会被try cache影响:

  1 window.onerror = function (msg, url, line, col, error) {

2 //......

3 }

  当时生产上的错误日志由于是压缩过的,真实抓到的错误信息非常难看:

  

  错误信息全部是第一行,报错的地方也是做过混淆的,如果不是页面界定的过开,这个错误会使人一头雾水,要想深入了解错误信息,这里便可以了解下source map了

  sourcemap

  简单来说,sourcemap是一个信息文件,里面储存着位置信息,也就是说,在js代码压缩混淆合并后的每位代码位置,对应的源码行列都是有标志的,有了这个source map,我们能够直接将源码对应的错误上报回来,大大增加我们的错误定位成本。

  这里不同的业务使用的不同的建立工具,这里以grunt为例,grunt打包一般来说是使用的require,这里须要为其配置加入一段代码即可:

  1 "generateSourceMaps": true,

2 "preserveLicenseComments": false,

3 "optimize": "uglify2",

  

  上面那种有一些问题,他将我的关键字过滤了,最后采用的这个:

  

  然后还会生成你要的sourcemap了

  

  可以听到压缩文件中,收录了map引用:

  

  于是我们线上代码才会弄成这个样子:

  

  这个时侯,我们故意写个错误的话,这里查看报错:

  

  虽然听到的是源码,但是上报的数据虽然没有哪些意义,这个时侯可以利用一些第三方工具对日志做二次解析:

  Sentry(GitHub - getsentry/sentry: Sentry is cross-platform crash reporting built with love)

  并且,显然我们并不希望我们的源代码被人看见,所以我们将sourcemap文件存到线下,在线下将日志反应为我们看得懂的源码,这里简单瞧瞧这个文件定义:

  1 - version:Source map的版本,目前为3。

2 - file:转换后的文件名。

3 - sourceRoot:转换前的文件所在的目录。如果与转换前的文件在同一目录,该项为空。

4 - sources:转换前的文件。该项是一个数组,表示可能存在多个文件合并。

5 - names:转换前的所有变量名和属性名。

6 - mappings:记录位置信息的字符串。

  线下翻译

  sourcemap的机制哪些的,就不是我关注的重点,想了解的可以看,我如今的需求是:

  获取了列号和行,如何可以在线下映射成我们要的真实行号

  比如我们领到了上述的行号与列号为{1,13310},那么我们这儿真实映射的是,合并文件中的某一行:

  

  要完成这一切,我们须要一套“错误还原”的后台系统,这个直接坐到js监控其中一环就好,比如我们可以简单这样做:

  

  这个被一美国网站实现了(一般来说要钱的......),所以是可以实现的,我们便去找寻他的实现即可。

  后续在github找了一个库,完成了类似的功能,这里使用nodejs:

  1 var mapData = require('./index.json');

2 // console.log(sourceMap);

3 var sourceMap = require('source-map');

4 var consumer = new sourceMap.SourceMapConsumer(mapData);

5 var numInfo = consumer.originalPositionFor({ line: 1, column: 13330 })

6 console.log(numInfo)

  输出==>

  1 { source: 'pages/index/index.js',

2 line: 182,

3 column: 0,

4 name: 'layoutHtml' }

  于是,我们早已找到了自己要的东西了。最初,在快速督查的时侯,我们不要晓得是干哪些的,但是假如我们决定使用的话,就须要去仔细研究一番了。

  总而言之,线上错误日志搜集的行号信息,在线下平台便能很好的翻译了,这里方案有了,我接下来马上想法落地,落地情况在存储篇反馈

  错误日志这儿,因为比较重要,也与普通的打点不一样,占的篇幅有点长,我们这儿先继续往下说,等日志简单落地后再简述。

  采集系统

  本来,我们数据采集可以使用百度或则友盟,但是总有这么一些东西得不到满足,而且也没有数据对外输出的API,而公司假如逐步上升的话,做这块是迟早的事情,所以宜早不宜迟吧,而我这儿主要还是先关注的联通体系,所以不太会关注兼容性,这个可以少考虑一些东西,真的遇见一些情况如跨域哪些的,我们前面再说吧。

  关于储存一块有很多须要考虑,比如怎么估算首屏加载时间,webapp和传统网易的优缺,hybrid的差别,uv的估算方式等都须要考虑,但是我们明天变只将采集代码实现即可,剩下的上篇再处理。

  简单来讲,日志采集,其实就是一个get恳求,你即便想用ajax发出去也是没有问题的,为了加入额外信息可能我们会做一个收口:

  1 ajax(url, {

2 s: ''

3 b: ''

4 c: ''

5 });

  但是这个不是主流的做法,一般来说,我们打点信息使用的图片的形式发出,而由于重复的恳求会被浏览器忽视,我们甚至会加入uniqueId做标志:

  1 var log = function () {

2 var img = new Image();

3 img.src = 'http://domain.com/bi/event?'+ uniqueId;

4 };

  基本的采集实现就如此简单,但是后续逐渐建立的功能,会降低复杂度,于是我构建了一个git库房储存代码,后续大数据一块的代码也将放在这儿:

  闭门造车的意义不大,翻看高手的一些采集代码例如alog,会发觉他打点的一块是这样做的:

   1 /**

2 * 上报数据

3 *

4 * @param {string} url 目标链接

5 * @param {Object} data 上报数据

6 */

7 function report(url, data) {

8 if (!url || !data) {

9 return;

10 }

11 // @see http://jsperf.com/new-image-vs-createelement-img

12 var image = doc.createElement('img');

13 var items = [];

14 for (var key in data) {

15 if (data[key]) {

16 items.push(key + '=' + encodeURIComponent(data[key]));

17 }

18 }

19 var name = 'img_' + (+new Date());

20 entry[name] = image;

21 image.onload = image.onerror = function () {

22 entry[name] =

23 image =

24 image.onload =

25 image.onerror = null;

26 delete entry[name];

27 };

28 image.src = url + (url.indexOf('?') < 0 ? '?' : '&') + items.join('&');

29 }

  其中有一块差别是绑定了onload等风波,应该是想释放资源吧?

  这里的代码,想与公司业务管理上去,比如按照业务线或则项目生成某个规则的id,上报代码比较简单,但是每次都要带什么信息,还没挺好的思路,先在这里立一个flag吧,接下来时间里竭力补齐吧,毕竟这块东西好多。

  结语

  前端数据有很多须要处理的地方,而数据的核心分为数据采集打点,数据持久化,数据使用,数据剖析。

  打点又会分辨H5打点与native打点,native因为权限本身,能做的事情更多,但是底层数据搜集基本能做到统一。

  采集的代码是其中一部分,但采集的各项数据获取是另一个更重要的部份,会收录数据设计,各种细节处理,我们上篇文章接着研究,有兴趣的朋友可关注。

  代码地址:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线