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

uniApp App 端日志本地存储方案:实现可靠的日志记录功能

在移动应用开发过程中,日志记录是排查问题、分析用户行为的重要手段。对于 UniApp 开发的 App 来说,实现日志本地存储并在需要时导出,能极大地方便问题定位。本文将介绍如何在 UniApp 的 App 端实现日志的本地文件存储功能。

功能需求分析

一个完善的本地日志存储方案应具备以下功能:

  • 支持写入不同级别日志(info、warn、error 等)
  • 自动记录日志时间和级别
  • 按日期分割日志文件,避免单个文件过大
  • 支持设置日志文件最大保存天数
  • 提供日志文件清理功能
  • 确保在 App 重启后日志不会丢失

实现方案

下面是一个完整的日志工具类实现,基于 UniApp 的文件系统 API:

// logger.js
const LOG_LEVELS = {DEBUG: 'DEBUG',INFO: 'INFO',WARN: 'WARN',ERROR: 'ERROR'
}class Logger {constructor() {this.maxLogDays = 7 // 默认保存7天日志this.logDir = 'logs' // 日志目录this.init()}async init() {// 确保日志目录存在try {const dirInfo = await this.getDirInfo(this.logDir)if (!dirInfo) {await this.createDir(this.logDir)}} catch (e) {console.error('初始化日志目录失败:', e)}// 启动时清理过期日志this.cleanOldLogs()}// 设置日志最大保存天数setMaxLogDays(days) {if (days > 0) {this.maxLogDays = days}}// 获取当前日期字符串 (格式: YYYY-MM-DD)getCurrentDateStr() {const date = new Date()return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`}// 获取当前时间字符串getCurrentTimeStr() {const date = new Date()return `${this.getCurrentDateStr()} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}.${date.getMilliseconds().toString().padStart(3, '0')}`}// 获取日志文件名getLogFileName() {return `app_${this.getCurrentDateStr()}.log`}// 写入日志async log(level, message, data = null) {try {const time = this.getCurrentTimeStr()let logContent = `[${time}] [${level}] ${message}`if (data) {logContent += ` | ${typeof data === 'object' ? JSON.stringify(data) : data}`}logContent += '\n'const fileName = this.getLogFileName()const filePath = `${this.logDir}/${fileName}`// 检查文件是否存在const fileInfo = await this.getFileInfo(filePath)if (fileInfo) {// 文件存在,追加内容await this.appendFile(filePath, logContent)} else {// 文件不存在,创建新文件await this.writeFile(filePath, logContent)}} catch (e) {console.error('写入日志失败:', e)}}// 快捷方法debug(message, data) {this.log(LOG_LEVELS.DEBUG, message, data)}info(message, data) {this.log(LOG_LEVELS.INFO, message, data)}warn(message, data) {this.log(LOG_LEVELS.WARN, message, data)}error(message, data) {this.log(LOG_LEVELS.ERROR, message, data)}// 清理过期日志async cleanOldLogs() {try {const now = new Date()const threshold = now.setDate(now.getDate() - this.maxLogDays)const dirInfo = await this.getDirInfo(this.logDir)if (!dirInfo) returnconst files = await this.readDir(this.logDir)for (const file of files) {const fileName = file.name// 解析文件名中的日期const dateStr = fileName.match(/app_(\d{4}-\d{2}-\d{2})\.log/)?.[1]if (dateStr) {const fileDate = new Date(dateStr)if (fileDate.getTime() < threshold) {// 文件日期早于阈值,删除await this.deleteFile(`${this.logDir}/${fileName}`)}}}} catch (e) {console.error('清理日志失败:', e)}}// 手动清理所有日志async clearAllLogs() {try {const files = await this.readDir(this.logDir)for (const file of files) {await this.deleteFile(`${this.logDir}/${file.name}`)}} catch (e) {console.error('清除所有日志失败:', e)}}// 获取所有日志文件列表async getLogFiles() {try {const files = await this.readDir(this.logDir)return files.filter(file => file.name.endsWith('.log'))} catch (e) {console.error('获取日志文件列表失败:', e)return []}}// 读取日志文件内容async readLogFile(fileName) {try {const filePath = `${this.logDir}/${fileName}`const content = await this.readFile(filePath)return content} catch (e) {console.error('读取日志文件失败:', e)return null}}// ========== 文件系统操作封装 ==========// 获取目录信息async getDirInfo(dirPath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(`_doc/${dirPath}`,entry => resolve(entry),error => resolve(null))})}// 创建目录async createDir(dirPath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL('_doc',rootEntry => {rootEntry.getDirectory(dirPath,{ create: true, exclusive: false },dirEntry => resolve(dirEntry),error => reject(error))},error => reject(error))})}// 获取文件信息async getFileInfo(filePath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(`_doc/${filePath}`,entry => resolve(entry),error => resolve(null))})}// 写入文件async writeFile(filePath, content) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL('_doc',rootEntry => {rootEntry.getFile(filePath,{ create: true, exclusive: false },fileEntry => {fileEntry.createWriter(writer => {writer.onwriteend = () => resolve()writer.onerror = e => reject(e)writer.write(content)},error => reject(error))},error => reject(error))},error => reject(error))})}// 追加内容到文件async appendFile(filePath, content) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(`_doc/${filePath}`,fileEntry => {fileEntry.createWriter(writer => {writer.onwriteend = () => resolve()writer.onerror = e => reject(e)writer.seek(writer.length)writer.write(content)},error => reject(error))},error => reject(error))})}// 读取文件内容async readFile(filePath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(`_doc/${filePath}`,fileEntry => {fileEntry.file(file => {const reader = new plus.io.FileReader()reader.onloadend = e => resolve(e.target.result)reader.onerror = e => reject(e)reader.readAsText(file)},error => reject(error))},error => reject(error))})}// 读取目录内容async readDir(dirPath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(`_doc/${dirPath}`,dirEntry => {const reader = dirEntry.createReader()reader.readEntries(entries => resolve(entries),error => reject(error))},error => reject(error))})}// 删除文件async deleteFile(filePath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(`_doc/${filePath}`,entry => {entry.remove(() => resolve(),error => reject(error))},error => reject(error))})}
}// 创建全局单例
const logger = new Logger()export default logger

使用方法

在 UniApp 项目中使用该日志工具非常简单,以下是使用示例:

import logger from './logger.js'// 记录不同级别日志
logger.debug('这是一条调试信息', { key: 'value' })
logger.info('这是一条普通信息')
logger.warn('这是一条警告信息')
logger.error('这是一条错误信息', new Error('示例错误'))// 设置日志最大保存天数
logger.setMaxLogDays(30) // 保存30天日志// 手动清理日志
logger.cleanOldLogs()// 清除所有日志
logger.clearAllLogs()

使用时,只需在项目中引入该方法,即可在任何需要记录日志的地方调用相应方法。

http://www.xdnf.cn/news/17840.html

相关文章:

  • 【python实用小脚本-187】Python一键批量改PDF文字:拖进来秒出新文件——再也不用Acrobat来回导
  • RH134 管理存储堆栈知识点
  • Day60--图论--94. 城市间货物运输 I(卡码网),95. 城市间货物运输 II(卡码网),96. 城市间货物运输 III(卡码网)
  • StarRocks集群部署
  • 顺丰面试题
  • 最长递增子序列-dp问题+二分优化
  • 金融业务安全增强方案:国密SM4/SM3加密+硬件加密机HSM+动态密钥管理+ShardingSphere加密
  • 【职场】-啥叫诚实
  • es7.x的客户端连接api以及Respository与template的区别
  • 基本电子元件:碳膜电阻器
  • pytorch 数据预处理,加载,训练,可视化流程
  • Ubuntu DNS 综合配置与排查指南
  • 研究学习3DGS的顺序
  • Golang信号处理实战
  • Linux操作系统从入门到实战(二十三)详细讲解进程虚拟地址空间
  • Canal 技术解析与实践指南
  • 【Spring框架】SpringAOP
  • Vue3从入门到精通: 4.4 复杂状态管理模式与架构设计
  • Python爬虫大师课:HTTP协议深度解析与工业级请求封装
  • dockerfile自定义镜像,乌班图版
  • MC0439符号统计
  • 智能家居【home assistant】(一)-在Windows电脑上运行home assistant
  • Webapi发布后IIS超时(.net8.0)
  • 什么是可信空间的全域节点、区域节点、业务节点?
  • Claude Opus 4.1深度解析:抢先GPT5发布,AI编程之王主动出击?
  • (Arxiv-2025)Stand-In:一种轻量化、即插即用的身份控制方法用于视频生成
  • 微软自曝Win 11严重漏洞:可导致全盘数据丢失
  • 简单使用 TypeScript 或 JavaScript 创建并发布 npm 插件
  • 搭建前端开发环境 安装nvm nodejs pnpm 配置环境变量
  • 大华相机RTSP无法正常拉流问题分析与解决