import 'dart:io'; import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:path_provider/path_provider.dart'; import 'package:intl/intl.dart'; import '../common/app_config.dart'; /// 初始化日志收集器 /// 用于收集应用启动和初始化过程中的所有日志,方便问题诊断 /// /// 使用说明: /// 1. 通过 AppConfig.enableInitLogCollection 全局开关控制是否收集日志 /// 2. 日志文件保存在:{应用文档目录}/init_logs/init_log_yyyyMMdd_HHmmss.txt /// 3. 自动保留最近5个日志文件,旧文件会被自动清理 class KRInitLogCollector { static final KRInitLogCollector _instance = KRInitLogCollector._internal(); factory KRInitLogCollector() => _instance; KRInitLogCollector._internal(); /// 日志文件 File? _logFile; /// 🔧 终极修复:使用 RandomAccessFile 进行真正的同步写入 RandomAccessFile? _logFileHandle; /// 日志缓冲区(用于在文件创建前暂存日志) final List _logBuffer = []; /// 是否已初始化 bool _isInitialized = false; /// 初始化开始时间 DateTime? _initStartTime; /// 日志文件路径 String? _logFilePath; /// 🔧 关键:检查是否启用日志收集 bool get _isEnabled => AppConfig.enableInitLogCollection; /// 初始化日志收集器 Future initialize() async { // 🔧 检查全局开关 if (!_isEnabled) { if (kDebugMode) { print('📝 初始化日志收集已关闭(AppConfig.enableInitLogCollection = false)'); } return; } if (_isInitialized) return; try { _initStartTime = DateTime.now(); // 获取应用文档目录 final directory = await getApplicationDocumentsDirectory(); final logDir = Directory('${directory.path}/init_logs'); // 创建日志目录 if (!await logDir.exists()) { await logDir.create(recursive: true); } // 创建日志文件(使用时间戳命名) final timestamp = DateFormat('yyyyMMdd_HHmmss').format(_initStartTime!); _logFile = File('${logDir.path}/init_log_$timestamp.txt'); _logFilePath = _logFile!.path; // 🔧 终极修复:使用 RandomAccessFile 进行真正的同步写入 _logFileHandle = await _logFile!.open(mode: FileMode.write); // 写入日志头部 _writeHeader(); // 将缓冲区中的日志写入文件 if (_logBuffer.isNotEmpty) { for (var log in _logBuffer) { _writeToFile(log); } _logBuffer.clear(); } _isInitialized = true; // 打印日志文件路径到控制台,方便查看 if (kDebugMode) { print('📝 初始化日志文件已创建: $_logFilePath'); } // 清理旧日志文件(保留最近5个) await _cleanOldLogs(logDir); } catch (e) { if (kDebugMode) { print('❌ 初始化日志收集器失败: $e'); } } } /// 写入日志头部信息 void _writeHeader() { final header = ''' ═══════════════════════════════════════════════════════════ 应用初始化日志 ═══════════════════════════════════════════════════════════ 开始时间: ${DateFormat('yyyy-MM-dd HH:mm:ss').format(_initStartTime!)} 设备信息: ${Platform.operatingSystem} ${Platform.operatingSystemVersion} Flutter版本: ${Platform.version} ═══════════════════════════════════════════════════════════ '''; _writeToFile(header); } /// 记录日志 void log(String message, {String tag = 'INIT'}) { // 🔧 检查全局开关 if (!_isEnabled) return; final timestamp = DateTime.now(); final elapsed = _initStartTime != null ? timestamp.difference(_initStartTime!).inMilliseconds : 0; final logLine = '[${DateFormat('HH:mm:ss.SSS').format(timestamp)}] ' '[+${elapsed}ms] ' '[$tag] ' '$message'; // 同时输出到控制台(DEBUG模式) if (kDebugMode) { print(logLine); } // 🔧 终极修复:检查 RandomAccessFile 是否可用 if (_isInitialized && _logFileHandle != null) { _writeToFile('$logLine\n'); } else { // 文件未创建前,暂存到缓冲区 _logBuffer.add('$logLine\n'); } } /// 记录分隔线 void logSeparator() { log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: ''); } /// 记录错误 void logError(String message, {String tag = 'ERROR', Object? error, StackTrace? stackTrace}) { log('❌ $message', tag: tag); if (error != null) { log(' 错误详情: $error', tag: tag); } if (stackTrace != null) { log(' 堆栈跟踪: $stackTrace', tag: tag); } } /// 记录警告 void logWarning(String message, {String tag = 'WARN'}) { log('⚠️ $message', tag: tag); } /// 记录成功 void logSuccess(String message, {String tag = 'SUCCESS'}) { log('✅ $message', tag: tag); } /// 记录阶段开始 void logPhaseStart(String phase) { logSeparator(); log('🎬 开始阶段: $phase', tag: 'PHASE'); logSeparator(); } /// 记录阶段完成 void logPhaseEnd(String phase, {bool success = true}) { final icon = success ? '✅' : '❌'; log('$icon 完成阶段: $phase', tag: 'PHASE'); logSeparator(); } /// 🔧 终极修复:使用 RandomAccessFile 进行真正的同步写入 void _writeToFile(String content) { try { if (_logFileHandle != null) { // 使用 writeStringSync 进行同步写入 _logFileHandle!.writeStringSync(content); // 立即刷新到磁盘,确保数据持久化 _logFileHandle!.flushSync(); } } catch (e, stackTrace) { if (kDebugMode) { print('❌ 写入日志文件失败: $e'); print('📚 堆栈跟踪: $stackTrace'); } // 尝试输出到控制台作为备份 if (kDebugMode) { print('[日志备份] $content'); } } } /// 清理旧日志文件(保留最近N个) Future _cleanOldLogs(Directory logDir, {int keepCount = 5}) async { try { final files = logDir.listSync() .whereType() .where((f) => f.path.contains('init_log_')) .toList(); if (files.length <= keepCount) return; // 按修改时间排序 files.sort((a, b) => b.lastModifiedSync().compareTo(a.lastModifiedSync())); // 删除多余的旧文件 for (var i = keepCount; i < files.length; i++) { await files[i].delete(); if (kDebugMode) { print('🧹 已删除旧日志文件: ${files[i].path}'); } } } catch (e) { if (kDebugMode) { print('❌ 清理旧日志文件失败: $e'); } } } /// 记录完成并写入汇总信息 Future finalize() async { if (!_isInitialized || _logFileHandle == null) return; try { final endTime = DateTime.now(); final totalDuration = endTime.difference(_initStartTime!); final footer = ''' ═══════════════════════════════════════════════════════════ 初始化完成 ═══════════════════════════════════════════════════════════ 结束时间: ${DateFormat('yyyy-MM-dd HH:mm:ss').format(endTime)} 总耗时: ${totalDuration.inMilliseconds}ms (${totalDuration.inSeconds}秒) ═══════════════════════════════════════════════════════════ '''; _writeToFile(footer); // 🔧 终极修复:使用同步方法关闭文件,确保所有数据都写入 _logFileHandle!.flushSync(); await _logFileHandle!.close(); _logFileHandle = null; if (kDebugMode) { print('📝 初始化日志已完成: $_logFilePath'); print('📊 总耗时: ${totalDuration.inMilliseconds}ms'); } } catch (e, stackTrace) { if (kDebugMode) { print('❌ 完成日志记录失败: $e'); print('📚 堆栈跟踪: $stackTrace'); } } } /// 获取日志文件路径(用于分享给用户) String? getLogFilePath() => _logFilePath; /// 获取所有日志文件列表 Future> getAllLogFiles() async { try { final directory = await getApplicationDocumentsDirectory(); final logDir = Directory('${directory.path}/init_logs'); if (!await logDir.exists()) return []; return logDir.listSync() .whereType() .where((f) => f.path.contains('init_log_')) .toList() ..sort((a, b) => b.lastModifiedSync().compareTo(a.lastModifiedSync())); } catch (e) { if (kDebugMode) { print('❌ 获取日志文件列表失败: $e'); } return []; } } /// 获取最新的日志文件 Future getLatestLogFile() async { final files = await getAllLogFiles(); return files.isNotEmpty ? files.first : null; } /// 读取日志文件内容 Future readLogFile(File file) async { try { return await file.readAsString(); } catch (e) { return '读取日志文件失败: $e'; } } }