Files
ZhiQiXiaoYuan/utils/logger.js
ChuXun eaab9a762a 1
2025-10-19 20:28:31 +08:00

311 lines
5.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 日志管理系统
* 提供分级日志记录、错误追踪、性能监控
*/
class Logger {
constructor() {
this.logs = []
this.maxLogs = 1000 // 最多保存1000条日志
this.level = 'info' // debug, info, warn, error
this.enableConsole = true
this.enableStorage = true
}
/**
* 日志级别枚举
*/
static LEVELS = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3
}
/**
* 记录调试信息
*/
debug(message, data = {}) {
this._log('DEBUG', message, data)
}
/**
* 记录普通信息
*/
info(message, data = {}) {
this._log('INFO', message, data)
}
/**
* 记录警告信息
*/
warn(message, data = {}) {
this._log('WARN', message, data)
}
/**
* 记录错误信息
*/
error(message, data = {}) {
this._log('ERROR', message, data)
}
/**
* 核心日志方法
*/
_log(level, message, data) {
const log = {
level,
message,
data,
timestamp: new Date().toISOString(),
page: getCurrentPages().length > 0 ? getCurrentPages()[getCurrentPages().length - 1].route : 'unknown'
}
// 添加到内存
this.logs.push(log)
if (this.logs.length > this.maxLogs) {
this.logs.shift()
}
// 输出到控制台
if (this.enableConsole) {
const consoleMethod = level.toLowerCase()
console[consoleMethod](`[${level}] ${message}`, data)
}
// 保存到本地存储
if (this.enableStorage && level === 'ERROR') {
this._persistErrorLog(log)
}
// 上报严重错误
if (level === 'ERROR') {
this._reportError(log)
}
}
/**
* 持久化错误日志
*/
_persistErrorLog(log) {
try {
const errorLogs = wx.getStorageSync('errorLogs') || []
errorLogs.push(log)
// 只保留最近100条错误
if (errorLogs.length > 100) {
errorLogs.shift()
}
wx.setStorageSync('errorLogs', errorLogs)
} catch (e) {
console.error('日志持久化失败:', e)
}
}
/**
* 上报错误
*/
_reportError(log) {
// TODO: 接入错误监控平台(如 Sentry
console.log('错误上报:', log)
}
/**
* 获取日志
*/
getLogs(filter = {}) {
let logs = this.logs
if (filter.level) {
logs = logs.filter(log => log.level === filter.level)
}
if (filter.page) {
logs = logs.filter(log => log.page === filter.page)
}
if (filter.startTime) {
logs = logs.filter(log => new Date(log.timestamp) >= new Date(filter.startTime))
}
return logs
}
/**
* 清空日志
*/
clearLogs() {
this.logs = []
wx.removeStorageSync('errorLogs')
}
/**
* 导出日志
*/
exportLogs() {
return {
logs: this.logs,
exportTime: new Date().toISOString(),
systemInfo: wx.getSystemInfoSync()
}
}
}
/**
* 错误处理器
*/
class ErrorHandler {
constructor() {
this.logger = new Logger()
this.setupGlobalErrorHandler()
}
/**
* 设置全局错误捕获
*/
setupGlobalErrorHandler() {
// 捕获未处理的Promise错误
wx.onUnhandledRejection((res) => {
this.handleError('UnhandledRejection', res.reason)
})
// 捕获小程序错误
wx.onError((error) => {
this.handleError('AppError', error)
})
}
/**
* 处理错误
*/
handleError(type, error, context = {}) {
const errorInfo = {
type,
message: error.message || error,
stack: error.stack || '',
context,
userAgent: wx.getSystemInfoSync(),
timestamp: Date.now()
}
this.logger.error(`${type}: ${errorInfo.message}`, errorInfo)
// 显示用户友好的错误提示
this.showUserFriendlyError(type, error)
return errorInfo
}
/**
* 显示用户友好的错误提示
*/
showUserFriendlyError(type, error) {
const errorMessages = {
'NetworkError': '网络连接失败,请检查网络设置',
'StorageError': '存储空间不足,请清理缓存',
'UnhandledRejection': '操作失败,请重试',
'AppError': '应用出现异常,请重启小程序'
}
const message = errorMessages[type] || '操作失败,请稍后重试'
wx.showToast({
title: message,
icon: 'none',
duration: 3000
})
}
/**
* 性能监控
*/
monitorPerformance(name, startTime) {
const duration = Date.now() - startTime
if (duration > 1000) {
this.logger.warn(`性能警告: ${name} 耗时 ${duration}ms`)
}
return duration
}
/**
* 获取错误统计
*/
getErrorStats() {
const errorLogs = wx.getStorageSync('errorLogs') || []
const stats = {
total: errorLogs.length,
byType: {},
byPage: {},
recent: errorLogs.slice(-10)
}
errorLogs.forEach(log => {
stats.byType[log.data.type] = (stats.byType[log.data.type] || 0) + 1
stats.byPage[log.page] = (stats.byPage[log.page] || 0) + 1
})
return stats
}
}
// 创建全局实例
const logger = new Logger()
const errorHandler = new ErrorHandler()
/**
* 用户反馈系统
*/
class FeedbackSystem {
/**
* 提交反馈
*/
static submit(feedback) {
const feedbackData = {
...feedback,
timestamp: Date.now(),
systemInfo: wx.getSystemInfoSync(),
logs: logger.getLogs({ level: 'ERROR' }).slice(-20)
}
logger.info('用户反馈', feedbackData)
// TODO: 上传到服务器
this._saveLocal(feedbackData)
return feedbackData
}
/**
* 保存到本地
*/
static _saveLocal(feedback) {
try {
const feedbacks = wx.getStorageSync('userFeedbacks') || []
feedbacks.push(feedback)
wx.setStorageSync('userFeedbacks', feedbacks)
} catch (e) {
console.error('反馈保存失败:', e)
}
}
/**
* 获取反馈列表
*/
static getList() {
return wx.getStorageSync('userFeedbacks') || []
}
}
module.exports = {
logger,
errorHandler,
Logger,
ErrorHandler,
FeedbackSystem
}