2022-11-27 22:34:19 +02:00
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
import 'package:hive/hive.dart';
|
|
|
|
import 'package:immich_mobile/constants/hive_box.dart';
|
|
|
|
import 'package:immich_mobile/shared/models/immich_logger_message.model.dart';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:share_plus/share_plus.dart';
|
|
|
|
|
|
|
|
/// [ImmichLogger] is a custom logger that is built on top of the [logging] package.
|
|
|
|
/// The logs are written to a Hive box and onto console, using `debugPrint` method.
|
|
|
|
///
|
|
|
|
/// The logs are deleted when exceeding the `maxLogEntries` (default 200) property
|
|
|
|
/// in the class.
|
|
|
|
///
|
|
|
|
/// Logs can be shared by calling the `shareLogs` method, which will open a share dialog
|
|
|
|
/// and generate a csv file.
|
|
|
|
class ImmichLogger {
|
|
|
|
final maxLogEntries = 200;
|
|
|
|
final Box<ImmichLoggerMessage> _box = Hive.box(immichLoggerBox);
|
|
|
|
|
|
|
|
List<ImmichLoggerMessage> get messages =>
|
|
|
|
_box.values.toList().reversed.toList();
|
|
|
|
|
|
|
|
ImmichLogger() {
|
|
|
|
_removeOverflowMessages();
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
Logger.root.level = Level.INFO;
|
|
|
|
Logger.root.onRecord.listen(_writeLogToHiveBox);
|
|
|
|
}
|
|
|
|
|
|
|
|
_removeOverflowMessages() {
|
|
|
|
if (_box.length > maxLogEntries) {
|
|
|
|
var numberOfEntryToBeDeleted = _box.length - maxLogEntries;
|
|
|
|
for (var i = 0; i < numberOfEntryToBeDeleted; i++) {
|
|
|
|
_box.deleteAt(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_writeLogToHiveBox(LogRecord record) {
|
|
|
|
final Box<ImmichLoggerMessage> box = Hive.box(immichLoggerBox);
|
|
|
|
var formattedMessage = record.message;
|
|
|
|
|
|
|
|
debugPrint('[${record.level.name}] [${record.time}] ${record.message}');
|
|
|
|
box.add(
|
|
|
|
ImmichLoggerMessage(
|
|
|
|
message: formattedMessage,
|
|
|
|
level: record.level.name,
|
|
|
|
createdAt: record.time,
|
|
|
|
context1: record.loggerName,
|
2022-11-28 18:17:27 +02:00
|
|
|
context2: record.stackTrace?.toString(),
|
2022-11-27 22:34:19 +02:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void clearLogs() {
|
|
|
|
_box.clear();
|
|
|
|
}
|
|
|
|
|
2022-11-28 18:17:27 +02:00
|
|
|
Future<void> shareLogs() async {
|
|
|
|
final tempDir = await getTemporaryDirectory();
|
|
|
|
final dateTime = DateTime.now().toIso8601String();
|
|
|
|
final filePath = '${tempDir.path}/Immich_log_$dateTime.csv';
|
|
|
|
final logFile = await File(filePath).create();
|
|
|
|
final io = logFile.openWrite();
|
|
|
|
try {
|
|
|
|
// Write header
|
|
|
|
io.write("created_at,level,context,message,stacktrace\n");
|
2022-11-27 22:34:19 +02:00
|
|
|
|
2022-11-28 18:17:27 +02:00
|
|
|
// Write messages
|
|
|
|
for (final m in messages) {
|
|
|
|
io.write(
|
|
|
|
'${m.createdAt},${m.level},"${m.context1 ?? ""}","${m.message}","${m.context2 ?? ""}"\n',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
await io.flush();
|
|
|
|
await io.close();
|
2022-11-27 22:34:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Share file
|
2023-01-26 16:40:19 +02:00
|
|
|
// ignore: deprecated_member_use
|
2022-11-28 18:17:27 +02:00
|
|
|
await Share.shareFiles(
|
2022-11-27 22:34:19 +02:00
|
|
|
[filePath],
|
2022-11-28 18:17:27 +02:00
|
|
|
subject: "Immich logs $dateTime",
|
2022-11-27 22:34:19 +02:00
|
|
|
sharePositionOrigin: Rect.zero,
|
|
|
|
);
|
2022-11-28 18:17:27 +02:00
|
|
|
|
|
|
|
// Clean up temp file
|
|
|
|
await logFile.delete();
|
2022-11-27 22:34:19 +02:00
|
|
|
}
|
|
|
|
}
|