181 lines
5.8 KiB
Dart
181 lines
5.8 KiB
Dart
import 'dart:io';
|
||
import 'package:archive/archive_io.dart';
|
||
import 'package:path_provider/path_provider.dart';
|
||
import 'package:intl/intl.dart';
|
||
import 'package:share_plus/share_plus.dart';
|
||
import 'dart:convert';
|
||
|
||
class DailyLogUtils {
|
||
// 获取当天日志文件路径
|
||
static Future<File> _getLogFile() async {
|
||
final dir = await getApplicationDocumentsDirectory();
|
||
final date = DateFormat('yyyy-MM-dd').format(DateTime.now());
|
||
final file = File('${dir.path}/$date.log');
|
||
if (!await file.exists()) {
|
||
await file.create(recursive: true);
|
||
}
|
||
return file;
|
||
}
|
||
|
||
// 写日志核心方法,带日志等级,固定 UTF-8
|
||
static Future<void> _writeLogWithLevel(String level, String content) async {
|
||
final file = await _getLogFile();
|
||
final now = DateTime.now();
|
||
final time = DateFormat('HH:mm:ss').format(now);
|
||
final logLine = '[$time][$level] $content\n';
|
||
await file.writeAsString(logLine, mode: FileMode.append, encoding: utf8);
|
||
}
|
||
|
||
// Info 日志
|
||
static Future<void> writeLog(String content) async {
|
||
print("[dailylog-->info] $content");
|
||
await _writeLogWithLevel('INFO', content);
|
||
}
|
||
|
||
// Warning 日志
|
||
static Future<void> writeWarning(String content) async {
|
||
print("[dailylog-->warning] $content");
|
||
await _writeLogWithLevel('WARNING', content);
|
||
}
|
||
|
||
// Error 日志
|
||
static Future<void> writeError(String content) async {
|
||
print("[dailylog-->error] $content");
|
||
await _writeLogWithLevel('ERROR', content);
|
||
}
|
||
|
||
// Debug 日志
|
||
static Future<void> writeDebug(String content) async {
|
||
print("[dailylog-->debug] $content");
|
||
await _writeLogWithLevel('DEBUG', content);
|
||
}
|
||
|
||
// 读取当天日志,容错 UTF-8
|
||
static Future<String> readTodayLog() async {
|
||
final file = await _getLogFile();
|
||
try {
|
||
return await file.readAsString(encoding: utf8);
|
||
} catch (e) {
|
||
final bytes = await file.readAsBytes();
|
||
return utf8.decode(bytes, allowMalformed: true);
|
||
}
|
||
}
|
||
|
||
// 获取所有日志文件
|
||
static Future<List<FileSystemEntity>> listLogFiles() async {
|
||
final dir = await getApplicationDocumentsDirectory();
|
||
final files = dir.listSync();
|
||
return files.where((f) => f.path.endsWith('.log')).toList();
|
||
}
|
||
|
||
// 清除所有日志
|
||
static Future<void> clearAllLogs() async {
|
||
final files = await listLogFiles();
|
||
for (final f in files) {
|
||
await File(f.path).delete();
|
||
}
|
||
}
|
||
|
||
// 获取指定日期范围内日志文件
|
||
static Future<List<File>> getLogsBetween(
|
||
DateTime fromDate, DateTime toDate) async {
|
||
final dir = await getApplicationDocumentsDirectory();
|
||
final logFiles = <File>[];
|
||
final dateFormat = DateFormat('yyyy-MM-dd');
|
||
|
||
for (DateTime date = fromDate;
|
||
!date.isAfter(toDate);
|
||
date = date.add(Duration(days: 1))) {
|
||
final file = File('${dir.path}/${dateFormat.format(date)}.log');
|
||
if (await file.exists()) logFiles.add(file);
|
||
}
|
||
|
||
return logFiles;
|
||
}
|
||
|
||
// 读取日期范围内日志,合并返回
|
||
static Future<String> readLogsByDateRange(
|
||
DateTime fromDate, DateTime toDate) async {
|
||
try {
|
||
final dir = await getApplicationDocumentsDirectory();
|
||
final dateFormat = DateFormat('yyyy-MM-dd');
|
||
String combinedLogs = '';
|
||
|
||
for (DateTime date = fromDate;
|
||
!date.isAfter(toDate);
|
||
date = date.add(Duration(days: 1))) {
|
||
final file = File('${dir.path}/${dateFormat.format(date)}.log');
|
||
if (await file.exists()) {
|
||
String content;
|
||
try {
|
||
content = await file.readAsString(encoding: utf8);
|
||
} catch (_) {
|
||
final bytes = await file.readAsBytes();
|
||
content = utf8.decode(bytes, allowMalformed: true);
|
||
}
|
||
combinedLogs += '日志日期: ${dateFormat.format(date)}\n$content\n\n';
|
||
}
|
||
}
|
||
|
||
return combinedLogs.isNotEmpty ? combinedLogs : '该时间段内没有日志记录';
|
||
} catch (e) {
|
||
return '读取日志失败: $e';
|
||
}
|
||
}
|
||
|
||
// 导出所有日志为 zip 并分享(系统分享)
|
||
static Future<void> exportAllLogs() async {
|
||
try {
|
||
final dir = await getApplicationDocumentsDirectory();
|
||
final dateStr = DateFormat('yyyy-MM-dd_HH-mm-ss').format(DateTime.now());
|
||
final zipPath = '${dir.path}/logs_$dateStr.zip';
|
||
|
||
final archive = Archive();
|
||
|
||
// 遍历日志文件
|
||
final logFiles = dir
|
||
.listSync()
|
||
.whereType<File>()
|
||
.where((f) => f.path.endsWith('.log') && f.existsSync());
|
||
|
||
if (logFiles.isEmpty) {
|
||
print("没有日志文件可压缩!");
|
||
return;
|
||
}
|
||
|
||
for (var file in logFiles) {
|
||
final name = file.path.split('/').last;
|
||
final bytes = await file.readAsBytes(); // 读取原始字节
|
||
final content =
|
||
utf8.decode(bytes, allowMalformed: true); // 转 UTF-8,允许非 UTF-8
|
||
final utf8Bytes = utf8.encode(content); // 写入压缩包
|
||
archive.addFile(ArchiveFile(name, utf8Bytes.length, utf8Bytes));
|
||
print("添加日志文件: ${file.path}, 大小: ${utf8Bytes.length}");
|
||
}
|
||
|
||
// 写入 zip 文件
|
||
final zipData = ZipEncoder().encode(archive);
|
||
final zipFile = File(zipPath);
|
||
await zipFile.writeAsBytes(zipData!);
|
||
|
||
print("压缩包生成成功: ${zipFile.path}, 大小: ${await zipFile.length()} 字节");
|
||
|
||
// 分享
|
||
await Share.shareXFiles([XFile(zipFile.path)], text: '应用日志打包 $dateStr');
|
||
} catch (e) {
|
||
print('导出日志失败: $e');
|
||
}
|
||
}
|
||
|
||
static Future<void> printLog(String content) async {
|
||
print("logger---> $content");
|
||
// 如果你希望顺便写入 info 日志,也可以取消下面注释
|
||
// await writeLog(content);
|
||
}
|
||
|
||
static Future<String> readLogByDate(DateTime date) async {
|
||
// 调用 readLogsByDateRange,fromDate 和 toDate 都是同一天
|
||
return await readLogsByDateRange(date, date);
|
||
}
|
||
}
|