feat:设备日志模块

feat:定时任务
feat:设置页面用路由重构
This commit is contained in:
dzc committed 2026-07-30 13:16:14 +08:00
1 parent 1033f403b1
commit 2efa7a3c19
60 files changed
+6560 -643

No files matched your search

+50
View File
@@ -43,6 +43,53 @@ Future<AppLogCatalog> listAppLogFiles() async {
return _consoleOutput.listLogFiles();
}
/// 上传当前日志前刷新文件写入队列,保证快照边界包含调用前已经产生的日志。
Future<void> flushCurrentAppLog() async {
await logger.init;
await _consoleOutput.flushCurrentLog();
}
/// 逐行生成脱敏副本,上传工具不会把原始日志文件直接交给网络层。
Future<void> sanitizeAppLogFile({
required File source,
required File target,
int? maxSourceBytes,
}) async {
final sourceLength = await source.length();
final limit = maxSourceBytes == null
? sourceLength
: maxSourceBytes.clamp(0, sourceLength);
final input = await source.open();
IOSink? output;
try {
output = target.openWrite(mode: FileMode.writeOnly);
var position = 0;
var pending = '';
const chunkSize = 64 * 1024;
while (position < limit) {
final length = (limit - position).clamp(0, chunkSize);
final bytes = await input.read(length);
if (bytes.isEmpty) break;
position += bytes.length;
pending += utf8.decode(bytes, allowMalformed: true);
final lines = pending.split('\n');
pending = lines.removeLast();
for (final line in lines) {
output.writeln(sanitizeAppLogContent(line));
}
}
if (pending.isNotEmpty) output.write(sanitizeAppLogContent(pending));
await output.flush();
} finally {
await input.close();
await output?.close();
}
}
/// 日志预览和上传共用同一套脱敏规则,避免两个入口出现隐私边界漂移。
String sanitizeAppLogContent(String content) =>
_sanitizePreviewContent(content);
class AppLogCatalog {
const AppLogCatalog({
required this.rootPath,
@@ -113,6 +160,9 @@ class ConsoleOutput extends LogOutput {
return _queue;
}
/// 排在既有写入队列末尾刷新当前文件,完成后调用方可取得一致的文件大小快照。
Future<void> flushCurrentLog() => _enqueue(() async => _sink?.flush());
/// 读取当前日志文件尾部,并在返回 UI 前移除终端颜色码和常见敏感字段。
Future<AppLogPreview> readPreview({
String? path,