上篇说明了微信小程序官方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;