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

阿里云日志服务之WebTracking 小程序端 JavaScript SDK (阿里SDK埋点和原生uni.request请求冲突问题)

目录标题

  • 1、官方文档
  • 2、安装和配置sdk
  • 3、自定义封装埋点事件,进行日志上报

1、官方文档

阿里云日志服务官方文档

2、安装和配置sdk

npm install --save @aliyun-sls/web-track-mini

使用下面方式,既能解决请求冲突问题,又不会丢失日志信息

// webTracker.js
import SlsTracker from '@aliyun-sls/web-track-mini'
import {logFlag
} from '@/utils/logger.js'
import {AppState
} from '@/utils/globalState.js';
export default class webTracker {/**** @param slsConfig 阿里云上传参数* @param publicParam 项目标准公参* @param projectArgs 项目个性化公参*/constructor(slsConfig, publicParam = {}, projectArgs = {}) {// this.tracker = new SlsTracker(slsConfig)// logFlag && console.log('创建SlsTracker对象this.tracker:',this.tracker)// 800ms延迟确保普通请求优先处理// 避免SLS初始化期间拦截有效请求:当SLS初始化未完成时,直接调用uni.request会导致请求丢失setTimeout(() => {this.tracker = new SlsTracker({...slsConfig,// opt:接收完整的uni.request配置对象(含url/method/data等)// 通过call(uni)显式绑定uni-app运行环境,避免this指向错误// 强制所有SLS日志请求通过uni-app原生方法发出,确保上下文绑定和参数透// 严格兼容uni-app环境‌时(如小程序、H5混合开发),必须使用自定义request配置,在‌纯浏览器环境‌或对请求无特殊要求时,可省略该配置// 如果不使用request配置将导致:SDK初始化阶段请求方法未就绪导致的调用失败||跨平台运行时出现的this指向混乱 || 特殊header或参数被SDK默认实现过滤// _originalRequest:指向‌备份的原始请求方法‌(通常是对 uni.request 的引用)// 头函数 (opt) => _originalRequest.call(uni, opt) 会 ‌继承外层作用域的变量‌(即模块作用域中的 _originalRequest),无需额外处理request: (opt) => _originalRequest.call(uni, opt)});AppState.setSLSReady(true); // 更新全局状态this._flushQueue();}, 800);this._queue = []; // 日志暂存队列// 项目标准公参// 保留字段系日志服务自动生成,无需进行埋点 (日志来源、上报时间、主题、分区时间、其它日志字段)this.params = {// log_source: '', // 日志来源// log_time: Math.floor(Date.now() / 1000), // 日志上报时间// log_topic: '', // 日志主题// log_partition_time: 'null', // 分区时间// log_extract_others: '', // 其他日志字段...publicParam}// 项目个性化公参this.args = {...projectArgs}}/*** 更新参数* @param publicParam 项目标准公参* @param projectArgs 项目个性化公参*/updateParam(publicParam = {}, projectArgs = {}) {this.params = {...this.params,...publicParam,}this.args = {...this.args,...projectArgs}}// 改造send方法(关键修改)send(params, args) {const sendParam = this._buildParams(params, args);if (AppState.slsReady) {this.tracker.sendImmediate(sendParam);} else {this._queue.push({type: 'single',data: sendParam});}}// 改造sendBatch方法(关键修改)sendBatch(arr) {const batchParams = arr.map(item => this._buildParams(item));if (AppState.slsReady) {this.tracker.sendBatchLogsImmediate(batchParams);} else {this._queue.push({type: 'batch',data: batchParams});}}// 新增私有方法_buildParams(params, args = {}) {let allParams = {...this.params,...params,args: JSON.stringify({...this.args,...args,...params.args,})};logFlag && console.log(`***当前${allParams.event_name}事件日志上报数据allParams***:`, allParams)return allParams}_flushQueue() {this._queue.forEach(item => {item.type === 'single' ?this.tracker.sendImmediate(item.data) :this.tracker.sendBatchLogsImmediate(item.data);});this._queue = [];}/*** 点击事件*/click(params, args) {this.send(params, args)}/*** 发送统计事件*/// send(params, args) {// 	//项目标准公参,埋点事件相关字段,项目个性化公参,埋点事件相关args字段//    let sendParam =  this._buildParams(params, args);//    logFlag && console.log('发送统计事件sendParam:',sendParam)//    this.tracker.sendImmediate(sendParam)// }/*** 组合发送统计事件*/// sendBatch(arr) {//     let batchParams = arr.map(item => this._buildParams(item));// 	logFlag && console.log('组合发送统计事件batchParams:',batchParams)//     this.tracker.sendBatchLogsImmediate(batchParams)// }}
// globalState.js
// 导出一个全局状态管理对象 AppState
export const AppState = {// SLS(日志服务)就绪状态标志位,默认false表示未就绪slsReady: false,  // 替代旧变量 _slsReady,命名更规范// 设置SLS就绪状态的方法setSLSReady(value) {// 更新当前对象的slsReady状态this.slsReady = value;// 通过uni-app的事件总线触发全局事件// 参数说明:// - 'sls-ready': 事件名称,其他组件可监听此事件// - value: 传递的状态值(true/false)uni.$emit('sls-ready', value); }
};
// request.js
// 在ES6模块(import/export)中,顶层变量(非函数内部声明)默认具有 ‌模块级作用域‌,即同一模块内的所有代码均可访问,且不会污染全局命名空间
// 保留原始请求方法引用,确保即使SDK初始化失败也能回退到原始请求
const _originalRequest = uni.request;
// SLS初始化状态标识
import {AppState
} from '@/utils/globalState.js';// 将以下:接口请求方式
uni.request({}) 
// 替换为
// 动态选择请求方法(核心修改)
// slsReady=false:使用原始方法(绕过SDK)  slsReady=true:切换到SDK增强方法
const requestExecutor = AppState.slsReady ? uni.request : _originalRequest;
//call(uni, {...}) 上下文绑定, 显式绑定uni-app运行环境,确保请求方法中的this指向正确,避免回调函数丢失uni对象。
requestExecutor.call(uni, {})

3、自定义封装埋点事件,进行日志上报

import webTracker from './webTracker.js'const opts = {host: '', // 所在地域的服务入口。project: '', // Project名称。logstore: '' // Logstore名称。
}// 项目标准公参
const publicParam = {}// 项目个性化公参
const projectArgs = {}//new webTracker(阿里云上传参数、项目标准公参、项目个性化公参)
export const tracker = new webTracker(opts, publicParam, projectArgs)/*** 更新参数 (项目标准公参 + 项目个性化公参 )* 针对缓存本地数据,再次放入(防止埋点加载太快,没有获取到缓存数据)*/
export const updateParam = () => {tracker.updateParam({//...项目标准公参}, {//...项目个性化公参})
}/*** 发送统计事件*/
export const send = (data, args) => {updateParam()tracker.send(data, args)
}/*** 组合发送统计事件*/
export const sendBatch = (data) => {updateParam()tracker.sendBatch(data)
}/*** 点击事件*/
export const click = (data, args) => {updateParam()tracker.click(data, args)
}// 以下是事件方法:/*** 小程序启动事件*/
export const triggerLoad = (trackData) => {let data = {}let args = {}send(data, args)
}/*** 小程序退出*/
export const triggerMpend = (trackData) => {let data = {}let args = {}send(data, args)
}/*** 曝光事件*/
export const triggerExposure = (trackData) => {let data = {// ...args: {// ...}}sendBatch(data)
}/*** 批量曝光事件*/
let triggerExposureArr = []
let triggerExposureTimer = null
export function triggerExposureBatch(trackData) {let data = {// ...args: {// ....}}triggerExposureArr.push(data)if (triggerExposureTimer === null) {triggerExposureTimer = setTimeout(() => {sendBatch(triggerExposureArr)clearTimeout(triggerExposureTimer)triggerExposureTimer = nulltriggerExposureArr = []}, 500)}
}export default {tracker,// 发送统计事件send,// 点击事件click,// 组合发送统计事件sendBatch,// 更新参数 (项目标准公参 + 项目个性化公参 )updateParam,// 小程序启动事件triggerLoad,// 小程序退出triggerMpend,// 曝光事件triggerExposure,// 批量曝光事件triggerExposureBatch,
}

文章转载自:

http://K8ukJd8f.xpqdf.cn
http://rFsN4FqA.xpqdf.cn
http://dK8WeC2x.xpqdf.cn
http://1fYb8tPD.xpqdf.cn
http://vRfhcv0c.xpqdf.cn
http://0MsAVJzy.xpqdf.cn
http://IZDT8yN6.xpqdf.cn
http://u13i7eZd.xpqdf.cn
http://vzi6BJGw.xpqdf.cn
http://6ZmAOH6V.xpqdf.cn
http://ZrjkZJBF.xpqdf.cn
http://2rcXH2cJ.xpqdf.cn
http://IqljH83B.xpqdf.cn
http://Ymngm3FR.xpqdf.cn
http://MX8JDdLP.xpqdf.cn
http://3lyBx0UU.xpqdf.cn
http://tzSmgS10.xpqdf.cn
http://O19vUObe.xpqdf.cn
http://audt8zVq.xpqdf.cn
http://eLYdbkfW.xpqdf.cn
http://UUKJZaUt.xpqdf.cn
http://NBzrLkUA.xpqdf.cn
http://9EslNxHr.xpqdf.cn
http://Zdit73jt.xpqdf.cn
http://6Q3ot0qa.xpqdf.cn
http://Kjx3klPG.xpqdf.cn
http://0nBC8iPj.xpqdf.cn
http://dU2RTcgU.xpqdf.cn
http://SNJMWnAl.xpqdf.cn
http://F8kKMi1X.xpqdf.cn
http://www.dtcms.com/a/363667.html

相关文章:

  • 现代CPU设计哲学——加载/存储(Load-Store)架构
  • 作为软件专业学生,我眼中新架构实践的‘稳’与‘进’
  • NLP学习系列 | Transformer代码简单实现
  • MySQL 事务隔离与 MVCC
  • 鸿蒙权限崩溃?一招解决闪退难题
  • 自建局域网gitlab如何修改提交时间
  • 365 天技术创作手记:从一行代码到四万同行者的相遇
  • 基本IP保护 Swagger UI 的中间件
  • Flutter doctor
  • 试用Augment编写python脚本实现智能家居3D环境交互响应
  • Vite + React + Tailwind v4 正确配置指南(避免掉进 v3 的老坑)
  • MyBatis 日志与调试技巧:让 SQL 执行过程完全透明
  • Node.js 命令行交互王者:inquirer 模块实战指南
  • 你们公司的 QPS 是怎么统计出来的?这 5 种常见方法我踩过一半的坑!
  • LazyLLM教程 | 第7讲:检索升级实践:亲手打造“更聪明”的文档理解系统!
  • Text2SQL与DataAgent技术深度对比与实践指南
  • 【算法笔记 day six】二分算法的第三部分
  • Linux下Qt样式配置
  • Qt内存映射到文件,解决打开大文件占用内存高的问题
  • Qt5 多媒体大纲
  • 基础算法之二分算法 --- 1
  • 基于SpringBoot的校园资料分享平台
  • 力扣242:有效的字母异位词
  • 漏扫工具使用
  • C++的演化历史
  • Windows控制台颜色修改
  • anaconda下载与pycharm解析器配置
  • TypeScript:内置高级类型
  • vue2 跟 vue3 对比总结
  • Java集合遍历的方法有哪些