微信小程序操作日志下
上篇说明了微信小程序官方api实现日志管理功能,但是存在缺陷的:
1、每个小程序账号每天限制1000万条日志,日志会保留7天;
2、每次调用的参数的总大小不超过5Kb
如果我们小程序pv较多,或者需要统计接口返回参数,但是数据太长的话就会出现异常,当然这样基本不会造成小程序宕机,并且这类型接口数据并非一定要上报。例如获取省市区信息,这个数据包一定很多,但是我们获取接口的时候,上报下开始获取接口数据时间,和获取数据结果时间和结果,我们可以直接上报获取成功,不上报具体返回内容。话说正题,针对此情况我使用的方法是,前端保存用户操作,满足一定条件的情况下,上报给后台,后台做存储处理,上报时间带有了时间、用户id信息,所以很容易搜索指定用户指定时间段数据。代码如下:
// 上报日志接口 import { apiMinilog } from "@/api/globalSettingInfo.js" import store from "@/store/index.js"; // 格式化时间,展示当前操作时间数据 import { formatTime } from "./index.js" class _logger { constructor() { this.logData = [] // 日志 this.logDataCache = [] // 缓冲区日志 this.isSaveLogs = false // 是否在上传日志中 this.maxSaveLength = 150 // 最大保存数目(部分接口返回数据过多,导致单个缓存值超载,缩小每篇日志数量) this.maxTemporaryLength = 200 // 最大临时保存数目 } // 初始化,日志文件夹不存在=》创建 async init() { if (uni.getStorageSync("logData") == "undefined" || uni.getStorageSync("logData") === "") { uni.setStorageSync("logData", []) } if (uni.getStorageSync("logDataCache") == "undefined" || uni.getStorageSync("logDataCache") === "") { uni.setStorageSync("logDataCache", []); } this.logData = uni.getStorageSync("logData"); this.logDataCache = uni.getStorageSync("logDataCache"); } // 写入日志,写入成功上传到本地缓存 async writeLogs(log, logMoll) { if (!this.isSaveLogs) { this.writeLogsToSave("logData", log, logMoll); // 日志数目达到上限并且用户已经登录,自动上传日志 if (((this.logData.length > this.maxSaveLength) || (this.logDataCache.length > this.maxSaveLength)) && !!store.getters.userId) { this.saveLogs(this.logData); } } else { this.writeLogsToSave("logDataCache", log, logMoll); } } // 实际写入内容 writeLogsToSave(dataName, log, logMoll) { // 日志格式整理 let _logDataTmp = { time: formatTime(Date.now()), }; // 当前日志为第一条时上报用户id和设备信息,主要检验用户会不会突然更换手机操作 if(this[dataName].length === 0) { _logDataTmp.phoneModel = store.state.system.model; _logDataTmp.userId = store.getters.userId; } if(this[dataName].length >= this.maxTemporaryLength) { if(!this[dataName][this.maxTemporaryLength-1].isLast) { this[dataName] = this[dataName].slice(0, this.maxTemporaryLength - 1); let lastObj = typeof log === "string" ? log : JSON.stringify(log); _logDataTmp.result = "缓存保存失败,达到临时最大值" + lastObj; _logDataTmp.isLast = 1; this[dataName].push(_logDataTmp) this.saveInStorage(dataName) } else { return } // 没有达到临界值,继续保存 } else { if (typeof log === "string") { _logDataTmp.info = log; _logDataTmp.result = logMoll; this[dataName].push(_logDataTmp); } else if (typeof log === "object") { this[dataName].push(log); } this.saveInStorage(dataName) } } // 保存写进缓存 saveInStorage(dataName) { // 不影响逻辑,缓存超出的情况下自动清理缓存 try { uni.setStorageSync(dataName, this[dataName]); } catch (e) { // 用户已登录并且处于日志区直接保存日志,否者清除缓存,以免逻辑进行不下去 if(!!store.getters.userId && dataName === "logData") { this.saveLogs(this.logData); } else { uni.setStorageSync(dataName, []); this[dataName] = []; this.writeLogs("不影响逻辑强制清除" + (dataName === "logData" ? "" : "临时区") + "缓存") } } } // 保存日志,上传到服务器,并清空缓存 async saveLogs(_tmpLogs) { this.isSaveLogs = true; let options = { tmpLogs: _tmpLogs, } apiMinilog(options).then(res => { this.logData = this.logDataCache; this.isSaveLogs = false; uni.setStorageSync("logData", this.logDataCache) // 清空缓冲区 this.logDataCache = []; uni.setStorageSync("logDataCache", []); }).catch(err => { // 上传接口失败时,状态没有重置,logDataCache临时缓存一直增加,但是释放不了,此时应该重置状态,触发重新上传,清除logDataCache this.isSaveLogs = false }) } } export default _logger;