Cook up proper logging

This commit is contained in:
2025-03-15 23:53:33 +01:00
parent 3c1e949b0d
commit ec4b78acc4
4 changed files with 122 additions and 28 deletions

View File

@@ -1,11 +1,17 @@
import 'package:flutter/material.dart';
import 'package:rimworld_modman/modloader.dart';
import 'dart:io';
import 'package:rimworld_modman/modloader.dart';
// Global variable to store loaded mods for access across the app
late ModList modManager;
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Get a reference to the logger (now auto-initializes)
final logger = Logger.instance;
logger.info('Rimworld Mod Manager starting...');
// Initialize the mod manager
modManager = ModList(path: modsRoot);

View File

@@ -1,11 +1,83 @@
import 'dart:io';
import 'dart:async';
import 'package:xml/xml.dart';
import 'package:path/path.dart' as path;
const root = r'C:/Users/Administrator/Seafile/Games-Rimworld';
const modsRoot = '$root/294100';
const configRoot = '$root/AppData/RimWorld by Ludeon Studios/Config';
const configPath = '$configRoot/ModsConfig.xml';
const logsPath = '$root/ModManager';
// Logger class for writing logs to console and file
class Logger {
static final Logger _instance = Logger._internal();
static Logger get instance => _instance;
File? _logFile;
IOSink? _logSink;
Logger._internal() {
_initLogFile();
}
void _initLogFile() {
try {
// Use system temp directory
final tempDir = Directory.systemTemp;
final timestamp = DateTime.now().toIso8601String().replaceAll(':', '-').substring(0, 19);
final logFileName = 'rimworld_modman_$timestamp.log';
_logFile = File('${tempDir.path}${Platform.pathSeparator}$logFileName');
_logSink = _logFile!.openWrite(mode: FileMode.writeOnly);
info('Logging initialized. Log file: ${_logFile!.path}');
} catch (e) {
print('Failed to initialize log file: $e');
}
}
void _log(String message, String level) {
final timestamp = DateTime.now().toIso8601String();
final formattedMessage = '[$timestamp] [$level] $message';
// Always print to console
print(formattedMessage);
// Write to file if initialized
if (_logSink != null) {
try {
_logSink!.writeln(formattedMessage);
} catch (e) {
print('Error writing to log file: $e');
}
}
}
void info(String message) {
_log(message, 'INFO');
}
void warning(String message) {
_log(message, 'WARN');
}
void error(String message) {
_log(message, 'ERROR');
}
void close() {
if (_logSink != null) {
try {
_logSink!.flush();
_logSink!.close();
} catch (e) {
print('Error closing log file: $e');
}
_logSink = null;
}
}
}
XmlElement findCaseInsensitive(XmlElement element, String name) {
return element.childElements.firstWhere(
@@ -52,6 +124,7 @@ class Mod {
});
static Mod fromDirectory(String path, {bool skipFileCount = false}) {
final logger = Logger.instance;
final stopwatch = Stopwatch()..start();
final aboutFile = File('$path/About/About.xml');
@@ -196,8 +269,8 @@ class Mod {
stopwatch.elapsedMilliseconds - metadataTime - xmlTime;
final totalTime = stopwatch.elapsedMilliseconds;
// Uncomment for detailed timing
print(
// Log detailed timing information
logger.info(
'Mod $name timing: XML=${xmlTime}ms, Metadata=${metadataTime}ms, FileCount=${fileCountTime}ms, Total=${totalTime}ms',
);
@@ -231,6 +304,8 @@ class ModList {
// Simplified loading with config file first
Future<void> loadWithConfig({bool skipFileCount = false}) async {
final logger = Logger.instance;
// Clear existing state if reloading
if (modsLoaded) {
mods.clear();
@@ -241,7 +316,7 @@ class ModList {
loadingStatus = 'Loading active mods from config...';
final stopwatch = Stopwatch()..start();
print('Loading configuration from config file: $configPath');
logger.info('Loading configuration from config file: $configPath');
try {
// First, load the config file to get the list of active mods
@@ -287,7 +362,7 @@ class ModList {
if (!directory.existsSync()) {
loadingStatus = 'Error: Mods root directory does not exist: $path';
print(loadingStatus);
logger.error(loadingStatus);
return;
}
@@ -297,7 +372,7 @@ class ModList {
totalModsFound = modDirectories.length;
loadingStatus = 'Found $totalModsFound mod directories. Loading...';
print('Found ${modDirectories.length} mod directories (${stopwatch.elapsedMilliseconds}ms)');
logger.info('Found ${modDirectories.length} mod directories (${stopwatch.elapsedMilliseconds}ms)');
for (final modDir in modDirectories) {
try {
@@ -351,21 +426,21 @@ class ModList {
loadingStatus = 'Loaded $loadedModsCount/$totalModsFound mods...';
if (loadedModsCount % 50 == 0 || loadedModsCount == totalModsFound) {
print('Progress: Loaded $loadedModsCount mods (${stopwatch.elapsedMilliseconds}ms)');
logger.info('Progress: Loaded $loadedModsCount mods (${stopwatch.elapsedMilliseconds}ms)');
}
} catch (e) {
print('Error loading mod from directory: $modDir');
print('Error: $e');
logger.error('Error loading mod from directory: $modDir');
logger.error('Error: $e');
}
}
modsLoaded = true;
final totalTime = stopwatch.elapsedMilliseconds;
loadingStatus = 'Completed! Loaded $loadedModsCount mods in ${totalTime}ms.';
print('Loading complete! Loaded ${mods.length} mods in ${totalTime}ms');
logger.info('Loading complete! Loaded ${mods.length} mods in ${totalTime}ms');
} catch (e) {
loadingStatus = 'Error loading mods: $e';
print(loadingStatus);
logger.error(loadingStatus);
}
}
@@ -690,24 +765,25 @@ class ConfigFile {
ConfigFile({required this.path, this.mods = const []});
Future<void> load() async {
final logger = Logger.instance;
final file = File(path);
print('Loading configuration from: $path');
logger.info('Loading configuration from: $path');
try {
final xmlString = file.readAsStringSync();
print('XML content read successfully.');
logger.info('XML content read successfully.');
final xmlDocument = XmlDocument.parse(xmlString);
print('XML document parsed successfully.');
logger.info('XML document parsed successfully.');
final modConfigData = xmlDocument.findElements("ModsConfigData").first;
print('Found ModsConfigData element.');
logger.info('Found ModsConfigData element.');
final modsElement = modConfigData.findElements("activeMods").first;
print('Found activeMods element.');
logger.info('Found activeMods element.');
final modElements = modsElement.findElements("li");
print('Found ${modElements.length} active mods.');
logger.info('Found ${modElements.length} active mods.');
// Get the list of known expansions
final knownExpansionsElement = modConfigData.findElements("knownExpansions").firstOrNull;
@@ -715,7 +791,7 @@ class ConfigFile {
? knownExpansionsElement.findElements("li").map((e) => e.innerText.toLowerCase()).toList()
: <String>[];
print('Found ${knownExpansionIds.length} known expansions.');
logger.info('Found ${knownExpansionIds.length} known expansions.');
// Clear and recreate the mods list
mods = [];
@@ -749,9 +825,9 @@ class ConfigFile {
);
}
print('Loaded ${mods.length} mods from config file.');
logger.info('Loaded ${mods.length} mods from config file.');
} catch (e) {
print('Error loading configuration file: $e');
logger.error('Error loading configuration file: $e');
throw Exception('Failed to load config file: $e');
}
}
@@ -767,13 +843,14 @@ class ConfigFile {
// Save the current mod order back to the config file
void save() {
final logger = Logger.instance;
final file = File(path);
print('Saving configuration to: $path');
logger.info('Saving configuration to: $path');
// Create a backup just in case
final backupPath = '$path.bak';
file.copySync(backupPath);
print('Created backup at: $backupPath');
logger.info('Created backup at: $backupPath');
try {
// Load the existing XML
@@ -798,16 +875,17 @@ class ConfigFile {
// Write the updated XML back to the file
file.writeAsStringSync(xmlDocument.toXmlString(pretty: true));
print('Configuration saved successfully with ${mods.length} mods.');
logger.info('Configuration saved successfully with ${mods.length} mods.');
} catch (e) {
print('Error saving configuration: $e');
print('Original configuration preserved at: $backupPath');
logger.error('Error saving configuration: $e');
logger.info('Original configuration preserved at: $backupPath');
}
}
// Fix the load order of mods according to dependencies
void fixLoadOrder(ModList modList) {
print("Fixing mod load order...");
final logger = Logger.instance;
logger.info("Fixing mod load order...");
// Get the ordered mod IDs from the mod list
final orderedIds = modList.sortMods();
@@ -836,7 +914,7 @@ class ConfigFile {
// Replace the current mods list with the ordered one
mods = orderedMods;
print(
logger.info(
"Load order fixed. ${mods.length} mods are now in dependency-sorted order.",
);
}