页面在用户端运行。如果10%的用户页面有问题,没有办法在本地复现?如何先了解前端出现的问题,而不是等待用户反馈?能不能像查看服务器日志一样定位前端页面的运行问题?随着前端的业务复杂度越来越高,即使有足够的本地测试和根据caniuse的大量兼容性,页面能不能正常运行,运行得如何,仍然不能让人放心。前端页面发布时,页面运行的设备、浏览器、网络环境、用户的操作习惯等因素都可能是导致页面异常的原因。因此,需要对前端页面进行一些监控,最可行的前端监控方式是将页面的日志选择上报给监控日志服务器。前端日志报告可以非常简单。采集到业务逻辑执行的日志数据后,可以通过参数的形式构造一个url,然后通过Image请求发送给服务器,完成日志上报。(newImage).src=`/r.png?page=${location.href}¶m1=${param1}...`;这行代码完成了日志的上报。然而,在生产环境中,日志上报所引发的问题要复杂得多。日志上报带来的问题日志上报的最终目的是为业务服务,监控业务的运行状态。一般来说,在前端运行场景下,开发者最期望监控的就是页面&API请求是否正常响应,页面的js逻辑是否正常执行。.为了覆盖这两个监控目标,需要覆盖很多类型的日志。在一些特殊场景下,开发者也希望能够与特定业务灵活结合,实现自定义上报。所以常见的日志类型如下-页面&API请求是否正常响应-API调用日志-API调用是否成功,耗时多少-页面性能日志-页面连接时间,首次渲染时间,资源加载时间等–访问统计日志–PV/UV,短时间内的断崖式体积变化很容易反映出问题–页面js逻辑是否正常执行–页面稳定性日志–页面加载和产生的JS错误信息页面交互-业务相关日志-自定义上报-一定随着前端业务的增长,日志监控上报量会快速增加,监控逻辑也会越来越复杂。在生产环境中,前端监控最重要的基本原则是日志的采集和上报本身不能抛出异常或影响页面性能。如此多的日志类型意味着日志获取的逻辑复杂,各种浏览器和环境也会让这个问题变得更加困难。比如你想用console.warn打印异常信息,但是可能会出现warn函数调用错误;比如捕获到错误但是error.message全是Scripterror...浏览器兼容性,前端业务逻辑依赖、日志上报方式、日志上报效率、用户操作习惯、网络环境等因素都可能导致日志上报出现问题,甚至影响业务。这些因素都会给日志上报带来可靠性和性能问题。日志报告的可靠性。浏览器兼容性在不同的终端和浏览器中,由于兼容性不同,日志的获取逻辑和上报方式需要兼容多种,比如fetch方式是否可用,页面性能(performance)计算是否可以使用NT2标准,这些问题可能导致上报逻辑本身报错,污染业务日志统计;上报可靠性日志采集sdk可能因为网络原因没有加载,所以安全的做法是sdk注入的位置合理靠后,那么在页面打开到sdk初始化的这段时间里会出现漏报;后端通常会独立设置一个日志采集服务器进行业务分离,这种情况下日志上报可能会遇到跨域问题;频繁的用户操作和关闭页面可能会导致许多收集的数据丢失。日志上报的性能问题在一个复杂的站点中,可能会有大量的日志数据,上报可能会因为浏览器并发数的限制而阻塞业务网络请求或者影响页面性能。更优雅的上报姿势姿势1业务资源隔离Isolation为了避免影响业务,理所当然的,为了不占用业务计算资源,日志上报需要单独设置一个后端服务。同时,不能使用与企业相同的域名。这类似于页面尽量使用CDN导入资源的原理。浏览器对同一个域名的并发数会有一定的限制。页面性能、资源加载、初始化API、PV/UV、初始化js逻辑错误等日志都是在页面初始化时触发上报的。短时间内如此大量的报告可能会导致网络请求延迟。比如Chrome同域名最大并发连接数为6,如果同时报日志超过6次,就会影响同域名的业务;更糟糕的是,页面上有一些错误,网络连接质量不高。会使日志上报阻碍页面渲染。因此,日志上报可以像使用CDN服务一样使用单独的域名和日志处理服务。由于使用不同的域名,跨域的问题也会随之而来,这就需要前后端的支持。服务器需要允许外部访问Access-Control-Allow-Origin:*;前端在上报日志时要加上跨域标识,比如fetch方法:varurl='https://arms-retcode.aliyuncs.com/r。png';fetch(`${url}?t=perf&page=qar.alibaba-inc.com&load=1168`,{mode:'no-cors'})首先是DNS解析,但是可以通过在页面中加入DNS预解析来避免。标签延迟上报。window.addEventListener("unload",uploadLog,false);functionuploadLog(){varxhr=newXMLHttpRequest();xhr.open("POST","/r.png",false);//false表示同步xhr.send(logData);}这种上报的缺点是会影响下一页的性能。更优雅的方式是使用navigator.sendBeacon(),它可以异步发送日志数据。window.addEventListener("unload",uploadLog,false);functionuploadLog(){navigator.sendBeacon("/r.png",logData);}合并前和合并后(navigator.sendBeacon)理想情况下,合并n条日志上报totaltimespent可以达到原来的1/n总结。前端业务场景和浏览器的兼容性差异很大,所以日志上报必须兼容多种方式;页面生命周期和业务逻辑会影响日志能否获取,是否遗漏。因此,必须严格把握相应的日志类型和上报时机;前端业务逻辑快速迭代,场景多样,日志上报必须和业务解耦,同时可以自定义。这些大大小小的陷阱促使我们将前端日志监控定为一个独立的系统工程。在打磨这个项目的过程中,我们也在探索是否有更高效稳定的日志上报方式。
