前端记录日志生成文件保存到本地

一、前言

项目上线后业务人员反馈说是打印数据不准确,通过websocket连接打印机服务去进行打印,会出现条码漏打的情况;通过后端日志和打印机日志均没有找到问题原因,猜测是websocket连接断开导致的问题。

也想通过前端日志去排查问题,本人据理力争说控制台有日志输出;奈何现场人员不会看控制台信息,无奈只能研究如何去生成前端日志。

二、日志思路

首先需要了解前端如何去生成日志,最终保存到用户电脑中。为此需要明确几点:

  1. 日志的生成方法;
  2. 日志信息如何展示;
  3. 保存方法与保存路径;
  4. 哪些信息需要保存到日志中;

2.1 日志生成的方法

日志信息需要定义一个变量,这个根据具体需求;如果是单一功能需要日志操作信息,则只需要定义局部变量;如果是整个项目都需要日志操作信息,则需要定义全局变量。

本次示例日志变量挂载到window上,这样可以直接获取及更改。

// 判断是否有日志变量
if (window.historryRecordLogs) {
    // 初始化日志变量
    window.historryRecordLogs = [];
}
// 根据项目需求去跟更改日志信息类型,建立一个消息队列;
// 需要记录的信息放进日志队列里面去
window.historryRecordLogs.push({
    // 如果需要前台展示效果可以根据类型展示不同样式
    type: "日志类型",	
    message: "具体日志信息",
    userName: "操作人",
    dateTime: "操作时间",
});

2.2 整理生成txt文件下载

最终我们需要得到这样一个日志文件,就需要前端生成一个文件,手动或被动去生成一个日志文件。

实现步骤:

  1. 整理日志信息,汇总输出文字;
  2. JS通过Blob方法生成一个Blob文件;
  3. 在生成一个临时a标签,来模拟手动下载;

简单示例:

// 导出下载日志文件
const exportFileTxt = () => {
	// 判断是否有日志变量
	if (window.historryRecordLogs && window.historryRecordLogs.length) {
		// 整理日志信息
		const dataTxt = window.historryRecordLogs.reduce((cur, next) => cur +=
			`操作人:${next.userName},日志信息:<${next.message}> 操作时间:${next.dataTime}\n`, "");
		// 生成一个Blob文件
		const urlObject = window.URL || window.webkitURL || window;
		const blobFile = new Blob([dataTxt]);
		// 生成一个a标签模拟下载
		const aDom = document.createElement("a")
		aDom.href = urlObject.createObjectURL(blobFile);
		// 定义文件名称
		aDom.download = `${moment(new Date())}_logs`;
		aDom.click();
	}
};

2.3 保存路径

保存路径是当前浏览器的默认下载路径,无法手动指定下载文件路径;

2.3.1 下载方式:
  1. 可以设置用户退出登录后默认下载;
  2. 放在头部导航栏,有需求的情况下再点击下载;
2.3.2 注意事项
  1. 如果采用默认下载的情况需要结合具体情况;
  2. 当用户直接关闭浏览器时无法自动下载;
  3. 直接关闭标签页也无法下载(这个可以监听关闭当前标签页的事件);
window.addEventListener('beforeunload', function (e) {
  // 取消关闭标签页的默认行为
  e.preventDefault();
  // 自定义确认消息
  e.returnValue = '您有未保存的更改,确定要离开吗?';
});

2.4 整理哪些信息存储日志

  1. 前端接口的报错信息;
  2. 敏感数据的操作流程;
  3. websocket连接状态详细日志记录;

三、详细记录

3.1 前端接口报错信息记录

// 封装一个请求方法,在catch阶段进行错误捕获
const request = async (url, options) => {
	try {
		const response = await fetch(url, options);
		if (!response.ok) {
			throw new Error(response.statusText);
		}
		return await response.json();
	} catch (error) {
		window.historryRecordLogs.push({
			type: "error",
			message: error.message,
			userName: "操作人",
			dateTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
		});
		throw error;
	}
};

3.2 敏感数据的操作流程

// 假设有一个敏感操作的函数
function sensitiveOperation() {
    try {
        // 操作逻辑
    } catch (e) {
        window.historryRecordLogs.push({
            type: "sensitiveOperation",
            message: e.message || '未知错误',
            userName: "操作人",
            dateTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
        });
    }
}

3.3 websocket连接状态详细日志记录

const ws = new WebSocket("ws://example.com");

ws.onopen = () => {
    window.historryRecordLogs.push({
        type: "websocket",
        message: "WebSocket连接已打开",
        userName: "操作人",
        dateTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
    });
};

ws.onclose = (event) => {
    window.historryRecordLogs.push({
        type: "websocket",
        message: `WebSocket连接已关闭,代码:${event.code},原因:${event.reason}`,
        userName: "操作人",
        dateTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
    });
};

ws.onerror = (error) => {
    window.historryRecordLogs.push({
        type: "websocket",
        message: `WebSocket错误:${error.message}`,
        userName: "操作人",
        dateTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
    });
};

四、总结

通过以上步骤,我们可以实现前端日志的记录和下载,方便我们排查问题。但是需要注意的是,这种方式并不能解决所有的问题,有些问题可能需要结合后端日志或者浏览器的开发者工具来解决。同时,这种方式也有一定的风险,因为日志信息可能会被恶意用户利用,所以我们需要确保日志信息的安全性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懒羊羊我小弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值