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 = null
triggerExposureArr = []
}, 500)
}
}
export default {
tracker,
// 发送统计事件
send,
// 点击事件
click,
// 组合发送统计事件
sendBatch,
// 更新参数 (项目标准公参 + 项目个性化公参 )
updateParam,
// 小程序启动事件
triggerLoad,
// 小程序退出
triggerMpend,
// 曝光事件
triggerExposure,
// 批量曝光事件
triggerExposureBatch,
}