当前位置: 首页 > news >正文

前端监控之用户行为监控实践1(数据收集)

前文对前端监控进行了简单介绍,起因是因为当前做的一个需求,老板要看当前项目的uv、pv信息。其实这是非常简单的统计。 但在最开始接到这个需求,却难倒我了。 现在进行简单的复盘,记录一下实现方法。 

一、数据记录

用户行为从大类上主要分为两个方面:

① 页面浏览行为 ② 操作行为

统一埋点函数

基于此共识,首先封装一个统一的埋点函数,代码如下:

export const captureMessage = async (type: 'browse' | 'action', content: string, title?: string) => {// 省略了判断开发环境时,在本地打印的代码const data = { type, content, title };// 这里调用的是统一封装的请求函数await post('userlog', data, { 'Content-Type': 'application/json; charset=utf-8' });
};

然后,采用的埋点方式,是在上文中提到的(前端监控简介_艾米栗写代码的博客-CSDN博客)手动埋点。 

页面浏览埋点

我们最初的埋点比较简单,主要是对 url 的埋点。而在 vue 中,url 的跳转主要是通过路由实现的,因此,只需要在全局检测路由的变化。代码如下:

    watch(() => route.fullPath, () => {const title = (route.meta?.title ?? '') as stringconst url: string = (route as any).fullPath || route.pathcaptureMessage('browse', url, title)})

操作行为埋点  

而操作行为的埋点同理,只需在需要监控的操作事件响应函数中,插入captureMessage 函数即可。

二、打补丁

问题分析

以上是我们最开始的记录方式,原则上,这样记录是能够满足后续的分析需求的。

注意,这也只是理论上可行。 但后续,产品提出要分析某个页面下不同子页面的pv、uv 情况。但项目当前的情况是,这个页面下的URL极其混乱,无法进行统一分析。为了满足分析需要,需要对这个页面下的 URL 进行统一化。

具体说来,页面的URL 为 /report。

进来之后的初始页面默认为子页面 1,这里我们设 子页面1名称为 table1.

在切换报表时,其 URL 会响应为子页面名称 ,即 /report/tableName。

但除此之外,该页面下还存在另外三种URL类型。

类型1:ID 类的 URL 是报表最开始的迭代方式,其ID 为 数字,即 /report/numberID

类型2:模板类的URL 记录的是,某一子页面下的用户选择项。其模板ID通过MD5生成,URL 为: /report/templateID。

类型3:具体信息类,从其他页面跳转到该子页面,携带的是具体请求信息。其URL 为:

/report?query=***(query 为对象,进行 encode 编码)

为了满足报表统计的需要,需要对不同URL进行统一,而统一的方式为,在 当前URL 的后面,加上 /table/tableName 。

即:

/report --> /report/table1

/report/tableName --> /report/tableName (保持不变)

/report/numberID --> /report/numberID/table/tableName 

/report/templateID --> /report/templateID/table/tableName

/report?query=*** --> /report?query=***/table/tableName

numberID和 templateID 对应的tableName在对应的数据库中可以查询到。

描述完了要做的事情,上代码咯!

问题解决(补丁)

代码

export const getEventTableUrl = async (content:string) => {let table = ''const eventUrl = content.replace('/report', '')// 情况1: content 为 report/table/tableNameif(eventUrl.startsWith('/table')){table = ''}else if(eventUrl === '') {// 情况2: content 仅为: /report    table = DEFAULT_QUERY_TABLE}else if(eventUrl.includes('?')) {// 情况3: content 为:/report?query=*** 参数中有query,解析query 参数获得queryKey// 匹配query参数const matchContent = eventUrl.match(/[?&]query=([^&/]*)&?/)table = getTableFromQuery(matchContent ? matchContent[1] : '')}else {// 情况4:content为:/report/***(id) 从模板id 或 eventid 中获得querykeytable = await getTableFromTemplate(eventUrl.split('/')[1])}if(!table) return content;return `${content}/table/${table}`
}

统一代码过程中,有两个小细节花费了较多时间。 

细节1: 拿到 URL 中的 query 参数内容

如何拿到get 请求中的参数信息,这是一个老生长谈的话题了。解决方法也是多种多样,在网上一搜,有人暴力破解和匹配的,有人调用函数的,有人用正则的。

比如: JavaScript 正则表达式获取url后的内容(第一个问号后的内容)_白菜new的博客-CSDN博客

而我,最开始的想法是,寻找 node 中是否提供了通用的解决方案。

哎嘿,还真的有:

MDN官方文档:

URL API - Web APIs | MDN

来自鑫旭大佬的详细介绍:

JS URL()和URLSearchParams() API接口详细介绍 « 张鑫旭-鑫空间-鑫生活

实例代码如下: 

//截取问号之后的字符串
const search = eventUrl.match(/\?(\S*)/) 
// 获取query参数
const queryParam = new URLSearchParams(search ? search[0] : '').get('query')

 但是,我们组长在review 这段代码之后,他觉得,这样不够简洁,应该直接用正则进行匹配。。。

于是,迫于”强权“之下代码变成了这样

eventUrl.match(/[?&]query=([^&/]*)&?/)

虽然正则看起来很简洁,可是,大家的正则水平真的能一眼看懂这行代码是在干嘛么???

我经验少,咱也不知道是不是自己太菜,我只能加上注释为后来的人默默助力。。。

 但是呢,一味抗拒对于自己的成长是不利的,在此之下,我还是对正则进行了一番研究。

我发现,正则可以在 match、replace 等都可以使用。

可参考文章: 正则表达式和字符串的方法

细节2: 解析 query 参数

在解析上面提到的带有 query 参数的 URL 时,发生了两个意外情况。

1、无法解码

前端基础-encodeURIComponent原理 | 华仔的博客

2、无法将string转化为对象

这是因为,用户可以对url进行编辑,这就有可能导致,记录的query 可能信息不全。甚至query中有一些会解析出错的消息,比如说,有一些无法解码的 + 号。

因此,在解码和转化为对象的时候,需要进行错误捕获。

/** 解析string为json */
export const parseString = (str:string): Record<string,any>| null => {try {return JSON.parse(str)} catch {return null}
}/** 解析 URI */
export const decodeUri = (uri: string) => {try {return decodeURIComponent(uri)} catch {return ''}
}

 通过以上的方式,我们就可以统计到需要进行数据分析的元信息了。

接下来就是进行数据分析了。

三、统计信息

这一部分我将用另外的篇幅去总结。

相关文章:

前端监控之用户行为监控实践1(数据收集)

前文对前端监控进行了简单介绍&#xff0c;起因是因为当前做的一个需求&#xff0c;老板要看当前项目的uv、pv信息。其实这是非常简单的统计。 但在最开始接到这个需求&#xff0c;却难倒我了。 现在进行简单的复盘&#xff0c;记录一下实现方法。 一、数据记录 用户行为从大…...

【网络原理7】认识HTTP

目录 一、HTTP协议的位置 二、HTTP协议的特点&应用场景 三、HTTP协议的格式的查看 Fiddler下载与使用 ​编辑 如何查看HTTP请求消息 ​编辑 如何查看HTTP响应数据包 如何默认开启HTTPS的解析功能 四、HTTP的请求数据包的格式含义 第一部分&#xff1a;请求行&…...

SPI实验

目录 一、SPI 简介 二、硬件原理 ECSPI3_SCLK ECSPI3_MISO和ECSPI3_MOSI ECSPI3_SS0 三、I.MX6U ECSPI 简介 ECSPIx_RXDATA ECSPIx_TXDATA ECSPIx_CONREG ECSPIx_CONFIGREG ECSPIx_PERIODREG​编辑 ECSPIx_STATREG 四、ICM-20608 简介 五、代码编写 1、创建文件及文…...

去基线处理

目录detrend函数去除基线多项式拟合原函数BEADS 基线处理小波算法经验模态分解&#xff08;EMD&#xff09;参考detrend函数去除基线 detrend函数只能用于去除线性趋势&#xff0c;对于非线性的无能为力。 函数表达式&#xff1a;y scipy.signal.detrend(x): 从信号中删除线…...

模拟信号4-20mA /0-5V/0-75mV/0-100mV转RS-485/232,数据采集A/D转换模块 YL21

特点&#xff1a;● 模拟信号采集&#xff0c;隔离转换 RS-485/232输出● 采用12位AD转换器&#xff0c;测量精度优于0.1%● 通过RS-485/232接口可以程控校准模块精度● 信号输入 / 输出之间隔离耐压3000VDC ● 宽电源供电范围&#xff1a;8 ~ 32VDC● 可靠性高&#xff0c;编程…...

[USB]键盘数据格式以及按键键值

USB键盘数据包含8个字节 BYTE1 – 特殊按键 |–bit0: Left Control是否按下&#xff0c;按下为1 |–bit1: Left Shift 是否按下&#xff0c;按下为1 |–bit2: Left Alt 是否按下&#xff0c;按下为1 |–bit3: Left GUI&#xff08;Windows键&#xff09; 是否按下&#xff0c;…...

web客户端-websocket

1、websocket简介 WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c…...

mysql间隙锁

首先我们这里有一个表t&#xff0c;其中的数据如下图所示 注意哈 update由于操作的最新的值&#xff0c;所以是当前读&#xff01; 另外一个事务插入 8的时候发生锁 而我对id为10的数据进行更新&#xff0c;却不会被锁住 分析&#xff1a;在执行当前读时&#xff0c;由于id7不存…...

华为OD机试 - 计算面积(Java) | 机试题+算法思路+考点+代码解析 【2023】

计算面积 绘图机器的绘图笔初始位i在原点(0.0)。 机器启动后其绘图笔按下面规则绘制直线: 1 )尝试沿着横向坐标轴正向绘制直线,直到给定的终点值E, 2 )期间可通过指令在纵坐标轴方向进行偏移。井同时绘制直线,偏移后按规则1绘制直线;指令的格式为X offsetY。表示在横坐标X…...

Python 之 Pandas 时间戳、通过时间间隔实现 datetime 加减、时间转化、时期频率转换和 shift() 时间频率进行移位)

文章目录一、时间戳1. unit 参数是 s2. year、month、day、hour、minute、second、microsecond 单独设置时间二、通过时间间隔实现 datetime 加减三、时间转化1. 处理各种输入格式2. 将字符串转 datetime3. 除了可以将文本数据转为时间戳外&#xff0c;还可以将 unix 时间转为时…...

一篇文章搞定linux网络模型

网络协议感觉晦涩难懂&#xff1f;什么七层网络模型&#xff1f;又五层网络模型&#xff1f;又四层网络模型&#xff1f;TCP/IP协议是个啥&#xff1f;UDP是啥&#xff1f;什么是三次握手&#xff1f;什么是四次挥手&#xff1f;tcpdump听说是抓包的&#xff0c;怎么用&#xf…...

惠普庆祝在中国40年,强化中国发展战略

中国北京&#xff0c;2023年2月23日 ——今日&#xff0c;“品质信赖向未来” 惠普在中国40年系列活动启动仪式及惠普打印春季新品发布会在北京盛大举行。现场&#xff0c;惠普回顾了40年来与中国经济及产业共同发展的历程&#xff0c;并再次强调了惠普一以贯之的“在中国&…...

C++小作业

前言&#xff1a;long long time ago&#xff0c;老大留了点小作业&#xff0c;一直忘了写…偷偷补上 小作业目录unique_ptr vs shared_ptrunique_ptrshared_ptrpublisher/subscriber 1?boost::bindstd::bindthis? _1&#xff1f;TopicContextPtr?std::moveunique_ptr vs sh…...

Python基础 — lambda匿名函数

1、什么是匿名函数&#xff1f; 匿名函数&#xff0c;顾名思义&#xff0c;就是没有名字的函数&#xff0c;它主要用在那些只使用一次的场景中。如果我们的程序中只需要调用一次某个简单逻辑&#xff0c;把它写成函数还需要先定义、取函数名字等一些列操作&#xff0c;这种场景…...

MongoDB安装和使用过程常见问题

文章目录一、安装过程显示没有相应的权限二、pymongo无法使用&#xff0c;报错一、安装过程显示没有相应的权限 oh我的天&#xff0c;找了网上很多种方法都不行哈哈 不同的电脑对应不同的问题吧~ 我的这个问题是这样解决滴 先直接简述操作路径&#xff0c;不明白的可以看如下图…...

AWS攻略——使用中转网关(Transit Gateway)连接同区域(Region)VPC

文章目录环境准备创建VPC配置中转网关给每个VPC创建Transit Gateway专属挂载子网创建中转网关创建中转网关挂载修改VPC的路由验证创建业务Private子网创建可被外网访问的环境测试子网连通性Public子网到Private子网Private子网到Private子网知识点参考资料在《AWS攻略——Peeri…...

Rouge | 自动文摘及机器翻译评价指标

tag:评价指标,摘要,nlp Rouge(Recall-Oriented Understudy for Gisting Evaluation)&#xff0c;是评估自动文摘以及机器翻译的一组指标。它通过将自动生成的摘要或翻译与一组参考摘要&#xff08;通常是人工生成的&#xff09;进行比较计算&#xff0c;得出相应的分值&#x…...

【Python入门第十五天】Python字典

字典&#xff08;Dictionary&#xff09; 字典是一个无序、可变和有索引的集合。在 Python 中&#xff0c;字典用花括号编写&#xff0c;拥有键和值。 实例 创建并打印字典&#xff1a; thisdict {"brand": "Porsche","model": "911&q…...

java学习思路

基础概念&#xff1a;了解Java的基本概念&#xff0c;如Java虚拟机&#xff08;JVM&#xff09;、Java标准版&#xff08;Java SE&#xff09;、Java企业版&#xff08;Java EE&#xff09;等。了解Java的版本、发展历程以及Java应用场景。可以通过阅读Java官方文档、相关书籍、…...

MySQL操作数据库-------创建数据库

搭建好MySQL环境后&#xff0c;现在我们正式的进入到MySQL的学习当中&#xff0c;这篇文章讲述如何去创建MySQL数据库。 1. 使用CREATE DATABASE创建数据库 语法格式&#xff1a;CREATE DATABASE database_name eg.打开MySQL命令行&#xff0c;查看当前MySQL中存在的数据库 my…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散

前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说&#xff0c;在叠衣服的过程中&#xff0c;我会带着团队对比各种模型、方法、策略&#xff0c;毕竟针对各个场景始终寻找更优的解决方案&#xff0c;是我个人和我司「七月在线」的职责之一 且个人认为&#xff0c…...