前端监控学习笔记

news2025/6/8 20:35:20

现成的SDK

  • Sentry
  • Fun Debug

需要监控什么?

  • 错误统计
    记录我们代码发布到线上各种奇奇怪怪的错误

  • 行为日志埋点
    记录用户行为,比如:分析用户浏览时间比较长的页面有哪些,常常点击的有哪些,可以做 相应的推荐

  • PV/UV统计
    记录用户访问页面的次数
    PV:访问的操作的次数,UV:访问页面的用户多少

前端监控的主要流程:
在这里插入图片描述

功能拆分

在这里插入图片描述

错误监控

错误监控,即当代码发生错误时,比如,同步错误,异步错误,promise错误,资源加载错误时,我们需要捕获到错误,然后上报给后端。

上报到后端简单,发送请求即可。那如何捕获到错误,我们下面进行讨论:

错误类型

  1. 语法错误

    语法错误一般在可发阶段就可以发现,比如常见的单词拼写错误,中英文符号错误等。注意:语法错误是无法被try catch捕获的,因为在开发阶段就能发现,所以一般不会发布到线上环境。

    try {
      let name = 'heima; // 少一个单引号
      console.log(name);
    } catch (error) {
      console.log('----捕获到了语法错误-----');
    }
    
  2. 同步错误

    同步错误指的是在js同步执行过程中的错误,比如变量未定义,是可以被try catch给捕获到的

    try {
      const name = 'heima';
      console.log(nam);
    } catch (error) {
      console.log('------同步错误-------')
    }
    
  3. 异步错误

    异步错误指的是在setTimeout等函数中发生的错误,是无法被try catch捕获到的

    try {
      setTimeout(() => {
        undefined.map();
      }, 0);
    } catch (error) {
      console.log('-----异步错误-----')
    }
    

    异步错误的话我们可以用window.onerror来进行处理,这个方法比try catch要强大很多

    /**
     * @param {String}  msg    错误描述
     * @param {String}  url    报错文件
     * @param {Number}  row    行号
     * @param {Number}  col    列号
     * @param {Object}  error  错误Error对象
     */
     window.onerror = function (msg, url, row, col, error) {
       console.log('出错了!!!');
       console.log(msg);
       console.log(url);
       console.log(row);
       console.log(col);
       console.log(error);
    };
    
  4. promise错误

    promise 中使用 catch 可以捕获到异步的错误,但是如果没有写 catch 去捕获错误的话 window.onerror 也捕获不到的,所以写 promise 的时候最好要写上 catch ,或者可以在全局加上 unhandledrejection 的监听,用来监听没有被捕获的promise错误。

    window.addEventListener("unhandledrejection", function(error){
      console.log('捕获到异常:', error);
    }, true);
    
  5. 资源加载错误

    资源加载错误指的是比如一些资源文件获取失败,可能是服务器挂掉了等原因造成的,出现这种情况就比较严重了,所以需要能够及时的处理,网路错误一般用 window.addEventListener 来捕获。

    window.addEventListener('error', (error) => {
      console.log(error);
    }, true);
    

用户埋点统计

埋点就是需要记录用户的某些行为,比如点击按钮,我们需要记录用户点击了哪个按钮,然后进行上报。这样做的作用是,我们得到的数据可以进行一些分析。PS:淘宝首页分类,需要知道哪个分类点击次数最多,即哪个分类最火。

手动埋点

手动埋点就是手动的去出发上报函数

// 方式1
<button
  onClick={() => {
    // 业务代码
  	tracker('click', '用户去支付');
    // tracker('visit', '访问新页面');
    // tracker('submit', '提交表单');
  }}
>手动埋点</button>
// 方式2
<button 
	data-target="支付按钮"
	onClick={() => {
    // 业务代码
  }}
>手动上报</button>
  • 优点:可控性强,可以自定义上报具体的数据。
  • 缺点:对业务代码侵入性强,如果有很多地方需要埋点就得一个一个手动的去添加埋点代码。

无痕埋点

无痕埋点是为了解决手动埋点的缺点,实现一种不用侵入业务代码就能在应用中添加埋点监控的埋点方式。

<button onClick={() => {
  // 业务代码
}}>自动埋点</button>
// 自动埋点实现
function autoTracker () {
  // 添加全局click监听
  document.body.addEventListener('click', function (e) {
    const clickedDom = e.target;
    // 获取data-target属性值
    let target = clickedDom?.getAttribute('data-target');
    if (target) {
      // 如果设置data-target属性就上报对应的值--手动埋点
      tracker('click', target);
    } else {
      // 如果没有设置data-target属性就上报被点击元素的html路径
      const path = getPathTo(clickedDom);
      tracker('click', path);
    }
  }, false);
};
  • 优点:不用侵入务代码就能实现全局的埋点。
  • 缺点:只能上报基本的行为交互信息,无法上报自定义的数据;上报次数多,服务器性能压力大。

PV统计

  • history路由

    history路由是由window.histroy api来实现的:
    - istory.back(); // 返回上一页,和浏览器回退功能一样
    - history.forward(); // 前进一页,和浏览器前进功能一样
    - history.go(); // 跳转到历史记录中的某一页,
    - history.pushState(); // 添加新的历史记录
    - history.replaceState(); // 修改当前的记录项

/**
 * 重写pushState和replaceState方法
 * @param {*} name 
 * @returns 
 */
const createHistoryEvent = function (name) {
  // 拿到原来的处理方法
  const origin = window.history[name];
  return function(event) {
    if (name === 'replaceState') {
      const { current } = event;
      const pathName = location.pathname;
      if (current === pathName) {
        let res = origin.apply(this, arguments);
        return res;
      }
    }

    let res = origin.apply(this, arguments);
    let e = new Event(name);
    e.arguments = arguments;
    window.dispatchEvent(e);
    return res;
  };
};

window.history.pushState = createHistoryEvent('pushState');
window.history.replaceState = createHistoryEvent('replaceState');

function listener() {
  const stayTime = getStayTime(); // 停留时间
  const currentPage = window.location.href; // 页面路径
  lazyReport('visit', {
    stayTime,
    page: beforePage,
  })
  beforePage = currentPage;
}

// history.go()、history.back()、history.forward() 监听
window.addEventListener('popstate', function () {
  listener()
});

// history.pushState
window.addEventListener('pushState', function () {
  listener()
});

// history.replaceState
window.addEventListener('replaceState', function () {
  listener()
});	

history路由无法监听到pushState和replaceState,所以我们冲洗了一个方法,并用windows.dispatch创建了一个自定义监听事件。

  • hash路由
    url上hash的改变会出发 hashchange 的监听,所以我们只需要在全局加上一个监听函数,在监听函数中实现采集并上报就可以了。但是在react和vue中,对于hash路由的跳转并不是通过 hashchange 的监听实现的,而是通过 pushState 实现,所以,还需要加上对 pushState 的监听才可以。
export function hashPageTrackerReport() {
  let beforeTime = Date.now(); // 进入页面的时间
  let beforePage = ''; // 上一个页面
  
  // 上报
  function listener() {
    const stayTime = getStayTime();
    const currentPage = window.location.href;
      lazyReport('visit', {
      stayTime,
      page: beforePage,
    })
    beforePage = currentPage;
  }

  // hash路由监听
  window.addEventListener('hashchange', function () {
    listener()
  });
}

UV统计

在SDK初始化的时候,上报即可

UV统计的是一天内访问该网站的用户数

/**
 * 初始化配置
 * @param {*} options 
 */
function init(options) {
  ... // 加载配置
  report('user', '加载应用'); // uv统计
}

合并上报

对于无痕埋点来说,一次点击就进行一次上报,会对服务器造成很大的压力,所以我们需要合并一下请求

// cache.js
const cache = [];

export function getCache() {
  return cache;
}

export function addCache(data) {
  cache.push(data);
}

// lazyReport.js
export function lazyReport(type, params) {
  // ....
  const data = getCache();

  if (delay === 0) { // delay=0相当于不做延迟上报
    report(data);
    return;
  }

  if (data.length > 10) { // 数据达到10条上报
    report(data);
    clearTimeout(timer);
    return;
  }

  clearTimeout(timer);
  timer = setTimeout(() => { // 合并上报
    report(data);
  }, delay);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1278444.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

管理类联考-性质

性质 ——性质—— 一、是什么 &#xff08;1&#xff09;本质&#xff1a;判断一定范围内的对象是否具备某个性质的命题就是性质命题&#xff08;直言命题&#xff09;。直言命题是断定事物/对象是否具有某种性质的命题。直言命题在结构上由主项、谓项、联项和量项组成。 &am…

【ArcGIS Pro微课1000例】0039:制作全球任意经纬网的两种方式

本文讲解在ArcGIS Pro中制作全球任意经纬网的两种方式。 文章目录 一、生成全球经纬网矢量1. 新建地图加载数据2. 创建经纬网矢量数据二、布局生成经纬网1. 新建布局2. 创建地图框2. 创建经纬网一、生成全球经纬网矢量 以1:100万比例尺地图分幅为例,创建经差6、维差4的经纬网…

<软考>软件设计师-1计算机组成与结构(总结)

(一)计算机系统基础知识 1 计算机硬件组成 计算机的基本硬件系统由运算器、控制器、存储器、输入设备 和 输出设备 5大部件组成。 1 运算器、控制器等部件被集成在一起统称为中央处理单元(CPU) 。CPU是硬件系统的核心&#xff0c;用于数据的加工处理&#xff0c;能完成各种算…

gitlab高级功能之容器镜像仓库

今天给大家介绍一个gitlab的高级功能 - Container Registry&#xff0c;该功能可以实现docker镜像的仓库功能&#xff0c;将gitlab上的代码仓的代码通过docker构建后并推入到容器仓库中&#xff0c;好处就是无需再额外部署一套docker仓库。 文章目录 1. 参考文档2. Container R…

mybatis数据输入-Map类型参数输入

1、建库建表 CREATE DATABASE mybatis-example;USE mybatis-example;CREATE TABLE t_emp(emp_id INT AUTO_INCREMENT,emp_name CHAR(100),emp_salary DOUBLE(10,5),PRIMARY KEY(emp_id) );INSERT INTO t_emp(emp_name,emp_salary) VALUES("tom",200.33); INSERT INTO…

P1 嵌入式开发之什么是Linux应用开发

目录 前言 01 .Linux应用与裸机编程、驱动编程之间的区别 1.1裸机编程&#xff1a; 1.2 驱动编程 1.3应用编程 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&a…

波奇学C++:智能指针(二):auto_ptr, unique_ptr, shared_ptr,weak_ptr

C98到C11&#xff1a;智能指针分为auto_ptr, unique_ptr, shared_ptr&#xff0c;weak_ptr,这几种智能都是为了解决指针拷贝构造和赋值的问题 auto_ptr&#xff1a;允许拷贝&#xff0c;但只保留一个指向空间的指针。 管理权转移&#xff0c;把拷贝对象的资源管理权转移给拷贝…

Centos7.9搭建zabbix6.4.0过程及报错注意点

搭建参考此链接即可&#xff1a;https://blog.csdn.net/PerDrix/article/details/129624091 报错整理&#xff1a; 一、zabbix6.0以上版本默认必须安装mysql 8.0.30以上版本数据库&#xff0c;否则服务起不来 二、编译安装zabbix时&#xff0c;必须执行如下操作&#xff0c;…

LeetCode算法题解(动态规划)|LeetCode1143. 最长公共子序列、LeetCode1035. 不相交的线、LeetCode53. 最大子数组和

一、LeetCode1143. 最长公共子序列 题目链接&#xff1a;1143. 最长公共子序列 题目描述&#xff1a; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一…

四、设置主机名和域名映射

目录 1、配置每台虚拟机主机名 2、配置每台虚拟机域名映射 1、配置每台虚拟机主机名

Unity对接后台和加载图片

1、前言 在unity中与后台对接&#xff0c;用await在web端暂时还不支持&#xff0c;所以&#xff0c;协程成为比较好的通用方式&#xff0c;以下适用除post访问外的所有对接 2、对接后台 2.1、安装插件 首先我们需要用到Newtonsoft.dll&#xff0c;如果没有这个.dll的请跟着我…

vue权限管理解决方案

一. 什么是权限管理 权限控制是确保用户只能访问其被授权的资源和执行其被授权的操作的重要方面。而前端权限归根结底是请求的发起权&#xff0c;请求的发起可能有下面两种形式触发 页面加载触发页面上的按钮点击触发 总体而言&#xff0c;权限控制可以从前端路由和视图两个…

QProcess 启动 进程 传参数 启动控制台进程 传参

目录 QProcess 启动外部程序的两种方式 依赖式 分离式&#xff1a; 启动进程前的预处理 设置启动路径 设置启动命令参数 设置启动工作目录 设置启动所需环境&#xff1a; 启动的状态 code smple: QProcess 控制台进程 QProcess启动控制台不显示窗口 注意&#xff1a;…

jvm基本概念,运行的原理,架构图

文章目录 JVM(1) 基本概念:&#xff08;2&#xff09;运行过程 今天来和大家聊聊jvm&#xff0c; JVM (1) 基本概念: JVM 是可运行Java代码的假想计算机&#xff0c;包括一套字节码指令集、一组寄存器、一个栈一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作…

9.ROS的TF坐标变换(三):坐标系关系查看与一个案例

1 查看目前的坐标系变化 我们先安装功能包&#xff1a; sudo apt install ros-melodic-tf2-tools安装成功&#xff01; 我们先启动上次的发布坐标变换的节点&#xff1a; liuhongweiliuhongwei-Legion-Y9000P-IRX8H:~/Desktop/final/my_catkin$ source devel/setup.bash liuho…

cyclictest 交叉编译与使用

目录 使用版本问题编译 numactl编译 cyclictest使用参考 cyclictest 主要是用于测试系统延时&#xff0c;进而判断系统的实时性 使用版本 rt-tests-2.6.tar.gz numactl v2.0.16 问题 编译时&#xff0c;需要先编译 numactl &#xff0c;不然会有以下报错&#xff1a; arm-…

Linux:优化原则

web系统的优化原则&#xff1a; 从单机到集群 对Linux系统自身的优化原则&#xff1a;

TCP报文解析

1.端口号 标记同一台计算机上的不同进程 源端口&#xff1a;占2个字节&#xff0c;源端口和IP的作用是标记报文的返回地址。 目的端口&#xff1a;占2个字节&#xff0c;指明接收方计算机上的应用程序接口。 TCP报头中的源端口号和目的端口号同IP报头中的源IP和目的IP唯一确定一…

【QT】Windows环境下,cmake引入QML

这里使用的QT库为5.7版本。 1、添加环境变量 QT库根目录环境变量 QTDIR QT库平台插件环境变量 QT_PLUGIN_PATH QML支持环境变量 QML2_IMPORT_PATH &#xff08;该环境变量仅在需要使用QML时添加&#xff09; QT库动态库环境变量&#xff0c;bin目录下包含了QT程序运行所需的dl…

电子学会C/C++编程等级考试2022年03月(四级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:拦截导弹 某国为了防御敌国的导弹袭击, 发展出一种导弹拦截系统。 但是这种导弹拦截系统有一个缺陷: 虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。 某天, 雷达捕捉到敌国的导弹来袭。…