一、前端监控现状
二、前端监控的目的
- 提升用户体验
- 更快的发现发现异常、定位异常、解决异常
- 了解业务数据,指导产品升级——数据驱动的思想
三、前端监控的流程
3.1 采集
3.1.1 环境信息
- url:正在监控的页面,该页面可能会出现性能、异常问题。获取方式为:<br/>
window.location.href<br/> - ua:访问该页面时该用户的userAgent信息,包含操作系统和浏览器的类型、版本等。获取方式为:<br/>
window.navigator.userAgent - token:记录当前用户是谁。通过记录该用户是谁。<br/>
一方面方便将该用户的所有监控信息建立联系,方便数据分析;<br/>
另一方面通过该标识可以查看该用户的所有操作,方便复现问题。<br/>
3.1.2 性能信息
3.1.2.1 指标分类
重定向耗时 | 重定向所耗费的时间 |
DNS解析耗时 | 浏览器输入网址后首先会进行DNS解析,其可以对服务器是否工作作出反馈 |
TCP连接耗时 | 指建立连接过程的耗时 |
SSL连接耗时 | 指数据安全性、完整性建立耗时 |
TTFB 网络请求耗时 | 表示浏览器接收第一个字节的时间 |
数据传输耗时 | 浏览器接收内容所耗费的时间 |
资源加载耗时 | DOM构建完毕后到页面加载完毕这段时间 |
二、页面展示层面
FP(First Paint) | 首次绘制,标记浏览器渲染任何在视觉上不同于导航前屏幕内容之内容的时间点. |
FCP(First Contentful Paint) | 首次内容绘制,标记浏览器渲染来自 DOM 第一位内容的时间点,该内容可能是文本、图像、SVG 甚至 元素. |
LCP(Largest Contentful Paint) | 最大内容渲染,表示可视区“内容”最大的可见元素开始出现在屏幕上的时间点。 |
FMP(First Meaningful Paint) | 首次有效绘制,表示页面的“主要内容”开始出现在屏幕上的时间点。它是我们测量用户加载体验的主要指标。 |
DCL(DomContentLoaded) | 当 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,无需等待样式表、图像和子框架的完成加载. |
L(onLoad) | 当依赖的资源全部加载完毕之后才会触发 |
TTI(Time to Interactive) | 可交互时间,用于标记应用已进入视觉渲染并能可靠响应用户输入的时间点 |
FID(First Input Delay) | 首次输入延迟,用户首次和页面交互(单击链接、点击按钮等)到页面响应交互的时间 |
3.1.2.2 指标求解
重定向耗时 | redirectEnd - redirectStart |
DNS解析耗时 | domainLookupEnd - domainLookupStart |
TCP连接耗时 | connectEnd - connectStart |
SSL连接耗时 | connectEnd - secureConnectionStart |
TTFB 网络请求耗时 | responseStart - requestStart |
数据传输耗时 | responseEnd - responseStart |
资源加载耗时 | loadEventStart - domContentLoadedEventEnd |
二、页面展示层面
- FP和FCP
通过window.performance.getEntriesByType(‘paint’)的方式获取
const paint = window.performance.getEntriesByType('paint');
const FP = paint[0].startTime,
const FCP = paint[1].startTime,
- LCP
function getLCP() {
// 增加一个性能条目的观察者
new PerformanceObserver((entryList, observer) => {
let entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
observer.disconnect();
console.log('LCP', lastEntry.renderTime || lastEntry.loadTime);
}).observe({entryTypes: ['largest-contentful-paint']});
}
- FMP
function getFMP() {
let FMP;
new PerformanceObserver((entryList, observer) => {
let entries = entryList.getEntries();
observer.disconnect();
console.log('FMP', entries);
}).observe({entryTypes: ['element']});
}
- DCL
domContentLoadEventEnd – fetchStart
- L
loadEventStart – fetchStart
- TTI
domInteractive – fetchStart
- FID
function getFID() {
new PerformanceObserver((entryList, observer) => {
let firstInput = entryList.getEntries()[0];
if (firstInput) {
const FID = firstInput.processingStart - firstInput.startTime;
console.log('FID', FID);
}
observer.disconnect();
}).observe({type: 'first-input', buffered: true});
}
3.1.3 异常信息
一、运行时错误
1.非Promise场景
export function listenerError() {
window.addEventListener('error', (event) => {
if (event.target.localName) {
console.log('这是资源错误', event);
}
else {
console.log('这是代码错误', event);
}
}, true)
}
2.Promise场景
export function listenerPromiseError() {
window.addEventListener('unhandledrejection', (event) => {
console.log('这是Promise场景中错误', event);
})
}
二、接口错误
function newXHR() {
const XMLHttpRequest = window.XMLHttpRequest;
const oldXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = (method, url, async) => {
// 做一些自己的数据上报操作
return oldXHROpen.apply(this, arguments);
}
const oldXHRSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = (body) => {
// 做一些自己的数据上报操作
return oldXHRSend.apply(this, arguments);
}
}
3.1.4 业务信息
3.2上报
为什么采用Image的方式上报?<br/>
- 没有跨域问题。因为数据服务器和后端服务器大概率是不同的域名,若采用Ajax的方式进行处理还要处理跨域问题,否则数据会被浏览器拦截。<br/>
- 不会阻塞页面加载,只需new Image对象即可。
- 图片类型很多,为什么采用gif这种格式进行上报?<br/>
其实归结为一个字——小。对于1*1px的图片,BMP结构的文件需要74字节,PNG结构的文件需要67字节,GIF结构的文件只需要43字节。同样的响应,GIF可以比BMP节约41%的流量,比PNG节约35%的流量,所以选择gif进行上报。
3.3分析
一、单机<br/>
访问量小、日志少的网站可以采用单机的方式对数据进行分析,例如用node读取日志文件,然后通过日志文件中获取所需要的信息,最终将处理的信息存储到数据库中。<br/>
二、集群<br/>
很多产品的访问量很大,日志很多,此时就需要利用Hadoop进行分布式处理,获取最终处理结果,其处理流程图如下所示:
3.4报警
- 邮件——普通报警
- 短信——严重报警,已影响部分业务
- 电话——特别严重,例如系统已宕机
1.如果觉得这篇文章还不错,来个分享、点赞、吧,让更多的人也看到
2.关注公众号执鸢者,领取学习资料,定期为你推送原创深度好文
参考
http://www.alloyteam.com/2020...
https://www.colabug.com/2019/...