Files

120 lines
3.0 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:injectable/injectable.dart';
import 'package:moonwell_launcher/config.dart';
import 'package:path/path.dart' as p;
@lazySingleton
class LauncherLogService {
static Future<void> _pendingWrite = Future<void>.value();
Future<void> info(
String message, {
String? installationDir,
Map<String, Object?> details = const <String, Object?>{},
}) {
return _write(
level: 'INFO',
message: message,
installationDir: installationDir,
details: details,
);
}
Future<void> error(
String message, {
String? installationDir,
Map<String, Object?> details = const <String, Object?>{},
Object? error,
StackTrace? stackTrace,
}) {
return _write(
level: 'ERROR',
message: message,
installationDir: installationDir,
details: details,
error: error,
stackTrace: stackTrace,
);
}
Future<String> resolveLogPath({String? installationDir}) async {
final logDirectory =
installationDir == null || installationDir.trim().isEmpty
? p.join(Directory.systemTemp.path, 'moonwell_launcher')
: p.join(installationDir, Config.launcherMetadataDirectoryName);
await Directory(logDirectory).create(recursive: true);
return p.join(logDirectory, Config.launcherLogFileName);
}
String logHint([String? installationDir]) {
if (installationDir == null || installationDir.trim().isEmpty) {
return Config.launcherLogFileName;
}
return '${Config.launcherMetadataDirectoryName}/${Config.launcherLogFileName}';
}
Future<void> _write({
required String level,
required String message,
required String? installationDir,
required Map<String, Object?> details,
Object? error,
StackTrace? stackTrace,
}) {
final operation = _pendingWrite.then((_) async {
final logPath = await resolveLogPath(installationDir: installationDir);
final buffer = StringBuffer()
..writeln('[${DateTime.now().toIso8601String()}] [$level] $message');
for (final entry in details.entries) {
if (entry.value == null) {
continue;
}
buffer.writeln('${entry.key}: ${_stringify(entry.value)}');
}
if (error != null) {
buffer.writeln('error: ${_stringify(error)}');
}
if (stackTrace != null) {
buffer.writeln('stackTrace: $stackTrace');
}
buffer.writeln();
await File(
logPath,
).writeAsString(buffer.toString(), mode: FileMode.append, flush: true);
});
_pendingWrite = operation.catchError((_) {});
return operation;
}
String _stringify(Object? value) {
if (value == null) {
return 'null';
}
if (value is String) {
return value;
}
if (value is Map || value is Iterable) {
try {
return jsonEncode(value);
} catch (_) {
return value.toString();
}
}
return value.toString();
}
}