refactor(mobile): log service (#16383)

refactor: log service

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong
2025-02-28 01:48:49 +05:30
committed by GitHub
parent fbd85a89e0
commit 28c664c769
24 changed files with 656 additions and 201 deletions
+9 -88
View File
@@ -2,11 +2,7 @@ import 'dart:async';
import 'dart:io';
import 'package:flutter/widgets.dart';
import 'package:immich_mobile/domain/models/store.model.dart';
import 'package:immich_mobile/entities/logger_message.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart';
import 'package:isar/isar.dart';
import 'package:logging/logging.dart';
import 'package:immich_mobile/domain/services/log.service.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
@@ -18,75 +14,10 @@ import 'package:share_plus/share_plus.dart';
///
/// Logs can be shared by calling the `shareLogs` method, which will open a share dialog
/// and generate a csv file.
class ImmichLogger {
static final ImmichLogger _instance = ImmichLogger._internal();
final maxLogEntries = 500;
final Isar _db = Isar.getInstance()!;
List<LoggerMessage> _msgBuffer = [];
Timer? _timer;
abstract final class ImmichLogger {
const ImmichLogger();
factory ImmichLogger() => _instance;
ImmichLogger._internal() {
_removeOverflowMessages();
final int levelId = Store.get(StoreKey.logLevel, 5); // 5 is INFO
Logger.root.level = Level.LEVELS[levelId];
Logger.root.onRecord.listen(_writeLogToDatabase);
}
set level(Level level) => Logger.root.level = level;
List<LoggerMessage> get messages {
final inDb =
_db.loggerMessages.where(sort: Sort.desc).anyId().findAllSync();
return _msgBuffer.isEmpty ? inDb : _msgBuffer.reversed.toList() + inDb;
}
void _removeOverflowMessages() {
final msgCount = _db.loggerMessages.countSync();
if (msgCount > maxLogEntries) {
final numberOfEntryToBeDeleted = msgCount - maxLogEntries;
_db.writeTxn(
() => _db.loggerMessages
.where()
.limit(numberOfEntryToBeDeleted)
.deleteAll(),
);
}
}
void _writeLogToDatabase(LogRecord record) {
debugPrint('[${record.level.name}] [${record.time}] ${record.message}');
final lm = LoggerMessage(
message: record.message,
details: record.error?.toString(),
level: record.level.toLogLevel(),
createdAt: record.time,
context1: record.loggerName,
context2: record.stackTrace?.toString(),
);
_msgBuffer.add(lm);
// delayed batch writing to database: increases performance when logging
// messages in quick succession and reduces NAND wear
_timer ??= Timer(const Duration(seconds: 5), _flushBufferToDatabase);
}
void _flushBufferToDatabase() {
_timer = null;
final buffer = _msgBuffer;
_msgBuffer = [];
_db.writeTxn(() => _db.loggerMessages.putAll(buffer));
}
void clearLogs() {
_timer?.cancel();
_timer = null;
_msgBuffer.clear();
_db.writeTxn(() => _db.loggerMessages.clear());
}
Future<void> shareLogs(BuildContext context) async {
static Future<void> shareLogs(BuildContext context) async {
final tempDir = await getTemporaryDirectory();
final dateTime = DateTime.now().toIso8601String();
final filePath = '${tempDir.path}/Immich_log_$dateTime.log';
@@ -94,13 +25,13 @@ class ImmichLogger {
final io = logFile.openWrite();
try {
// Write messages
for (final m in messages) {
for (final m in await LogService.I.getMessages()) {
final created = m.createdAt;
final level = m.level.name.padRight(8);
final logger = (m.context1 ?? "<UNKNOWN_LOGGER>").padRight(20);
final logger = (m.logger ?? "<UNKNOWN_LOGGER>").padRight(20);
final message = m.message;
final error = m.details != null ? " ${m.details} |" : "";
final stack = m.context2 != null ? "\n${m.context2!}" : "";
final error = m.error == null ? "" : " ${m.error} |";
final stack = m.stack == null ? "" : "\n${m.stack!}";
io.write('$created | $level | $logger | $message |$error$stack\n');
}
} finally {
@@ -115,16 +46,6 @@ class ImmichLogger {
[XFile(filePath)],
subject: "Immich logs $dateTime",
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
).then(
(value) => logFile.delete(),
);
}
/// Flush pending log messages to persistent storage
void flush() {
if (_timer != null) {
_timer!.cancel();
_db.writeTxnSync(() => _db.loggerMessages.putAllSync(_msgBuffer));
}
).then((value) => logFile.delete());
}
}