前端监控sdk实战 青训营笔记

117 阅读5分钟

这是我参加青训营伴学笔记的第十二天

什么是前端监控

前端监控技术尽可能的采集这一个过程以及后续用户交互中产出的性能指标与发生的异常事件并上报到平台完成消费

前端监控通过对页面数据的采集和上报,来帮助开发者更快速的对质量差的页面进行归因

监控了什么

1.性能指标

2.异常事件

3.用户行为

常用的前端监控性能指标

传统的性能指标

呈现给用户很难,只在乎技术细节

以用户为中心的性能指标

渲染 首屏 FP(首次渲染的时间点) FCP(首次有内容渲染出来的时间点)

渲染的内容

FMP(首次绘制有意义内容的时间点,比FP,FCP内容更多)

FMP缺点

非标准化,有20%的差距

SI(很少用)

LCP(最大的内容在可视区域内变得可见的时间点,大概就是整个页面的主要内容出来的时间点)

LCP的优点

用户容易理解

与FMP相似

容易计算和上报

我们使用LCP比较多,FMP比较少

页面的是否可以交互

TTI(测量页面完全加载主要资源的时间节点)

TTI越小越好,是很重要的性能指标

TBT 用户无法响应用户输入的时间有多少

就是FCP-TTI之间的时间,所有长任务的阻塞时间的总和

超过50毫秒就算作长任务,可以说是性能阻塞

具体使用体验

FID(页面渲染的加载体验)

FID:第一次与页面交互直到浏览器对交互作出响应

CLS 加载时期视口中元素的移动程度

时间线

FP(开始)=》

FCP=》FMP(主要内容)或者是LCP=》TTI(完全加载)

| ----------- TBT(阻塞时间) -------------|

常见异常

静态资源错误

在拉取和加载静态资源的过程中发生了预期之外的错误

如网络异常,导致静态资源无法正常渲染到页面上 (比如说视频和图片无法加载)

请求异常

主要监控的是HTTP协议

请求状态码

请求异常=请求状态码>=400

异步请求拉去取的静态资源错误

状态码为0

XML http被停止

请求成功率=请求成功数/(成功数+失败数)

JS错误(前端监控的重点)

严重影响页面的正常交互与渲染

白屏异常(特殊,因为不能通过标准化方法监听)

可以通过DOM树的结果粗略的判断白屏是否发生

监听到异常时应该对其归因

通常导致白屏的原因

发放js错误导致关键资源加载错误

请求异常或者静态资源加载失败

长时间js线程繁忙阻塞渲染任务

实践: 监控前端性能与异常

性能指标监控实践

原理

利用perormance和performanceobserver (要做好技术方案的准备 看文档)

 /*对应性能指标
                FP,FCP=>paint
                LCP=>largest-contentful-paint
                FIP=>first-input  
              */
               const entryTypes=["paint","largest-contentful-paint","first-input"]
               //1.performance obsever
               const p=new PerformanceObserver(list=>{
                for(const entry of list.getEntries()){
                  console.log(entry);
                }
               })
               p.observe({entryTypes});
              //performance对象去读取性能指标
              window.performance.getEntriesByType("paint");
              window.performance.getEntriesByType("first-input");

              /*performance对象有一些值没有办法取到(比如LCP),而且它是在渲染之前去读取
                那么我们先使用performance对象去获取性能指标
                获取不到的再使用performance obsever

              */
             //封装一个monitor
             //1.有很多monitor  那么第一步就是取名字
             //2.监听能力  封装这个能力
             //3.主动开启(而不是在创建出来就直接开启)
             //4.把数据收集起来(性能指标)上报给平台  上报能力
             function createPerfMonitor(report:({name:string,data:any})=>void){//为了sdk调用(这是个高阶函数)
              const name="performance";//取名字
              const entryTypes=["paint","largest-contentful-paint","first-input"]
               
               function start(){
               const p=new PerformanceObserver(list=>{
                for(const entry of list.getEntries()){
                  console.log(entry);
                  //上报能力
                   report({name,data:entry});
                }
               })
               p.observe({entryTypes});
             }//封装监听能力  不是直接开启
             return {name,start};
            }

42eb057441cf415e3f82125a5b73458.png

JS错误监听

异步编程时,promise被reject且没有处理器时就会触发unhandledrejection

//1.监听js错误
            window.addEventListener("error",(e)=>{
                if(e.error){//过滤
                    console.log("capture an error",e.error);
                }

            })
            // throw new Error("1111");
            //promise rejection
            window.addEventListener("unhandledrejection",(e)=>{
                console.log("capture unrejection",e);
            })
        //    Promise.reject("test");
        //3.monitor
        function createJsErrorMonitor(report:({name:string,data:any})=>void){

            const name="js-error";
            function start(){
            window.addEventListener("error",(e)=>{
                if(e.error){//过滤
                    console.log("capture an error",e.error);
              report({name,data:{type:e.type,massage:e.message}})
                }

            })
            // throw new Error("1111");
            //promise rejection
            window.addEventListener("unhandledrejection",(e)=>{
              report({name,data:{type:e,reason:e.reason}})
            })
        //    Promise.reject("test");
        }
    }
    return {name,start}

c519850f13f47477ef772f8925760e0.png

a8906d060d6581b54ac190e9a786164.png

静态错误类型
//1.静态资源错误   注意捕获阶段才可以监听到
            window.addEventListener("error",(e)=>{
           const target=e.target||e.srcElement;//srcenlement兼容老版本浏览器
           if(!target){
            return;//如果错误就直接返回了
           }
           if(target instanceof HTMLElement){
            //link script
            let url;
           if(target.tagName.toLocaleLowerCase()==="link"){
            url=target.getAttribute("href");//区分link
           }
           else{
            url=target.getAttribute("scr");//区分link

           }
           console.log("异常",url);
           }
            },true)//设置为捕获阶段
        // const link=document.createElement("link");
        // link.href="1.css";
        // link.rel="stylesheet";
        // document.head.append(link);
        // const script=document.createElement("script");
        // script.src="2.js";
        // document.head.append(link);
            //2.封装monitor
            function createSteateMonitor(report:({name:string,data:any})=>void){
                const name="steate-error";
                function start(){
                    window.addEventListener("error",(e)=>{
           const target=e.target||e.srcElement;//srcenlement兼容老版本浏览器
           if(!target){
            return;//如果错误就直接返回了
           }
           if(target instanceof HTMLElement){
            //link script
            let url;
           if(target.tagName.toLocaleLowerCase()==="link"){
            url=target.getAttribute("href");
           }
           else{
            url=target.getAttribute("scr");

           }
           report({name,data:{url}});
           }
            },true)
                }
            }
            return{name,start};
请求异常

使用回调方式

hook(钩子)

5f3a7e8635bc96227f1bbb98c970a4a.png

前端监控流程概述

76a3b1a9d1a1936fad7fc622309b7e4.png 数据上报 sendBeacon()

关注请求性能 请求异常除了请求错误外,我们还关注慢请求

更安全和稳定的hook函数 补全hook函数,更安全

用户行为监控 也十分重要

sdk提供了数据采集和组装上报的功能

在后端里面还需要清洗存储(大数据)和数据消费(接口)