hugh 的个人博客

vuePress-theme-reco hugh 的个人博客    2021
hugh 的个人博客

Choose mode

  • dark
  • auto
  • light
Home
分类
  • 前端
  • fe-robot
  • 前端监控
标签
专题
  • femonitor
  • jsby
  • fe-robot
TimeLine
工具
全版

hugh 的个人博客

154

Article

324

Tag

Home
分类
  • 前端
  • fe-robot
  • 前端监控
标签
专题
  • femonitor
  • jsby
  • fe-robot
TimeLine
工具
全版
  • 数据收集篇

    • 收集请求数据集详情-前端监控之数据采集篇
      • 第一,我们先要清楚,对于请求,我们通常需要哪些信息
      • 第二,对于这些数据,我们又用来做些什么
      • 第三, 注意点
    • 收集错误信息及堆栈-前端监控之数据收集篇
      • 1. 了解异常发生的情况和影响
      • 2. 了解 js 中异常抛出的内容
      • 3. 收集跨域异常信息
      • 4. 错误捕获上报
      • 5. 框架类异常收集
    • 收集资源加载错误
      • 资源类型
      • 如何监控
    • 前端日志打印收集-前端监控之数据收集篇
      • 问题主要分为以下几种
      • 什么是前端日志
      • 如何记录前端日志
    • 如何保证页面卸载时的上报数据完整性
      • 1. 使用异步 xhr
      • 2. 异步不好使,试试同步 xhr
      • 3. 杀手锏 sendBeacon
      • 4. 如果不追求时效性, 自然是使用缓存 + 延时发送的策略最优雅, 同时丢失数据的问题也可以大大改善
    • CPS报告收集-前端监控
      • csp
      • CSP 报告
      • 使用
  • 数据分析篇

  • 数据监控篇

  • 采坑篇

前端日志打印收集_-_前端监控之数据收集篇

vuePress-theme-reco hugh 的个人博客    2021

前端日志打印收集-前端监控之数据收集篇


hugh 的个人博客 2019-08-07 15:30:44 前端web日志fe_monitor

日志,一般大家听到的都是后台的日志概念。

前端由于其特殊性,console 输出的我们认为是控制台调试信息

很多时候本地开发,我们定位问题还是需要 debug 模式进行逐行定位,但是当线上问题发生时,我们并不具备远程 debug 的能力或条件,那么如何进行快速问题定位呢?

# 问题主要分为以下几种

  1. 由 js 错误引发,这种可以通过 js 堆栈还原 解决大部分问题

  2. 由于后台服务异常导致的, 这种可以通过数据分析请求 解决问题

  3. 还有一些可能是由于用户操作的原因,并没有明确的异常发生, 这时候就需要通过日志的方式记录关键节点的操作

# 什么是前端日志

日志至少应该具备以下几个要素

# ①. 分级别

日志,是我们用于输出系统消息的一些节点, 但是由于业务、编码优先级的不同,日志需要通过定义不同的基本来进行输出

Chrome 上可以看到对级别做了几个划分

在 console 的 API 中,我们可以将类别划分成一下

# ②. 多种记录方式

开发时: 我们使用 console 输出,便于调试

测试时:一般可以关闭输出

生产时:应该需要输出到服务端,用于定位

# ③. 输出级别

可第一点的级别不同,输出级别用于我们对日志的输出做更详细的控制

生产时:我们通常只需要输出级别较高的日志, 这时候我们会发现上表中的级别并不够用,这时候我们可以对输出级别在进行划分

# ④. 控制开关

用于控制日志的开启关闭

# 如何记录前端日志

# 1. 通过自定义代理

 function wrapConsole(console, level, callback) {
	var originalConsoleLevel = console[level];
	var originalConsole = console;
	
	
	if (!(level in console)) {
	    return;
	}
	
	console[level] = function() {
	    var args = [].slice.call(arguments);
	
	    var msg = '' + args.join(' ');
	    var data = {level: level, extra: {arguments: args}};
	
	    if (level === 'assert') {
	        if (args[0] === false) {
	            msg = 'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert');
	            data.extra.arguments = args.slice(1);
	            callback && callback(level,msg, data);
	        }
	    } else {
	        callback && callback(level,msg, data);
	    }
	
	    if (originalConsoleLevel) {
	   	 Function.prototype.apply.call(originalConsoleLevel, originalConsole, args);
	    }
	};
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

** 或者使用 proxy**

function warpConsole(console, level, callback) {
	let handler = {
		apply (target, ctx, arg) {
			var args = [].slice.call(arg);
			
			
			    var msg = '' + args.join(' ');
			    var data = {level: level, extra: {arguments: args}};
			
			    if (level === 'assert') {
			        if (args[0] === false) {
			            msg = 'Assertion failed: ' + (args.slice(1).join(' ') || 'console.assert');
			            data.extra.arguments = args.slice(1);
			            callback && callback(level,msg, data);
			        }
			    } else {
			        callback && callback(level,msg, data);
			    }
			   return Reflect.apply(...arguments);
			}
		};
	console[level] = new Proxy(console[level], handler)
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 2. 加入分级管理

首先定义级别

const levelMap = {trace: 5, log:5, dir:5, debug: 10, info: 15, warn: 25, error: 30, fatal: 40}

1
2

定义控制开关

this.consoleSettings= utils.objectMerge({
	clientOn: false,
	serverOn: false,
	level: "error"
}, options.console || {})

1
2
3
4
5
6

代码中加入控制点

在 warpConsole 中回调源方法处加入级别和开关判断

let limitLevel = levelMap[reporter.consoleSettings.level] || 0
if(reporter.consoleSettings.clientOn && levelMap[level] >= limitLevel ) {
// 回调源方法
}

1
2
3
4
5

在发送到服务端的方法中同样加入开关

var consoleMethodCallback = function(level, msg, data) {
	let limitLevel = levelMap[reporter.consoleSettings.level] || 0
	if(reporter.consoleSettings.serverOn && levelMap[level] >= limitLevel ) {
		if(data.extra) {
			try {
				data.extra = JSON.stringify(data.extra)
			}catch(e){
				data.extra = JSON.stringify({arguments: msg})
			}
		}
		var session = reporter._getSessionId();
		data.m_uuid = session.sid;
		               // 发送到服务器
		reporter.captureInfo("console_data", data, {category: "console", filter: "track"})
	}
};


    utils.each(['debug', 'info', 'warn', 'error', 'log'], function(_, level) {
        wrapMethod(console, level, consoleMethodCallback);
    });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 3. 数据收集

console 数据只是用于辅助的数据, 建议使用批量发送的方式收集