最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端埋点抽离方案与异常监控

    正文概述 掘金(IvanLiu___)   2021-04-03   843

    前端监控主要为了获取用户行为以及跟踪产品端的使用情况,通过筛选合理数据,以大数据为依托,规划合理的产品优化方向

    前端监控:主要分为三类:数据监控(埋点)、性能监控、异常监控
    

    数据监控(埋点)

    埋点常见收集点:
    1. PV:页面浏览量;UV:浏览页面的自然人个数
    2. 按钮点击/入口渠道/用户信息/访问的卡片信息/出发区域的空间信息
    3. 页面停留时长
    

    埋点方案

    1.代码埋点

    大家工作中经常使用的方案是代码埋点,开发人员按照埋点sdk,手动区分场景进行代码嵌入
    前端埋点一般区分为:站外与自主app内
    需要进行两端埋点的统一输入口径的封装
    
    // 前端页面存在多渠道公用,简单的代理封装,让业务看起来更明了
    let sendTracker = (options){
        if(isMyApp){
            APPSDK.SendTracker(options)
        }else{
            // sdk 发送
            SendTracker(options)
        }
    }
    

    上面说的接入入口发送,具体的业务接入才是最痛苦的,因为代码埋点直接侵袭了业务代码范畴,很难做到一个明确的隔离。对于业务数据分析师的考验也很大,如果数据联系分析不下功夫,那就变成前端要进行 “傻瓜式” 埋点收集

    tips: 比方说:商品卡片交互事件统计,如浏览者为平台会员,展示的促销卡片样式。也就是卡片存在多种自定义的样式。

      样式的依赖数据也就是用户身份
      前端只需要上报 {productid: 'xxxxx',token: 'xxxxxxxxxxxxx'}
      通过用户身份的获取,即可分析卡片的曝光率/点击率
    

    ? ? 当然前端上报全数据,对于分析师会节省很多计算操作,但全数据对于业务的侵入伤害会增加很多。很多业务模块不需要,不关注的字段,因为需要上报埋点数据,需要进行数据集中管理,这也就是前端会排斥很多埋点的最主要因素。

    总结一句话:本来不需要,做完了也不需要,你来了,我必须要。可我真的不想要

    常规的代码埋点方案在开发维护中,存在版本不同步,产品 & ui & 数据 & 技术 在交互流程简单调整的时候,可能并不会去过多在意是否会影响埋点流程代码。而埋点数据逻辑流程异常,数据上报是无状态的,并不具有很强的敏锐度。可能要很长时间才能会被感知

    所有我们需要去把我一个度,就是尽量减少 埋点逻辑与业务逻辑的融合

    移动端主要收集埋点交互的方式,大致分为两类: “曝光” 跟 “点击”
      曝光:一般需要携带的发送的数据,不存在交互逻辑,基本为服务端直出,然后拼接页面公共数据进行上报
      点击:强耦合业务逻辑
      
    
    问题来了,如何减少呢
      拿vue组件为例,业务组件模块分为:
    
      style: 样式表
      templete: html 模版
      script: 组件自身逻辑处理/用户交互
      
      埋点侵入最深的 script,业务组件后期变更最频繁的也便是js逻辑,这就变成了,日志 === 业务
      
      如果业务开发中把大部分的埋点数据直接挂载到templete上, 逻辑 script 模块可有效减少代码。
      提升一定的阅读维护效率
    
    以前写的一套脱离框架的埋点上报方案
      思想:所有需要埋点上报的数据,全部挂载到dom标签上,在特定交互时机进行页面扫描,check触发条件,上报
      
    
    1. 生命js库全局配置参数 支持扩展
        let sendTracker = {
          version: '1.0.0', // 版本
          poll: null, // 扫描 time callback
          throttle: 0, // 节流时长
          showTime: 0, // 有效曝光时间
          openSendShow:false,  // 是否开启监测页面show
          // offsetX  dom 进入适口的偏移量
          // offsetY  dom 进入适口的偏移量
      };
    

    2.定义全局 “默认”数据 支持扩展

    let globalData = { 
       'ua': navigator.userAgent,  
       'cookie': (() => {
           let key = Cookies.get('MP_MD_UUID') // setcookie 设置唯一uid
           if (!key) {
               Cookies.set('MP_MD_UUID', UUID, {
                   expires: 365
               })
           }
           return key
       })(),
       'source':(() => {
           return getAppType(); //获取渠道
       })(),
    }
       
    
    1. check 元素是否正确显示在视口中
     let inView = (ele) => {
    
        //1. dom 元素是否显示中 
        // String.prototype.toLocaleLowerCase.apply(ele.style.display) !== 'none'
    
        //2. to-do 判断元素是否在视口中
     };
    
    1. 扫描所有dom元素节点,check 是否需要发送埋点,正确发送后,dom节点打上标记
    
    /**
     * 捕获所有节点
     */
    let render = () => {
        // 获取有效 show dom 
        let nodes = (function() {
            let allNodes = document.getElementsByTagName("*");
            allNodes = Array.prototype.slice.call(allNodes);
            let mpNodes = [];
            allNodes.forEach(dom => {
                if(dom.getAttribute('mp_module_event') && dom.getAttribute('mp_module_event').indexOf('show') > -1){
                    // 发送埋点
                    mpNodes.push(dom)
                }
            });
            return mpNodes;
        })();
    
        /**
         * 循环遍历有效dom 节点 是否显示在视口
         * dom 在适口中曝光的时间
         */
        for (let i = 0; i < nodes.length; i++) {
            let elem = nodes[i];
            if (isShow(elem) && inView(elem)) {
                if (!elem) {
                    return false;
                }
                setTimeout(function(){
                    if (isShow(elem) && inView(elem) && !elem.getAttribute('mp_send_status')) {
                        // 已显示 记录
                        elem.setAttribute('mp_send_status',true);
                        // console.log('已发送',elem)
                        sendTracker.sendTrackerMsg({},elem)
                    }else{
                        // console.log('时间不够',elem)
                    }
                },sendTracker.showTime)
            }else{
                // console.log('未显示入口 || 隐藏元素',elem)
            }
        }
    };
    
    

    5.初始化埋点,合并配置项。同时注册监听

    sendTracker.init = (config) => {
    
        // 首先合并配置项
        sendTracker.throttle = optionToInt(config.throttle, 200) //节流 200 毫秒
    
        sendTracker.showTime = optionToInt(config.showtime, 150) // 曝光时间
        
        
        // 更新全局发送数据
        globalData = { ...globalData, ...config.global}
        
        document.documentElement.addEventListener('touchstart',function(e){
            let domlist = e.path;
            for (let i = 0; i < domlist.length; i++) {
                if(domlist[i]['nodeName'] == 'HTML'){break;}
                if(domlist[i].getAttribute('iavn_module_event') && domlist[i].getAttribute('ivan_module_event').indexOf('click') > -1){
                    // 发送点击埋点
                    sendTracker.sendTrackerMsg({},domlist[i])
                    break;
                }
            }
        },false)
    
        // 是否开启 页面show的捕获
        if(!sendTracker.openSendShow){return}
        render();
        // 注册页面全局交互监听
        if (document.addEventListener) {
            window.addEventListener('scroll', function(){
                sendTracker.raf(render);
            }, false);
            window.addEventListener('touchstart', function(){
                sendTracker.raf(render);
            }, false);
            window.addEventListener('load', function(){
                sendTracker.raf(render);
            }, false);
        }
    };
    
    

    6.触发上报,收集特定规则属性(例如 ivan-productid)

    sendTracker.sendTrackerMsg = (elem) => {
        // to-do
        // 获取dom 节点上 挂载特定表示 例如 ivan-xx-xx 属性数值 obj
        // 上报发送
    }
        
    
    1. 扩展类 api

       1.切换发送地址  sendTracker.changeSendUrl // 变更数据上报地址
       2.手动检测api  sendTracker.handlecheck  // 触发收集
       3.销毁监听 sendTracker.detach 
       4.xxxxxx
      
    将一些不牵扯复杂业务逻辑的埋点,挂载到 dom标签上面,需要定义的一些上报数据直接进行dom标签属性的挂载。在后续的开发过程中,逻辑业务js中需要处理的埋点,基本上很少,代码量也会得到大幅度减少,后续维护对于模块的阅读效率也会得到很大提升
    数据安全的时代,完全可以强跟随业务模块,进行去统计数据的展示系统,可实现全司数据共享,实时数据可视化

    2.无埋点

    无埋点并不是说不需要埋点,而是全部埋点
    前端的任意一个事件都被绑定一个标识,收录页面发生的一切。
    上报统计数据,需要专业人员进行分析。
    

    大家看到上面的解释,基本理解这个方案 高大上,有使用门槛,数据分析需要专业度人员分析 无埋点虽然可以对数据做提前收录,以防未来所需,但全数据,在页面上报与数据存储,都会对页面性能与数据库增加压力。 最大的一个问题,就是无法个性化定制上传的数据

    此方案更多的贴合一线公司去实施落地


    前端页面监控

    性能监控
    性能监控指的是监听前端的性能,主要包括监听网页或者说产品在用户端的体验。常见的性能监控项包括:
    1.不同用户,不同机型和不同系统下的首屏加载时间
    2.白屏时间
    3.http 等请求的响应时间
    4.静态资源整体下载时间
    5.页面渲染时间
    6.页面交互动画完成时间
    

    performance.timing api 可以获取浏览器在加载 -》渲染完成 的事件流程。

    封装sdk上报,针对需要收录的页面,直接嵌入js 代码,统计分析页面性能。

    在线检测工具

    Chrome工具:lighthouse

    六大指标

    前端埋点抽离方案与异常监控 可在线检测生成文档,同时提供优化具体方向,看一下检测的六大指标

    1.First Contentful Paint: It marks the time at which the first text or image is painted.
    第一个内容丰富的绘画:它标记了第一个文本或图像的绘画时间。
    2.Speed Index: It shows how quickly the contents of a page are visibly populated.
    速度索引:显示页面内容的可见速度。
    3.Largest Contentful Paint: It marks the time at which the largest text or image is painted.
    内容最大的涂料:它标记了最大的文字或图像的绘制时间。
    4.Time to Interactive: It is the amount of time it takes for the page to become fully interactive.
    互动时间:页面完全互动所花费的时间。
    5.Total Blocking Time: It is the sum of all time periods between First Contentful Paint and Time to Interactive.
    总阻止时间:这是“第一个内容丰富的绘画”与“互动时间”之间的所有时间段的总和。
    6.Cumulative Layout Shift: It measures the movement of visible elements within the viewport.
    累积布局偏移:它测量视口内可见元素的移动
    
    评分区间:【0-49(红色):较差】 【50-89(橙色):需要改进】 【90-100(绿色):良好】
    具体的优化方案
    可根据检测报告,有目的的进行网站优化提升
    

    前端埋点抽离方案与异常监控

    错误日志收集

    常规脚本错误

        /**
         * @description window.onerror 全局捕获错误
         * @param event 错误信息,如果是
         * @param source 错误源文件URL
         * @param lineno 行号
         * @param colno 列号
         * @param error Error对象
         */
        window.onerror = function (event, source, lineno, colno, error) {
          // 上报错误
          // 如果不想在控制台抛出错误,只需返回 true 即可
        };
        
        
        //VS
        
        window.addEventListener('error', (event) => {
          // addEventListener 回调函数的离散参数全部聚合在 error 对象中
          // 上报错误
        }, true)
        
        
    

    Promise 错误

        window.addEventListener('unhandledrejection', (event) => {
          console.log(event)
        }, true);
        
        
        // rejectionhandled 
        window.addEventListener('rejectionhandled', (event) => {
          console.log(event)
        }, true);
        
        
      // 备选处理方案 window.onunhandledrejection / window.onrejectionhandled 
    
    

    框架错误

    Vue.config.errorHandler = function (err, vm, info) {
        // 框架级别的捕获错误
        // 拦截分析 但不吞并,直接在丢出去,再接入日志监控服务统一上报入口进行上报。
        // 例如 console.err(err) 再次抛出错误
    }
    

    请求错误监控

    前端请求方案基本上就两种: ajax fetch,针对两种方式进行统一重写代理

    大家常用的 axios ,只需在请求拦截器以及响应拦截器进行处理上报即可

    axiosHttp.interceptors.response.use(
      response => {
        let resData
        if (response.code === 1000) {
          resData = response.data ? response.data : response
        } else {
          throw resData
        }
        return resData
      },
      error => {
        throw error
      }
    )
    

    资源错误监控

    资源错误监控本质上和常规脚本错误监控一样,都是监控错误事件实现错误捕获
    脚本错误参数对象 instanceof ErrorEvent,而资源错误的参数对象 instanceof Event
    由于 ErrorEvent 继承于 Event ,所以不管是脚本错误还是资源错误的参数对象都 instanceof Event
    优先判断脚本错误即可区分
    
      window.addEventListener('error', (event) => {
        if (event instanceof ErrorEvent) {
          console.log('脚本错误')
        } else if (event instanceof Event) {
          console.log('资源错误')
        }
      }, true) // 回调函数是否在捕获阶段执行,默认是false,在冒泡阶段执行
    
    日志服务在后端开发中必不可少,但在前端领域,日志服务,基本只存在于node服务承接一些微服务聚合业务的异常监控
    其次前端异常问题,要比中间层错误更难捕获,不同机型,不同业务场景,很奇怪的业务边界。不可预期性,不可控制的设备 硬件,都会存在影响。日志的收集,可为排查问题带来更多的可能性
    日志仍然是洞察力的主要来源
    成熟日志库,可以借鉴日志库结合本身业务需求进行包装

    log4js

    Loggerr


    起源地下载网 » 前端埋点抽离方案与异常监控

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元