From a016d45e5737f3cdf87866da8b64c150670b983f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 26 Nov 2025 18:34:44 +0800 Subject: [PATCH 1/5] Refactor logging and add dependency injection Enhanced logging with conditional debug checks based on log level, ensuring logs are only generated in DEBUG mode. Integrated `CommunityToolkit.Mvvm.DependencyInjection` for dependency injection, improving modularity and testability. - Replaced direct settings access with `FlowSettings` via DI. - Updated logging in `PluginManager.cs`, `PluginsLoader.cs`, `MainViewModel.cs`, and `ResultsViewModel.cs`. - Improved plugin initialization error handling with conditional logging. - Refactored query and result logging for better performance. - Added necessary namespace imports for DI and logging. - Cleaned up redundant logging and improved code readability. --- Flow.Launcher.Core/Plugin/PluginManager.cs | 9 +++++++-- Flow.Launcher.Core/Plugin/PluginsLoader.cs | 5 ++++- Flow.Launcher/ViewModel/MainViewModel.cs | 19 +++++++++++++------ Flow.Launcher/ViewModel/ResultsViewModel.cs | 5 ++++- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 54712942c28..7ab8c2e4221 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -6,10 +6,12 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; @@ -32,6 +34,7 @@ public static class PluginManager private static readonly ConcurrentDictionary _nonGlobalPlugins = []; private static PluginsSettings Settings; + private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService(); private static readonly ConcurrentBag ModifiedPlugins = []; private static readonly ConcurrentBag _contextMenuPlugins = []; @@ -277,13 +280,15 @@ public static async Task InitializePluginsAsync(IResultUpdateRegister register) { // If this plugin is already disabled, do not show error message again // Or else it will be shown every time - PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error"); + if (FlowSettings.LogLevel == LOGLEVEL.DEBUG) + PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error"); } else { pair.Metadata.Disabled = true; pair.Metadata.HomeDisabled = true; - PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed"); + if (FlowSettings.LogLevel == LOGLEVEL.DEBUG) + PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed"); } // Even if the plugin cannot be initialized, we still need to add it in all plugin list so that diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs index 119dd83baa3..a8f61e2a360 100644 --- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.ExternalPlugins.Environments; #pragma warning disable IDE0005 using Flow.Launcher.Infrastructure.Logger; @@ -14,6 +15,7 @@ namespace Flow.Launcher.Core.Plugin public static class PluginsLoader { private static readonly string ClassName = nameof(PluginsLoader); + private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService(); public static List Plugins(List metadatas, PluginsSettings settings) { @@ -108,7 +110,8 @@ private static List DotNetPlugins(List source) }); metadata.InitTime += milliseconds; - PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>"); + if (FlowSettings.LogLevel == LOGLEVEL.DEBUG) + PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>"); } if (erroredPlugins.Count > 0) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c35f96e6200..f6738c01ffa 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -19,6 +19,7 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; using Flow.Launcher.Infrastructure.Hotkey; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -314,7 +315,8 @@ public void RegisterResultsUpdatedEvent(PluginPair pair) if (token.IsCancellationRequested) return; - App.API.LogDebug(ClassName, $"Update results for plugin <{pair.Metadata.Name}>"); + if (Settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Update results for plugin <{pair.Metadata.Name}>"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, token))) @@ -1382,7 +1384,8 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b { _updateSource?.Cancel(); - App.API.LogDebug(ClassName, $"Start query with text: <{QueryText}>"); + if (Settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Start query with text: <{QueryText}>"); var query = await ConstructQueryAsync(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts); @@ -1392,7 +1395,8 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b return; } - App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>"); + if (Settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>"); var currentIsHomeQuery = query.IsHomeQuery; var currentIsDialogJump = _isDialogJump; @@ -1456,7 +1460,8 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b } } - App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}"); + if (Settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}"); // Do not wait for performance improvement /*if (string.IsNullOrEmpty(query.ActionKeyword)) @@ -1560,7 +1565,8 @@ void ClearResults() async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) { - App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>"); + if (Settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>"); if (searchDelay && !currentIsHomeQuery) // Do not delay for home query { @@ -1604,7 +1610,8 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : if (token.IsCancellationRequested) return; - App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>"); + if (Settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, token, reSelect))) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 2f4ca6ccf36..6933e0963bc 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -8,6 +8,7 @@ using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -253,7 +254,9 @@ private List NewResults(ICollection resultsFo return newResults.OrderByDescending(rv => rv.Result.Score).ToList(); } - App.API.LogDebug(ClassName, $"Keeping existing results for {resultsForUpdates.Count} queries"); + if (_settings.LogLevel == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Keeping existing results for {resultsForUpdates.Count} queries"); + return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) .Concat(newResults) .OrderByDescending(rv => rv.Result.Score) From a2188acfe7e3760180a2437fc7a2861711b4330c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 26 Nov 2025 18:47:41 +0800 Subject: [PATCH 2/5] Refactor logging system for conditional debug checks Updated logging system to conditionally execute debug-level logs only when the log level is set to `DEBUG`, reducing performance overhead in production. Introduced a `LogLevel` property in the `Log` class to dynamically track and configure logging levels. Refactored logging rules to use `NLog.LogLevel` for better compatibility and maintainability. Key changes: - Added conditional checks for `Log.LogLevel` in debug logs across multiple files (`DialogJump.cs`, `WindowsDialog.cs`, `Http.cs`, etc.). - Updated `SetLogLevel` to dynamically adjust NLog configurations. - Streamlined logging method calls to use `NLog.LogLevel` consistently. - Improved exception handling in `Http.cs` and optimized `Stopwatch` utility for debug-level logging. - Minor formatting adjustments and bug fixes in logging rule initialization. These changes enhance the logging system's efficiency, maintainability, and clarity. --- .../DialogJump/DialogJump.cs | 33 ++++++++++++------- .../DialogJump/Models/WindowsDialog.cs | 5 +-- Flow.Launcher.Infrastructure/Http/Http.cs | 17 ++++++---- Flow.Launcher.Infrastructure/Logger/Log.cs | 29 +++++++++------- Flow.Launcher.Infrastructure/Stopwatch.cs | 6 ++-- 5 files changed, 57 insertions(+), 33 deletions(-) diff --git a/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs b/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs index 4a3e6474ef2..06604c110a6 100644 --- a/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs +++ b/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs @@ -536,7 +536,8 @@ uint dwmsEventTime // Handle window based on its type if (isDialogWindow) { - Log.Debug(ClassName, $"Dialog Window: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Dialog Window: {hwnd}"); // Navigate to path if (_settings.AutoDialogJump) { @@ -580,12 +581,14 @@ uint dwmsEventTime // Dialog jump window else if (hwnd == _mainWindowHandle) { - Log.Debug(ClassName, $"Main Window: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Main Window: {hwnd}"); } // Other window else { - Log.Debug(ClassName, $"Other Window: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Other Window: {hwnd}"); var dialogWindowExist = false; lock (_dialogWindowLock) { @@ -613,7 +616,8 @@ uint dwmsEventTime var explorerWindow = explorer.Plugin.CheckExplorerWindow(hwnd); if (explorerWindow != null) { - Log.Debug(ClassName, $"Explorer window: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Explorer window: {hwnd}"); _dialogJumpExplorers[explorer] = explorerWindow; _lastExplorer = explorer; break; @@ -703,7 +707,8 @@ uint dwmsEventTime { if (_dialogWindow != null && _dialogWindow.Handle == hwnd) { - Log.Debug(ClassName, $"Destory dialog: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Destory dialog: {hwnd}"); _dialogWindow = null; dialogWindowExist = true; } @@ -734,7 +739,8 @@ uint dwmsEventTime { if (_dialogWindow != null && _dialogWindow.Handle == hwnd) { - Log.Debug(ClassName, $"Hide dialog: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Hide dialog: {hwnd}"); _dialogWindow = null; dialogWindowExist = true; } @@ -765,7 +771,8 @@ uint dwmsEventTime { if (_dialogWindow != null && _dialogWindow.Handle == hwnd) { - Log.Debug(ClassName, $"End dialog: {hwnd}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"End dialog: {hwnd}"); _dialogWindow = null; dialogWindowExist = true; } @@ -955,15 +962,18 @@ private static async Task JumpToPathAsync(IDialogJumpDialogWindowTab dialo switch (_settings.DialogJumpFileResultBehaviour) { case DialogJumpFileResultBehaviours.FullPath: - Log.Debug(ClassName, $"File Jump FullPath: {path}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"File Jump FullPath: {path}"); result = FileJump(path, dialog); break; case DialogJumpFileResultBehaviours.FullPathOpen: - Log.Debug(ClassName, $"File Jump FullPathOpen: {path}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"File Jump FullPathOpen: {path}"); result = FileJump(path, dialog, openFile: true); break; case DialogJumpFileResultBehaviours.Directory: - Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}"); result = DirJump(Path.GetDirectoryName(path), dialog, auto); break; default: @@ -972,7 +982,8 @@ private static async Task JumpToPathAsync(IDialogJumpDialogWindowTab dialo } else { - Log.Debug(ClassName, $"Dir Jump: {path}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Dir Jump: {path}"); result = DirJump(path, dialog, auto); } diff --git a/Flow.Launcher.Infrastructure/DialogJump/Models/WindowsDialog.cs b/Flow.Launcher.Infrastructure/DialogJump/Models/WindowsDialog.cs index ee4e034337b..c5725f91751 100644 --- a/Flow.Launcher.Infrastructure/DialogJump/Models/WindowsDialog.cs +++ b/Flow.Launcher.Infrastructure/DialogJump/Models/WindowsDialog.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Plugin; @@ -125,7 +125,8 @@ internal WindowsDialogTab(IntPtr handle, DialogType dialogType) { Handle = handle; _dialogType = dialogType; - Log.Debug(ClassName, $"File dialog type: {dialogType}"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"File dialog type: {dialogType}"); } #endregion diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index f8c111f369d..eccd0372f9d 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -146,7 +146,8 @@ public static async Task DownloadAsync([NotNull] string url, [NotNull] string fi /// The Http result as string. Null if cancellation requested public static Task GetAsync([NotNull] string url, CancellationToken token = default) { - Log.Debug(ClassName, $"Url <{url}>"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Url <{url}>"); return GetAsync(new Uri(url), token); } @@ -158,7 +159,8 @@ public static Task GetAsync([NotNull] string url, CancellationToken toke /// The Http result as string. Null if cancellation requested public static async Task GetAsync([NotNull] Uri url, CancellationToken token = default) { - Log.Debug(ClassName, $"Url <{url}>"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Url <{url}>"); using var response = await client.GetAsync(url, token); var content = await response.Content.ReadAsStringAsync(token); if (response.StatusCode != HttpStatusCode.OK) @@ -189,7 +191,8 @@ public static Task GetStreamAsync([NotNull] string url, public static async Task GetStreamAsync([NotNull] Uri url, CancellationToken token = default) { - Log.Debug(ClassName, $"Url <{url}>"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Url <{url}>"); return await client.GetStreamAsync(url, token); } @@ -200,7 +203,8 @@ public static async Task GetResponseAsync(string url, HttpC public static async Task GetResponseAsync([NotNull] Uri url, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, CancellationToken token = default) { - Log.Debug(ClassName, $"Url <{url}>"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Url <{url}>"); return await client.GetAsync(url, completionOption, token); } @@ -223,10 +227,11 @@ public static async Task GetStringAsync(string url, CancellationToken to { try { - Log.Debug(ClassName, $"Url <{url}>"); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(ClassName, $"Url <{url}>"); return await client.GetStringAsync(url, token); } - catch (System.Exception e) + catch { return string.Empty; } diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 2a5b826a9d9..26c9d5251d1 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -15,6 +15,8 @@ public static class Log public const string DirectoryName = Constant.Logs; public static string CurrentLogDirectory { get; } + + public static LOGLEVEL LogLevel { get; private set; } = LOGLEVEL.DEBUG; static Log() { @@ -48,12 +50,12 @@ static Log() configuration.AddTarget("file", fileTargetASyncWrapper); configuration.AddTarget("debug", debugTarget); - var fileRule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper) + var fileRule = new LoggingRule("*", NLog.LogLevel.Debug, fileTargetASyncWrapper) { RuleName = "file" }; #if DEBUG - var debugRule = new LoggingRule("*", LogLevel.Debug, debugTarget) + var debugRule = new LoggingRule("*", NLog.LogLevel.Debug, debugTarget) { RuleName = "debug" }; @@ -65,22 +67,25 @@ static Log() public static void SetLogLevel(LOGLEVEL level) { + LogLevel = level; + var rule = LogManager.Configuration.FindRuleByName("file"); var nlogLevel = level switch { - LOGLEVEL.NONE => LogLevel.Off, - LOGLEVEL.ERROR => LogLevel.Error, - LOGLEVEL.DEBUG => LogLevel.Debug, - _ => LogLevel.Info + LOGLEVEL.NONE => NLog.LogLevel.Off, + LOGLEVEL.ERROR => NLog.LogLevel.Error, + LOGLEVEL.DEBUG => NLog.LogLevel.Debug, + _ => NLog.LogLevel.Info }; - rule.SetLoggingLevels(nlogLevel, LogLevel.Fatal); + rule.SetLoggingLevels(nlogLevel, NLog.LogLevel.Fatal); LogManager.ReconfigExistingLoggers(); // We can't log Info when level is set to Error or None, so we use Debug - Debug(nameof(Logger), $"Using log level: {level}."); + if (LogLevel == LOGLEVEL.DEBUG) + Debug(nameof(Logger), $"Using log level: {level}."); } private static void LogFaultyFormat(string message) @@ -135,7 +140,7 @@ private static void ExceptionInternal(string classAndMethod, string message, Sys public static void Error(string className, string message, [CallerMemberName] string methodName = "") { - LogInternal(LogLevel.Error, className, message, methodName); + LogInternal(NLog.LogLevel.Error, className, message, methodName); } private static void LogInternal(LogLevel level, string className, string message, [CallerMemberName] string methodName = "") @@ -149,17 +154,17 @@ private static void LogInternal(LogLevel level, string className, string message public static void Debug(string className, string message, [CallerMemberName] string methodName = "") { - LogInternal(LogLevel.Debug, className, message, methodName); + LogInternal(NLog.LogLevel.Debug, className, message, methodName); } public static void Info(string className, string message, [CallerMemberName] string methodName = "") { - LogInternal(LogLevel.Info, className, message, methodName); + LogInternal(NLog.LogLevel.Info, className, message, methodName); } public static void Warn(string className, string message, [CallerMemberName] string methodName = "") { - LogInternal(LogLevel.Warn, className, message, methodName); + LogInternal(NLog.LogLevel.Warn, className, message, methodName); } } diff --git a/Flow.Launcher.Infrastructure/Stopwatch.cs b/Flow.Launcher.Infrastructure/Stopwatch.cs index 870e0fe263a..2afd3945fc0 100644 --- a/Flow.Launcher.Infrastructure/Stopwatch.cs +++ b/Flow.Launcher.Infrastructure/Stopwatch.cs @@ -17,7 +17,8 @@ public static long Debug(string className, string message, Action action, [Calle action(); stopWatch.Stop(); var milliseconds = stopWatch.ElapsedMilliseconds; - Log.Debug(className, $"{message} <{milliseconds}ms>", methodName); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(className, $"{message} <{milliseconds}ms>", methodName); return milliseconds; } @@ -31,7 +32,8 @@ public static async Task DebugAsync(string className, string message, Func await action(); stopWatch.Stop(); var milliseconds = stopWatch.ElapsedMilliseconds; - Log.Debug(className, $"{message} <{milliseconds}ms>", methodName); + if (Log.LogLevel == LOGLEVEL.DEBUG) + Log.Debug(className, $"{message} <{milliseconds}ms>", methodName); return milliseconds; } From 8387e722d440fe50b45e34fb43e558e972fc9bfa Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 26 Nov 2025 18:53:42 +0800 Subject: [PATCH 3/5] Refactor logging system and remove unused dependencies Replaced `FlowSettings.LogLevel` with `PublicApi.Instance.GetLogLevel()` for dynamic log level retrieval. Introduced a centralized `LOGLEVEL` enum in the `Flow.Launcher.Plugin` namespace to standardize log level definitions. Added `GetLogLevel()` to the `IPublicAPI` interface for plugin access. Removed the dependency on `CommunityToolkit.Mvvm.DependencyInjection` and unused namespaces across multiple files. Updated `PublicAPIInstance` to use a `Lock` type for `_saveSettingsLock`. Introduced a new `LogLevel.cs` file for the `LOGLEVEL` enum and removed the old enum from `Flow.Launcher.Infrastructure.Logger`. Improved modularity, maintainability, and extensibility of the logging system while streamlining the codebase. --- Flow.Launcher.Core/Plugin/PluginManager.cs | 7 ++--- Flow.Launcher.Core/Plugin/PluginsLoader.cs | 4 +-- Flow.Launcher.Infrastructure/Http/Http.cs | 1 + Flow.Launcher.Infrastructure/Logger/Log.cs | 9 +------ Flow.Launcher.Infrastructure/Stopwatch.cs | 1 + Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 6 +++++ Flow.Launcher.Plugin/LogLevel.cs | 27 +++++++++++++++++++ Flow.Launcher/PublicAPIInstance.cs | 6 +++-- 8 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 Flow.Launcher.Plugin/LogLevel.cs diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 7ab8c2e4221..f44ece6c21c 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -6,12 +6,10 @@ using System.Text.Json; using System.Threading; using System.Threading.Tasks; -using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; -using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; @@ -34,7 +32,6 @@ public static class PluginManager private static readonly ConcurrentDictionary _nonGlobalPlugins = []; private static PluginsSettings Settings; - private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService(); private static readonly ConcurrentBag ModifiedPlugins = []; private static readonly ConcurrentBag _contextMenuPlugins = []; @@ -280,14 +277,14 @@ public static async Task InitializePluginsAsync(IResultUpdateRegister register) { // If this plugin is already disabled, do not show error message again // Or else it will be shown every time - if (FlowSettings.LogLevel == LOGLEVEL.DEBUG) + if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG) PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error"); } else { pair.Metadata.Disabled = true; pair.Metadata.HomeDisabled = true; - if (FlowSettings.LogLevel == LOGLEVEL.DEBUG) + if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG) PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed"); } diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs index a8f61e2a360..b0005f72bcb 100644 --- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.ExternalPlugins.Environments; #pragma warning disable IDE0005 using Flow.Launcher.Infrastructure.Logger; @@ -15,7 +14,6 @@ namespace Flow.Launcher.Core.Plugin public static class PluginsLoader { private static readonly string ClassName = nameof(PluginsLoader); - private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService(); public static List Plugins(List metadatas, PluginsSettings settings) { @@ -110,7 +108,7 @@ private static List DotNetPlugins(List source) }); metadata.InitTime += milliseconds; - if (FlowSettings.LogLevel == LOGLEVEL.DEBUG) + if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG) PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>"); } diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index eccd0372f9d..aaa3acea11f 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; using JetBrains.Annotations; namespace Flow.Launcher.Infrastructure.Http diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 26c9d5251d1..e2e155452a6 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; using NLog; using NLog.Config; using NLog.Targets; @@ -167,12 +168,4 @@ public static void Warn(string className, string message, [CallerMemberName] str LogInternal(NLog.LogLevel.Warn, className, message, methodName); } } - - public enum LOGLEVEL - { - NONE, - ERROR, - INFO, - DEBUG - } } diff --git a/Flow.Launcher.Infrastructure/Stopwatch.cs b/Flow.Launcher.Infrastructure/Stopwatch.cs index 2afd3945fc0..7758e9d8c22 100644 --- a/Flow.Launcher.Infrastructure/Stopwatch.cs +++ b/Flow.Launcher.Infrastructure/Stopwatch.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Infrastructure { diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 93844159f75..f56df514c37 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -637,5 +637,11 @@ public interface IPublicAPI /// /// string GetLogDirectory(); + + /// + /// Get the current log level of Flow Launcher. + /// + /// + LOGLEVEL GetLogLevel(); } } diff --git a/Flow.Launcher.Plugin/LogLevel.cs b/Flow.Launcher.Plugin/LogLevel.cs new file mode 100644 index 00000000000..6cc97c0ceed --- /dev/null +++ b/Flow.Launcher.Plugin/LogLevel.cs @@ -0,0 +1,27 @@ +namespace Flow.Launcher.Plugin; + +/// +/// Log level enum used in Flow +/// +public enum LOGLEVEL +{ + /// + /// No log will be produced + /// + NONE, + + /// + /// Only error log will be produced + /// + ERROR, + + /// + /// Info and error log will be produced + /// + INFO, + + /// + /// Debug, info and error log will be produced + /// + DEBUG +} diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 55737151af3..a3e9710d888 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; @@ -52,7 +52,7 @@ public class PublicAPIInstance : IPublicAPI, IRemovable private Updater _updater; private Updater Updater => _updater ??= Ioc.Default.GetRequiredService(); - private readonly object _saveSettingsLock = new(); + private readonly Lock _saveSettingsLock = new(); #region Constructor @@ -623,6 +623,8 @@ public event ActualApplicationThemeChangedEventHandler ActualApplicationThemeCha public string GetLogDirectory() => DataLocation.VersionLogDirectory; + public LOGLEVEL GetLogLevel() => Log.LogLevel; + #endregion #region Private Methods From 46986bb1148d5470ab1efe6eec0b1886d13dcc98 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 26 Nov 2025 18:59:50 +0800 Subject: [PATCH 4/5] Refactor logging to use App.API and clean up namespaces Replaced direct usage of `Settings.LogLevel` with `App.API.GetLogLevel()` to centralize log level retrieval and align with the updated API. Updated logging calls to use `App.API.LogDebug` for consistency. Removed the `using Flow.Launcher.Infrastructure.Logger;` directive from `MainViewModel.cs` and `ResultsViewModel.cs`, as logging is now accessed through `App.API`. Cleaned up unused namespaces in `ResultsViewModel.cs`. Added `using CommunityToolkit.Mvvm.Input;` in `MainViewModel.cs` to support new MVVM-related functionality. Improved code readability and maintainability by reducing redundancy in log level checks and logging calls. --- Flow.Launcher/ViewModel/MainViewModel.cs | 13 ++++++------- Flow.Launcher/ViewModel/ResultsViewModel.cs | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index f6738c01ffa..c2d2f0fbb7e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -19,7 +19,6 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; using Flow.Launcher.Infrastructure.Hotkey; -using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -315,7 +314,7 @@ public void RegisterResultsUpdatedEvent(PluginPair pair) if (token.IsCancellationRequested) return; - if (Settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Update results for plugin <{pair.Metadata.Name}>"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, @@ -1384,7 +1383,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b { _updateSource?.Cancel(); - if (Settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Start query with text: <{QueryText}>"); var query = await ConstructQueryAsync(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts); @@ -1395,7 +1394,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b return; } - if (Settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>"); var currentIsHomeQuery = query.IsHomeQuery; @@ -1460,7 +1459,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b } } - if (Settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}"); // Do not wait for performance improvement @@ -1565,7 +1564,7 @@ void ClearResults() async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) { - if (Settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>"); if (searchDelay && !currentIsHomeQuery) // Do not delay for home query @@ -1610,7 +1609,7 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : if (token.IsCancellationRequested) return; - if (Settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 6933e0963bc..d75bc5e4ccd 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -8,7 +8,6 @@ using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; -using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -254,7 +253,7 @@ private List NewResults(ICollection resultsFo return newResults.OrderByDescending(rv => rv.Result.Score).ToList(); } - if (_settings.LogLevel == LOGLEVEL.DEBUG) + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) App.API.LogDebug(ClassName, $"Keeping existing results for {resultsForUpdates.Count} queries"); return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) From 8256dd09f1b76a04dc497b1fce5e233cd64c67e5 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 28 Nov 2025 07:17:41 +1100 Subject: [PATCH 5/5] typo --- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index f56df514c37..6e08538397d 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -639,7 +639,7 @@ public interface IPublicAPI string GetLogDirectory(); /// - /// Get the current log level of Flow Launcher. + /// Get the current log level for Flow Launcher. /// /// LOGLEVEL GetLogLevel();