diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 54712942c28..f44ece6c21c 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -277,13 +277,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 (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; - PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed"); + if (PublicApi.Instance.GetLogLevel() == 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..b0005f72bcb 100644 --- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs @@ -108,7 +108,8 @@ private static List DotNetPlugins(List source) }); metadata.InitTime += milliseconds; - PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>"); + if (PublicApi.Instance.GetLogLevel() == LOGLEVEL.DEBUG) + PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>"); } if (erroredPlugins.Count > 0) 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..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 @@ -146,7 +147,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 +160,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 +192,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 +204,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 +228,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..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; @@ -15,6 +16,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 +51,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 +68,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 +141,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,25 +155,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); } } - - public enum LOGLEVEL - { - NONE, - ERROR, - INFO, - DEBUG - } } diff --git a/Flow.Launcher.Infrastructure/Stopwatch.cs b/Flow.Launcher.Infrastructure/Stopwatch.cs index 870e0fe263a..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 { @@ -17,7 +18,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 +33,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; } diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 93844159f75..6e08538397d 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 for 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 diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c35f96e6200..c2d2f0fbb7e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -314,7 +314,8 @@ public void RegisterResultsUpdatedEvent(PluginPair pair) if (token.IsCancellationRequested) return; - App.API.LogDebug(ClassName, $"Update results for plugin <{pair.Metadata.Name}>"); + 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, token))) @@ -1382,7 +1383,8 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b { _updateSource?.Cancel(); - App.API.LogDebug(ClassName, $"Start query with text: <{QueryText}>"); + if (App.API.GetLogLevel() == LOGLEVEL.DEBUG) + App.API.LogDebug(ClassName, $"Start query with text: <{QueryText}>"); var query = await ConstructQueryAsync(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts); @@ -1392,7 +1394,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 (App.API.GetLogLevel() == 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 +1459,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 (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 /*if (string.IsNullOrEmpty(query.ActionKeyword)) @@ -1560,7 +1564,8 @@ void ClearResults() async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) { - App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>"); + 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 { @@ -1604,7 +1609,8 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : if (token.IsCancellationRequested) return; - App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>"); + 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, token, reSelect))) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 2f4ca6ccf36..d75bc5e4ccd 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -253,7 +253,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 (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)) .Concat(newResults) .OrderByDescending(rv => rv.Result.Score)