前端监控之性能与异常

前端,监控,性能,异常 · 浏览次数 : 73

小编点评

**页面性能监控与异常处理代码** **1. 页面加载类型判断** - `loadPageInfo.loadType = navigation.type;` **2. 页面加载完成时间** - `loadPageInfo.loadPage = timing.loadEventEnd - timing.navigationStart;` **3. 重定向时间** - `loadPageInfo.redirect = timing.redirectEnd - timing.redirectStart;` **4. 卸载页面的时间** - `loadPageInfo.unloadEvent = timing.unloadEventEnd - timing.unloadEventStart;` **5. DNS查询时间** - `loadPageInfo.appCache = timing.domainLookupStart - timing.fetchStart;` **6. onload回调函数** - `loadPageInfo.loadEvent = timing.loadEventEnd - timing.loadE`4 异常监控前端需要监控的错误主要有两类:Javascript错误(js错误、promise错误)监听error错误(资源加载错误)4.1 console.error1. **7. console.error捕获** - `window.addEventListener( 'error', function(e){`1. `var errorMsg = e.error && e.error.message,`1. `errorStack = e.error && e.error.stack,`1. `pageUrl = e.filename,`1. `lineNumber = e.lineno,`1. `columnNumber = e.colno;`1. ``1. ``1. `saveJSError( 'console_error', errorMsg, pageUrl, lineNumber, columnNumber, errorStack );`1. `} });` **8. saveJSError函数** - `window.onunhandledrejection = function(e){``var errorMsg = '';``var errorStack = '';``if( typeof e.reason === 'object' ){``errorMsg = e.reason.message;``errorStack = e.reason.stack;``}else{``errorMsg = e.reason;``errorStack = '';` `}` `saveJSError( 'on_error', errorMsg, '', 0, 0, 'UncaughtInPromiseError: ' + errorStack );` `}`5 总结以上,通过简单的js代码,即可实现对页面性能与异常的监控与数据上报,后续需要相应具体的平台汇总,及相应的业务所需数据(如PV、UV等)的计算,才能真正实现对产品的页面数据呈现,用于业务扩展及宣导。

正文

作者:京东零售 李菲菲

1 前言

现有的大部分监控方案都是针对服务端的,而针对前端的监控很少,诸如线上页面的白屏时间是多少、静态资源的加载情况如何、接口请求耗时好久、什么时候挂掉了、为什么挂掉,这些都不清楚。

同时,在产品推广过程中,经常需要统计页面的使用情况及用户行为,从而可以从运营和产品的角度去了解用户群体,进而迭代升级产品,使其更加贴近用户,为业务的扩展提供更多可能性。

因而,我们需要一个前端的页面监控系统,持续监控和预警页面性能的状况,并且在发现瓶颈时用于指导优化工作。

2 前端监控目标

前端监控主要包含两大块:性能监控及异常监控

  1. 保证稳定性(异常监控)
    错误监控包括 JavaScript 代码错误,Promsie 错误,接口(XHR,fetch)错误,资源加载错误(script,link等)等,这些错误大多会导致页面功能异常甚至白屏。
  2. 提升用户体验(性能监控)
    性能监控包括页面的加载时间,接口响应时间等,侧面反应了用户体验的好坏。

3 性能监控

3.1 简单描述页面加载

简单看一下,从输入url到页面加载完成的过程如下:

首先需要通过 DNS(域名解析系统)将 URL 解析为对应的 IP 地址,然后与这个 IP 地址确定的那台服务器建立起 TCP 网络连接,随后我们向服务端抛出 HTTP 请求,服务端处理完我们的请求之后,把目标数据放在 HTTP 响应里返回给客户端,拿到响应数据的浏览器就可以开始走一个渲染的流程。渲染完毕,页面便呈现给了用户。

我们可以将这个过程分为如下的过程片段:

  1. DNS 解析
  2. TCP 连接
  3. HTTP 请求抛出
  4. 服务端处理请求,HTTP 响应返回
  5. 浏览器拿到响应数据,解析响应内容,把解析的结果展示给用户

3.2 从开发者角度,看页面加载各阶段

从输入url到用户可以使用页面的全过程时间统计,会返回一个PerformanceTiming对象,单位均为毫秒。
关于performace,已经在《从前端角度浅谈性能》中进行过介绍,,下面再强调一下:

各阶段的性能耗时可以通过API:window.performance来获取,对应的具体方法有:performance.timing、performance.getEntriesByType(‘resource’)、performance.navigation等。
如上,开发者可以通过performance中各阶段的时间戳,分别获取到 页面各阶段的性能指标,具体的个静态资源的加载耗时、及 页面是否重定向和重定向耗时。

按触发顺序排列所有属性:

  • navigationStart:在同一个浏览器上下文中,前一个网页(与当前页面不一定同域)unload 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等
  • redirectStart:第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0
  • unloadEventStart:前一个网页(与当前页面同域)unload 的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0
  • redirectEnd:最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内的重定向才算,否则值为 0
  • unloadEventEnd:和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳
  • fetchStart:浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前
  • domainLookupStart:DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
  • domainLookupEnd:DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
  • connectStart:HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间
  • secureConnectionStart:HTTPS 连接开始的时间,如果不是安全连接,则值为 0
  • connectEnd:HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间
  • requestStart:HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存,连接错误重连时,这里显示的也是新建立连接的时间
  • responseStart:HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
  • responseEnd:HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存
  • domLoading:开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
  • domInteractive:完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件
  • domContentLoadedEventStart:DOM 解析完成后,网页内资源加载开始的时间,文档发生 DOMContentLoaded事件的时间
  • domContentLoadedEventEnd:DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕),文档的DOMContentLoaded 事件的结束时间
  • domComplete:DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件
  • loadEventStart:load 事件发送给文档,也即 load 回调函数开始执行的时间,如果没有绑定 load 事件,值为 0
  • loadEventEnd:load 事件的回调函数执行完毕的时间,如果没有绑定 load 事件,值为 0

3.3 各阶段性能的计算(自定义)

1.  `const { timing, navigation } = window.performance`
1.  `const loadPageInfo = {};`
1.  ``
1.  `// 页面加载类型,区分第一次load还是reload, 0初次加载、1重加载`
1.  `loadPageInfo.loadType = navigation.type;`
1.  ``
1.  `// 页面加载完成的时间 - 几乎代表了用户等待页面白屏的时间`
1.  `loadPageInfo.loadPage = timing.loadEventEnd - timing.navigationStart;`
1.  ``
1.  `// 重定向的时间`
1.  `loadPageInfo.redirect = timing.redirectEnd - timing.redirectStart;`
1.  ``
1.  `// 卸载页面的时间`
1.  `loadPageInfo.unloadEvent = timing.unloadEventEnd - timing.unloadEventStart;`
1.  ``
1.  `// 查询 DNS 本地缓存的时间`
1.  `loadPageInfo.appCache = timing.domainLookupStart - timing.fetchStart;`
1.  ``
1.  `// 【重要】DNS 查询时间`
1.  `// 页面内是不是使用了太多不同的域名,导致域名查询的时间太长?推荐 DNS 预加载。`
1.  `// 可使用 HTML5 Prefetch 预查询 DNS`
1.  `loadPageInfo.lookupDomain = timing.domainLookupEnd - timing.domainLookupStart;`
1.  ``
1.  `// HTTP(TCP)建立连接完成握手的时间`
1.  `loadPageInfo.connect = timing.connectEnd - timing.connectStart;`
1.  ``
1.  `// 【重要】HTTP请求及获取 文档内容的时间`
1.  `loadPageInfo.request = timing.responseEnd - timing.responseStart;`
1.  ``
1.  `// 【重要】前一个页面 unload 到 HTTP获取到 页面第一个字节的时间`
1.  `// 【原因】这可以理解为用户拿到你的资源占用的时间,推荐 加异地机房,加 CDN 处理,加宽带,加 CPU 运算速度`
1.  `// TTFB 即 Time To First Byte`
1.  `loadPageInfo.ttfb = timing.responseStart - timing.navigationStart;`
1.  ``
1.  `// 解析 DOM 树结构的时间`
1.  `loadPageInfo.domReady = timing.domComplete - timing.responseEnd;`
1.  ``
1.  `// 【重要】执行 onload 回调函数的时间`
1.  `// 【原因】是否太多不必要的操作都放在 onload 回调函数里执行了,推荐 延迟加载、按需加载的策略`
1.  `loadPageInfo.loadEvent = timing.loadEventEnd - timing.loadE`

4 异常监控

前端需要监控的错误主要有两类:

  1. Javascript错误(js错误、promise错误)
  2. 监听error错误(资源加载错误)

4.1 console.error

1.  `// 重写console.error,可以捕获更全面的报错信息`
1.  `var oldError = console.error;`
1.  ``
1.  ``
1.  `console.error = function(tempErrorMsg){`
1.  `var errorMsg = ( arguments[0] && arguments[0].message ) || tempErrorMsg;`
1.  `var lineNumber = 0;`
1.  `var columnNumber = 0;`
1.  `var errorStack = arguments[0] && arguments[0].stack;`
1.  ``
1.  ``
1.  `if( !errorStack ){`
1.  `saveJSError( 'console_error', errorMsg, '', lineNumber, columnNumber, 'CustomizeError: ' + errorMsg );`
1.  `}else{`
1.  `saveJSError( 'console_error', errorMsg, '', lineNumber, columnNumber, errorStack );`
1.  `}`
1.  ``
1.  ``
1.  `return oldError.apply( console, arguments );`

4.2 error事件

通过对error事件的监听,可以捕捉到 js语法 及 资源加载 的错误。根据 event.target.src / href 来判断是否为资源加载错误。

1.  `window.addEventListener( 'error', function(e){`
1.  `var errorMsg = e.error && e.error.message,`
1.  `errorStack = e.error && e.error.stack,`
1.  `pageUrl = e.filename,`
1.  `lineNumber = e.lineno,`
1.  `columnNumber = e.colno;`
1.  ``
1.  ``
1.  `saveJSError( 'on_error', errorMsg, pageUrl, lineNumber, columnNumber, errorStack );`
1.  `} );`

4.3 Promise

 `// 捕获未处理的Promise错误`
`window.onunhandledrejection = function(e){`
`var errorMsg = '';`
`var errorStack = '';`
`if( typeof e.reason === 'object' ){`
`errorMsg = e.reason.message;`
`errorStack = e.reason.stack;`
`}else{`
`errorMsg = e.reason;`
`errorStack = '';`
 `}`
 `saveJSError( 'on_error', errorMsg, '', 0, 0, 'UncaughtInPromiseError: ' + errorStack );`
  `}`

5 总结

以上,通过简单的js代码,即可实现对页面性能与异常的监控与数据上报,后续还需要相应具体的平台汇总,及相应的业务所需数据(如PV、UV等)的计算,才能真正实现对产品的页面数据呈现,用于业务扩展及宣导。

6 后续

上述代码,实现了对页面性能及异常的监控,但其实前端的监控还包括了请求接口的监控与埋点的实现,后续将陆续推出,敬请期待。

与前端监控之性能与异常相似的内容:

前端监控之性能与异常

现有的大部分监控方案都是针对服务端的,而针对前端的监控很少,因而,我们需要一个前端的页面监控系统,持续监控和预警页面性能的状况,并且在发现瓶颈时用于指导优化工作。本文介绍通过简单的js代码,即可实现对页面性能与异常的监控与数据上报。

[转帖]Jmeter插件之ServerAgent服务器性能监控工具的安装和使用

https://www.cnblogs.com/pachongshangdexuebi/p/13354201.html 一、前言 性能测试时我们关注的重要指标是:并发用户数,TPS,请求成功率,响应时间,服务器的CPU,memory, I/O disk等。Jmeter的聚合报告可以查看并发数、吞吐量

Jmeter学习之七_使用influxdb2.7和grafana10进行Jmeter测试结果展示的方法

# Jmeter学习之七_使用influxdb2.7和grafana10进行Jmeter测试结果展示的方法 ## 摘要 ``` 前几天验证了 线程组内的-监听器 jp@gc 相关的组件 以及验证了 server-agent的方式可以监控机器的性能表现. 但是发现很多结果集是比较杂乱 并且不太好查看的

[转帖]数据库的可观测性能力与监控能力建设之间的差别

白鳝的洞穴2023-04-18 39 前阵子的DTC2023上,我分享的内容是关于数据库可观测性的。会后有不少朋友都和我聊了关于数据库可观测性的问题,也有很多朋友对于这个新名词感到有点高大上,不过并不以为然。认为可观测性就是以前的数据库监控的炒冷饭。实际上从数据库监控到利用数据库的可观测性能力去做数

企业应用可观测性利器!华为云CodeArts APM发布

摘要:近日,华为云全链路应用性能管理服务CodeArts APM全新上线,提供端到端的全链路性能管理服务,涵盖前端监控、应用性能监控,全面拥抱开源生态。 本文分享自华为云社区《企业应用可观测性利器!华为云CodeArts APM发布》,作者:华为云头条。 当前,企业数字化转型和业务互联网化逐渐加深,

【性能监控】如何有效监测网页静态资源大小?

前言 作为前端人员肯定经常遇到这样的场景:需求刚上线,产品拿着手机来找你,为什么页面打开这么慢呀,心想自己开发的时候也有注意性能问题呀,不可能会这么夸张。那没办法只能排查下是哪一块影响了页面的整体性能,打开浏览器控制台一看,页面上的这些配图每张都非常大,心想这些配图都这么大,页面怎么快,那么我们有没

[转帖]Linux性能优化(四)——BCC性能监控工具

http://www.javashuo.com/article/p-cxglhftg-nz.html 时间 2021-01-17 标签 前端 python linux ios git github 正则表达式 编程 api 缓存 栏目 Linux 繁體版 原文 https://blog.51cto.

[转帖]Linux性能优化(四)——BCC性能监控工具

一、BCC简介 1、BCC简介 BCC是一个Python库,简化了eBPF应用的开发过程,并收集了大量性能分析相关的eBPF应用。BCC为BPF开发提供了不同的前端支持,包括Python和Lua,实现了map创建、代码编译、解析、注入等操作,使开发人员只需聚焦于用C语言开发要注入的内核代码。 BCC

[转帖]python 性能优化监控工具_Linux性能优化(四)——BCC性能监控工具

一、BCC简介 1、BCC简介 BCC是一个Python库,简化了eBPF应用的开发过程,并收集了大量性能分析相关的eBPF应用。BCC为BPF开发提供了不同的前端支持,包括Python和Lua,实现了map创建、代码编译、解析、注入等操作,使开发人员只需聚焦于用C语言开发要注入的内核代码。 BCC

【转帖】Linux性能优化(四)——BCC性能监控工具

一、BCC简介 1、BCC简介 BCC是一个Python库,简化了eBPF应用的开发过程,并收集了大量性能分析相关的eBPF应用。BCC为BPF开发提供了不同的前端支持,包括Python和Lua,实现了map创建、代码编译、解析、注入等操作,使开发人员只需聚焦于用C语言开发要注入的内核代码。 BCC