From f03f38a7df7d06c90d13bf120880073ee4adf86c Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Tue, 28 Jan 2025 19:57:35 -0300 Subject: [PATCH] Logging rework --- Knossos.NET/Classes/Knossos.cs | 2 + Knossos.NET/Models/Log.cs | 111 ++++++++++-------- Knossos.NET/Models/Nebula.cs | 5 +- .../ViewModels/Templates/ModCardViewModel.cs | 3 +- .../Templates/NebulaModCardViewModel.cs | 1 - 5 files changed, 68 insertions(+), 54 deletions(-) diff --git a/Knossos.NET/Classes/Knossos.cs b/Knossos.NET/Classes/Knossos.cs index d0a2f268..8be67653 100644 --- a/Knossos.NET/Classes/Knossos.cs +++ b/Knossos.NET/Classes/Knossos.cs @@ -704,6 +704,8 @@ public async static void LoadBasePath(bool isQuickLaunch = false) { await FolderSearchRecursive(globalSettings.basePath, isQuickLaunch).ConfigureAwait(false); + Log.Add(Log.LogSeverity.Information, "Knossos.LoadBasePath()", "Loaded: " + installedMods.Count() +" installed mods or tcs and " + engineBuilds.Count() + " engine builds." ); + if (!isQuickLaunch) { //Sort/Re-sort installed mods diff --git a/Knossos.NET/Models/Log.cs b/Knossos.NET/Models/Log.cs index 5a5168e7..26ce3725 100644 --- a/Knossos.NET/Models/Log.cs +++ b/Knossos.NET/Models/Log.cs @@ -1,7 +1,9 @@ using Avalonia.Threading; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; @@ -19,7 +21,64 @@ public enum LogSeverity Error } - public static string LogFilePath = KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log"; + private class LogEntry + { + string logString = string.Empty; + bool writeToFile = false; + + public LogEntry(LogSeverity logSeverity, string from, string data) + { + logString = DateTime.Now.ToString() + " - *" + logSeverity.ToString() + "* : (" + from + ") " + data; + if (Knossos.globalSettings.enableLogFile && (int)logSeverity >= Knossos.globalSettings.logLevel) + { + writeToFile = true; + } + Task.Factory.StartNew(() => { + ProcessLogEntry(); + }); + } + + private async void ProcessLogEntry() + { + while (!queuedLogs.Any() || queuedLogs.Peek() != this) + await Task.Delay(10); + WriteToConsole(); + if (writeToFile) + WriteToFile(); + queuedLogs.Dequeue(); + } + + private void WriteToConsole() + { + Log.WriteToConsole(logString); + } + + private void WriteToFile(int attempt = 1) + { + try + { + using (var writer = new StreamWriter(LogFilePath, true)) + { + writer.WriteLine(logString, Encoding.UTF8); + } + }catch(Exception ex) + { + if(attempt < maxFileWriteAttempts) + { + attempt++; + WriteToFile(attempt); + } + else + { + Log.WriteToConsole("Failed to write to the logfile, reason: " + ex.ToString() + " \nFilePath:"+ LogFilePath); + } + } + } + } + + public static readonly string LogFilePath = KnUtils.GetKnossosDataFolderPath() + Path.DirectorySeparatorChar + "Knossos.log"; + private static readonly int maxFileWriteAttempts = 5; + private static Queue queuedLogs = new Queue(); /// /// Write a log entry to console and file @@ -31,28 +90,7 @@ public enum LogSeverity /// public static void Add(LogSeverity logSeverity, string from, string data) { - var logString = DateTime.Now.ToString() + " - *" + logSeverity.ToString() + "* : (" + from + ") " + data; - if (Knossos.globalSettings.enableLogFile && (int)logSeverity >= Knossos.globalSettings.logLevel ) - { - Task.Run(async () => { - try - { - if (!Knossos.isKnDataFolderReadOnly) - { - await WaitForFileAccess(LogFilePath); - using (var writer = new StreamWriter(LogFilePath, true)) - { - writer.WriteLine(logString, Encoding.UTF8); - } - } - } - catch (Exception ex) - { - WriteToConsole(ex.Message); - } - }); - } - WriteToConsole(logString); + queuedLogs.Enqueue(new LogEntry(logSeverity, from, data)); } /// @@ -83,35 +121,10 @@ public async static void WriteToConsole(string data) await Dispatcher.UIThread.InvokeAsync(() => Knossos.WriteToUIConsole(data), DispatcherPriority.Background); if (Debugger.IsAttached) { - System.Diagnostics.Debug.WriteLine(data); + Debug.WriteLine(data); } } catch { } } - - /// - /// Wait for the log file being available for write - /// Returns when the file is ready - /// - /// - private static async Task WaitForFileAccess(string filename) - { - try - { - if (File.Exists(filename)) - { - using (FileStream inputStream = File.Open(filename, FileMode.Open, FileAccess.Read)) - { - inputStream.Close(); - return; - } - } - } - catch (IOException) - { - await Task.Delay(500); - await WaitForFileAccess(filename); - } - } } } diff --git a/Knossos.NET/Models/Nebula.cs b/Knossos.NET/Models/Nebula.cs index 64875bd8..48a87399 100644 --- a/Knossos.NET/Models/Nebula.cs +++ b/Knossos.NET/Models/Nebula.cs @@ -487,6 +487,7 @@ private static bool IsModUpdate(Mod mod) cancellationToken = null; } GC.Collect(); + Log.Add(Log.LogSeverity.Information, "Nebula.InitialRepoLoad()", "Loaded: " + allModsInRepo.Count() + " repo entries. Engine builds: "+ builds.Count() + ", Mods: " + modsByID.Count() + ", TCs: " + modsTcs.Count() + "." ); return modUpdates; } catch (TaskCanceledException) @@ -1170,7 +1171,7 @@ public static async Task IsModEditable(string id) if (reply.Value.mods != null && reply.Value.mods.Any()) { var ids = reply.Value.mods.Select(x => x.Deserialize()!).ToArray()!; - Log.Add(Log.LogSeverity.Information, "Nebula.GetEditableMods", "Editable mods in Nebula: " + string.Join(", ", ids)); + Log.Add(Log.LogSeverity.Information, "Nebula.GetEditableMods", "Editable mod ids in Nebula: " + string.Join(",", ids)); editableIds = ids; return ids; } @@ -1208,7 +1209,7 @@ public static async Task IsModEditable(string id) var mods = reply.Value.mods.Select(x => x.Deserialize()!).ToArray()!; foreach (var mod in mods) { - Log.Add(Log.LogSeverity.Information, "Nebula.GetPrivateMods", "Private mod in Nebula with access: " + mod); + Log.Add(Log.LogSeverity.Information, "Nebula.GetPrivateMods", mod.ToString()); } return mods; } diff --git a/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs b/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs index 06e56752..f3cd1647 100644 --- a/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs +++ b/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs @@ -66,7 +66,6 @@ public ModCardViewModel() public ModCardViewModel(Mod modJson) { - Log.Add(Log.LogSeverity.Information, "ModCardViewModel(Constructor)", "Creating mod card for " + modJson.title +" "+ modJson.version); modJson.ClearUnusedData(); modVersions.Add(modJson); Name = modJson.title; @@ -102,7 +101,7 @@ public void AddModVersion(Mod modJson) modVersions.Sort((o1, o2) => -SemanticVersion.Compare(o1.version, o2.version)); if (SemanticVersion.Compare(modJson.version, currentVersion) > 0) { - Log.Add(Log.LogSeverity.Information, "ModCardViewModel.AddModVersion()", "Changing active version for " + modJson.title + " from " + modVersions[activeVersionIndex].version + " to " + modJson.version); + Log.Add(Log.LogSeverity.Information, "ModCardViewModel.AddModVersion()", "Changing active version for " + modJson.title + " from " + currentVersion + " to " + modJson.version); activeVersionIndex = modVersions.FindIndex((m) => m.version.Equals(modJson.version)); Name = modJson.title; ModVersion = modJson.version + " (+" + (modVersions.Count - 1) + ")"; diff --git a/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs b/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs index 3dee01d9..b82288c3 100644 --- a/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs +++ b/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs @@ -60,7 +60,6 @@ public NebulaModCardViewModel() public NebulaModCardViewModel(Mod modJson) { - Log.Add(Log.LogSeverity.Information, "NebulaModCardViewModel(Constructor)", "Creating mod card for " + modJson); modJson.ClearUnusedData(); this.modJson = modJson; //Moved to load when visible only