uniapp本地存储日志

uniapp本地存储日志

背景

我们的APP开发完成之后,在我们测试环境或者自测的时候都好好的,但是发布到生产环境客户使用总会出现一些奇奇怪怪的问题。这时候因为没在开发环境,我们无法查看到日志,所以我们需要手机到用户的操作日志然后上传,方便我们排查出问题。

实现

我们通过5+API提供的IO模块来进行文件的读写操作。主要实现如下功能:

1、日志打印

2、日志按天存储(同一天的日志会自动续写到文件)

3、日志删除

4、日志压缩

代码实现

主要通过plus.io.requestFileSystem对应用私有目录进行读写,完整代码如下:

javascript 复制代码
// 新建logger.js文件
// 日志存放的文件夹目录
const LOG_DIR = '_doc/logs';
/**
 * 获取当前时间
 */
function getDayStr() {
	var y, m, d, h, mm, s;
	var date = new Date();
	y = date.getFullYear();
	m = date.getMonth() + 1;
	d = date.getDate();
	m = m < 10 ? '0' + m : m;
	d = d < 10 ? '0' + d : d;
	// //console.log('日期:',y,m,d)
	// return '20220607' // 生成指定日期
	return '' + y + m + d;
}
/**
 * 获取当前时间,yyyy-mm-dd hh:mm:ss
 * 用于记录日志的时间信息
 */
function getTimeStr() {
	var y, m, d, h, mm, s;
	var date = new Date();
	y = date.getFullYear();
	m = date.getMonth() + 1;
	d = date.getDate();
	h = date.getHours();
	mm = date.getMinutes();
	s = date.getSeconds();
	m = m < 10 ? '0' + m : m;
	d = d < 10 ? '0' + d : d;
	h = h < 10 ? '0' + h : h;
	mm = mm < 10 ? '0' + mm : mm;
	s = s < 10 ? '0' + s : s;
	var timeStr = y + '-' + m + '-' + d + ' ' + h + ':' + mm + ':' + s;
	return timeStr;
}
/**
 * 日志TXT的名称
 */
function getLogFileName() {
	const txt = LOG_DIR + '/' + getDayStr() + '.txt';
	// //console.log('TXT文件名称:',txt)
	return txt;
}
let tasks = [];
/**
 * @param {Object} tag 标识
 * @param {Object} msg 空格
 */
function writeToTxt(tag) {
	return new Promise((resolve, reject) => {
		let msgs = '';
		for (var i = 1; i < arguments.length; i++) {
			const item = arguments[i];
			if (
				typeof item == 'string' ||
				typeof item == 'number' ||
				typeof item == 'boolean'
			) {
				msgs = msgs + '\t' + item;
			} else {
				msgs = msgs + '\t' + JSON.stringify(item);
			}
		}
		// 获取当前时间
		let txt_msg = getTimeStr() + '\t[' + tag + ']\t' + msgs + '\n';
		tasks.push(txt_msg);
		resolve(true);
	}).then(() => {
		clearTask();
	});
}
// 清空日志到日志文件
function clearTask() {
	// #ifdef APP-PLUS
	if (tasks.length === 0) {
		return;
	}
	const txt_msg = tasks.join('');
	tasks = [];
	const fileName = getLogFileName();
	plus.io.requestFileSystem(
		plus.io.PRIVATE_DOC,
		fs => {
			fs.root.getFile(
				fileName, {
					create: true,
				},
				function(entry) {
					// 写入到本地
					entry.createWriter(
						function(writer) {
							writer.onwrite = function(e) {
								// console.log("Write data success!");
								//console.log('写入本地日志 >>>> ', txt_msg);
							};
							writer.onerror = function(e) {
								if (process.env.NODE_ENV === 'development'){
									console.eror(
										'写入本地日志失败 >>>> ',
										JSON.stringify(e),
										txt_msg
									);
								}
							};
							// Write data to the end of file.
							writer.seek(writer.length);
							writer.write(txt_msg);
						},
						function(e) {
							if (process.env.NODE_ENV === 'development') {
								console.log(e.message);
							}
						}
					);
				}
			);
		},
		function(e) {
			if (process.env.NODE_ENV === 'development') {
				console.log('Request file system failed: ' + JSON.stringify(e));
			}
		}
	);
	// #endif
}

/**
 * 压缩所有的日志为zip
 */
function zipLogDir(callback) {
	// #ifdef APP-PLUS
	var zipFile = '_doc/logs.zip';
	var targetPath = LOG_DIR;

	// 开始压缩文件
	if (process.env.NODE_ENV === 'development') {
		console.log('开始压缩', targetPath, zipFile);
	}
	plus.zip.compress(
		targetPath,
		zipFile,
		function(res) {
			if (process.env.NODE_ENV === 'development') {
				console.log('开始压缩 Compress success!', res);
			}
			if (callback) {
				callback({
					success: true,
					res,
					zipPath: zipFile,
				});
			}
		},
		function(error) {
			if (process.env.NODE_ENV === 'development') {
				console.error('开始压缩 Compress error!', error);
			}
			if (callback) {
				callback({
					success: false,
					error,
				});
			}
		}
	);
	// #endif
}
/**
 * 删除多少天之前的日志文件
 */
function removeFile(durationDay) {
	// #ifdef APP-PLUS
	return new Promise((resolve, reject) => {
		if (!durationDay || durationDay <= 0) {
			durationDay = 10;
		}
		var dirPath = LOG_DIR;
		plus.io.resolveLocalFileSystemURL(
			dirPath,
			function(entry) {
				//读取这个目录对象
				var directoryReader = entry.createReader();
				//读取这个目录下的所有文件
				directoryReader.readEntries(
					function(entries) {
						console.log('日志文件数量', entries.length);
						//如果有才操作
						if (entries.length > 0) {
							let now = getDayStr();
							for (let file of entries) {
								// 判断需要保留的日志
								let day = file.name.replace('.txt', '');
								if (parseInt(day) + parseInt(durationDay) < parseInt(now)) {
									console.log('需要删除的日志是', file.name);
									try {
										file.remove(
											function() {
												if (process.env.NODE_ENV === 'development') {
													console.error('删除日志成功', file.name);
												}
											},
											function(e) {
												if (process.env.NODE_ENV === 'development') {
													console.error('删除日志失败', file.name, e);
												}
											}
										);
									} catch (e) {
										if (process.env.NODE_ENV === 'development') {
											console.error('删除日志失败', file.name, e);
										}
									}
								} else {
									if (process.env.NODE_ENV === 'development') {
										console.log('保留的日志是', file.name);
									}
								}
							} // for
						} // if
						resolve();
					},
					function(e) {
						if (process.env.NODE_ENV === 'development') {
							console.log('读取文件失败:' + e.message);
						}

						resolve();
					}
				);
			},
			function(e) {
				if (process.env.NODE_ENV === 'development') {
					console.log('读取目录失败:' + e.message);
				}
				resolve();
			}
		);
	});
	// #endif
}

/**
 * 自定义TXT日志
 */
const logger = {
	/**
	 * @param {Object} msg 日志信息的字符串信息
	 */
	debug: function() {
		writeToTxt('DEBUG', ...arguments);
		//production
		if (process.env.NODE_ENV === 'development') {
			console.debug(...arguments);
		}
	},
	log: function() {
		writeToTxt('LOG', ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.log(...arguments);
		}
	},
	info: function() {
		writeToTxt('INFO', ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.info(...arguments);
		}
	},
	warn: function() {
		writeToTxt('WARN', ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.warn(...arguments);
		}
	},
	error: function() {
		writeToTxt('ERROR', ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.error(...arguments);
		}
	},
	/**
	 * @param {String} tag 日志信息的自定义信息
	 */
	tag: function(tag) {
		writeToTxt(tag, ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.log(...arguments);
		}
	},
	/**
	 * @param {Object} msg 日志信息的字符串信息
	 */
	network: function() {
		writeToTxt('NETWORK', ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.log(...arguments);
		}
	},
	/**
	 * @param {Object} msg 日志信息的字符串信息
	 */
	logIpExchange: function(msg) {
		writeToTxt('IpExchange', ...arguments);
		if (process.env.NODE_ENV === 'development') {
			console.log(...arguments);
		}
	},
	/**
	 * 压缩成zip,并返回路径
	 * @param {Object} callback
	 */
	zipLogDir,
	/**
	 * 删除多少${durationDay}天之前的日志文件
	 * @param {Object} durationDay 默认是10天
	 */
	removeFile,
	/**
	 * 主要使用方法。先移除
	 * @param {Object} callback
	 */
	removeFileAndZipLogDir(callback) {
		removeFile().then(() => {
			zipLogDir(callback);
		});
	},
};

export default logger;

使用

引入logger.js文件

javascript 复制代码
//这里根据你自己路径来
import logger from '@/common/js/logger.js'

删除5天前的日志

javascript 复制代码
logger.removeFile(5)

打印

javascript 复制代码
logger.log('test')

查看生成log

我们这里使用的是hbx基座调试,这里的plus.io.PRIVATE_DOC对应的手机端文件管理器中Android/data/io.dcloud.HBuilder/apps/Hbuilder/doc/logs,其中doc/logs对应代码中的LOG_DIR变量。

到这里log已经成功存储到了手机中。

读取

我们保存log到本地之后,我们希望读取然后上传,依然使用的是plus.io.requestFileSystem这个API,参考上文的写法。遍历文件夹后可以在界面显示让用户手动上传,或者启动应用静默上传。

注意事项

日志本地存储只在APP平台生效,演示为Android平台,iOS平台未做测试。

尾巴

今天的文章就到这里了,希望能给大家帮助,如果喜欢我的文章,欢迎给我点赞,评论,关注,谢谢大家!

相关推荐
断墨先生6 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
guai_guai_guai7 小时前
uniapp
前端·javascript·vue.js·uni-app
阿伟来咯~12 小时前
一些 uniapp相关bug
uni-app·bug
瑶琴AI前端16 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
mosen86816 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
尚梦1 天前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
尚学教辅学习资料1 天前
基于SSM+uniapp的营养食谱系统+LW参考示例
java·uni-app·ssm·菜谱
Bessie2341 天前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
qq22951165022 天前
小程序Android系统 校园二手物品交换平台APP
微信小程序·uni-app
qq22951165022 天前
微信小程序uniapp基于Android的流浪动物管理系统 70c3u
微信小程序·uni-app