前端监控系列,SDK,服务、存储 ,会全部总结一遍,写文不易,点个赞吧
监控的内容我们已经说了很多了,那么我们一般上报一条监控内容都具体包含什么数据呢
今天就来详细列举一下
本文列出的数据会这样说明
1、有什么数据
2、作用是什么
3、怎么获取
我会给每个具体分个类,按分类来逐个说明
数据大概分为下面几类
1、监控点数据
2、用户信息
3、设备信息
4、项目信息
5、日志信息
下面就按这个分类来说明里面包含的详细数据
监控点数据
这个就是每个监控点类型相应的数据,像接口请求信息,静态资源,首屏测速等等
具体可以在相应的文章中查看
1、自动抓取接口请求数据
2、静态资源测速&错误上报
3、页面错误监控
4、单页首屏测速
所以这里就不一一列举了,本文主要是讲一些公共的监控数据
不过这里简单说个接口信息的监控数据
cgi | 接口链接 |
---|---|
status | 状态码 |
body | 请求体 |
responce | 响应 |
reqHeader | 请求header |
code | 接口状态码 |
cost_time | 接口耗时 |
用户信息
包括用户的特征,唯一标识等等
uin
用户的账号信息。如果是QQ 登陆,就是QQ 号,微信登陆就是 微信uin(不是微信号),或者你们公司自己登录体系下的账号
下面是获取 qq 或者 微信uin
代码语言:javascript复制function getCookie(name) {
const cookieReg = new RegExp(`(^| )${name}=([^;]*)(;|$)`);
const matches = document.cookie.match(cookieReg);
return !matches ? '' : decodeURIComponent(matches[2]);
}
function getQQUin() {
const uin = getCookie('p_luin') || getCookie('p_uin') || getCookie('uin');
return uin ? parseInt(uin.replace(/[^d]/g, ''), 10).toString() : null;
}
function getWeixinUin() {
const uidUin = getCookie('uid_uin');
return uidUin || null;
}
微信uin 是创建微信时分配的独有的uin,不是微信号,因为微信号能改,并不唯一。大概像这样 14411xxxxxxxx134
地区
国家、省、市 这些位置信息,在服务端通过客户端ip 做解析
可以使用 npm 包 node-ip2region 来解析
简单使用如下
代码语言:javascript复制const searcher = require('node-ip2region').create();
const res = searcher.btreeSearchSync('120.68.22.68');
console.log(res);
返回结果如下
代码语言:javascript复制{
city: 0,
region: '中国|0|新疆|伊犁|电信',
}
具体可以看
https://github.com/lionsoul2014/ip2region
设备标识 - aid
页面初始化的时候,会给用户分配一个尽可能唯一的id标识,存在localstorage 中。
可以使用 uuid 生成,或者自己写一个
代码语言:javascript复制const getRandomId = () => {
const aid = 'xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
return aid;
}
会话标识 - sessionId
同样也是唯一的id 标识,但是表示的是会话id,存在 sessionStorage 中。
比如你这次打开页面,为你生成一个,接着你的任何操作都会带上这个id。
下次再打开页面时,会重新生成。
生成方式和 aid 一样
设备信息
关于设备信息的数据就比较多了,对于前端比较重要,前端看重兼容性,各端的支持五花八门,定位问题需要考虑这一点
设备信息,一般我们可以通过 navigator.userAgent 来获取,拿到以下这些字段
os | 系统以及版本 |
---|---|
brand | 品牌(苹果,华为,小米 等) |
device | 产品型号(Huawei P30、Mate40...等等) |
engine | 浏览器渲染引擎 |
browser | 浏览器以及版本 |
具体我们会使用一个 npm 包来解析拿到相应的数据
可以看一下
https://github.com/faisalman/ua-parser-js
使用方式如下
代码语言:javascript复制const parser = require('ua-parser-js');
const sliceVersion = (version, count = 2) => {
if (!version) return '';
return version.split('.').slice(0, count).join('.');
};
const parserUa = (ua) => {
const { browser = {}, os = {}, engine = {}, device = {} } = parser(ua);
return {
browser: browser.name
? `${browser.name}(${sliceVersion(browser.version)})`
: '',
device: device.vendor ? `${device.vendor} - ${device.model || ''}` : '',
os: os.name ? `${os.name} - ${os.version || ''}` : '',
engine: engine.name
? `${engine.name}(${sliceVersion(engine.version)})`
: '',
brand: device.vendor || '',
};
};
比如 userAgent 是
Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
可以解析得到
关于渲染引擎,大概有这么几种
1、IE浏览器 (Trident内核) 2、Firefox (Gecko内核) 3、Safari (Webkit内核) 4、Chrome (Blink内核) 5、Opera (原为Presto内核,现为Blink内核) 6、QQ/WX (原为Webkit内核,现为Blink内核)
网络状态 netType
用户网络状态很重要,有可能用户加载慢时因为网络不行,所以需要记录这个指标
具体先从 navigator.userAgent 中获取,因为微信会将网络类型注入 ua。
看一个 wx 的 userAgent 例子
Mozilla/5.0 (Linux; Android 10; VOG-AL00 Build/HUAWEIVOG-AL00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/045811 Mobile Safari/537.36 MMWEBID/2264 MicroMessenger/8.0.11.1980(0x28000B3B) Process/tools WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64
其次我们再从 navigator.connection 中获取,但是兼容性有点问题,iOS 不支持这个。
代码如下
代码语言:javascript复制const NetworkTypeNum = {
unknown: 'unknown',
wifi: 'wifi',
net2g: '2g',
net3g: '3g',
net4g: '4g',
net5g: '5g',
net6g: '6g',
};
const parseNumberType = (net) => {
net = String(net).toLowerCase();
if (net.indexOf('4g') >= 0) return NetworkTypeNum.net4g;
if (net.indexOf('wifi') >= 0) return NetworkTypeNum.wifi;
if (net.indexOf('5g') >= 0) return NetworkTypeNum.net5g;
if (net.indexOf('6g') >= 0) return NetworkTypeNum.net6g;
if (net.indexOf('3g') >= 0) return NetworkTypeNum.net3g;
if (net.indexOf('2g') >= 0) return NetworkTypeNum.net2g;
return NetworkTypeNum.unknown;
};
const getNetworkType = function () {
let netType = '';
// 优先从 ua 中获取(微信会将网络类型注入 ua)
const arr = navigator.userAgent.match(/NetType/(w )/);
if (arr) {
[, netType] = arr;
} else if (navigator.connection) {
// navigator.connection 存在兼容性问题,当前不支持 ios
netType = navigator.connection.effectiveType || navigator.connection.type;
}
if (!netType) {
netType = 'unknown';
}
const net = parseNumberType(netType);
return;
}
客户端 ip
客户端ip 需要在服务端获取了
代码语言:javascript复制function getClientIp(req) {
try {
const xff = (
req.headers['X-Forwarded-For']
|| req.headers['x-forwarded-for']
|| ''
).split(',')[0].trim();
return xff
|| req.connection.remoteAddress
|| req.socket.remoteAddress
|| req.connection.socket.remoteAddress;
} catch (ex) {
}
return '0.0.0.0';
}
网络运营商 ISP
就是 中国移动,联通,电信 那些数据,在服务端通过 ip 解析拿到,和上面解析省市区一样
可以使用 npm 包 node-ip2region 来解析
简单使用如下
代码语言:javascript复制const searcher = require('node-ip2region').create();
const res = searcher.btreeSearchSync('120.68.22.68');
console.log(res);
返回结果如下,最后一个就是运营商
代码语言:javascript复制{
city: 0,
region: '中国|0|新疆|伊犁|电信',
}
具体可以看
https://github.com/lionsoul2014/ip2region
这一类数据可以帮助你查看用户画像,比如建立像下面这些可视化图
项目信息
主要是页面相关的信息
页面 url
就是页面url 。可以便于根据 url 定位出所有数据,包括错误、资源、请求、性能 等数据,全方位评测出一个页面的质量。
还可以页面作为维度,比较数据
环境 env
一般环境分为 local 本地开发环境、test 线上测试环境、pre 预发布环境、prod 正式环境。
告警都是设置正式环境,测试环境错误日志可不要浪费时间排查
项目 project
团队有很多项目,上报的数据肯定要带上项目名。便于你排查过滤日志
监控npm包版本 sdk_version
项目引入的 监控 sdk 的版本也要记录。
如果因为sdk 导致日志记录的数据有问题,sdk 修复更新了版本之后,还存在有问题的日志。需要查看它依赖的是否是更新之后的版本
项目更新标识 build_time | project_version
这个很重要,作用和上面差不多
比如你线上出现了一个很严重的bug,已经触发告警了。
你修复之后,需要看线上运作情况
因为仍然会存在错误日志,所以需要一个字段去筛选修复之后的线上日志。
可以使用项目打包构建的世界,可以使用项目版本号。不过考虑到一般的业务项目,不太会更新版本号
所以最好是在构建配置中注入一个构建时间变量,供SDK 获取上报
日志信息
日志等级 level
在 离线日志 中说过,日志一般分有等级,来区分重要性,是否需要请求上报,存到本地作为离线日志
代码语言:javascript复制const LOG_LEVEL = {
trace: 10,
debug: 20,
info: 30,
warn: 40,
error: 50,
fatal: 60,
};
日志类型 log_type
上报的日志有很多类型,就像我们之前说的各种监控点一样
1、离线日志
2、页面错误(细分很多种)
3、接口信息
4、静态资源(细分很多种)
5、首屏时间
等等
代码语言:javascript复制const LOG_TYPE = {
pv: 'pv',
promise_error: 'promise_error',
offline: 'offline',
cgi_speed: 'cgi_speed',
resource_speed: 'resource_speed',
....
}
日志时间 log_time
日志发生的时间,一般是时间戳 Date.now()
日志信息 message
一般用于项目内自定义上报存放文字信息的,便于查找对应日志
比如上报 message="报名按钮点击",你就会搜索这个条件,看活动上线一共有多少人报名点击
日志数据 addition
一般用于项目内自定义上报存放 调试数据,便于排查哪个环节出了问题,类似于debug一样,是否在处理数据过程中出现了问题
比如说项目中 catch 拿到的error,或者 表单提交时的数据。
你可能会说,提交的数据,我直接看接口请求的body 不就好了吗,但是其实有时你的函数处理出问题,甚至都没走到请求的这一步。
数据出问题的概率是很大的,不是像你本地开发调试一样规规矩矩的数据,每一步的数据处理都要记录下来,特别是那种format 的处理函数,入口和出口的数据都必须要记录上报
最后
看完上面这些字段,可以基本清楚,字段的设置无非是为了方便你筛选合适日志帮助排查,尽可能帮助还原问题场景,实打实从数据定位问题,不要靠猜想,靠自己偶然复现
鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵, 如果有任何描述不当的地方,欢迎后台联系本人,领取红包