/** * 日志管理系统 * 提供分级日志记录、错误追踪、性能监控 */ 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 }