From f80ae3092e11eb5c6023e5f3147e5f6a381168e4 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 11 Jun 2021 12:40:07 +0800 Subject: [PATCH 01/13] CherryPick Exception Optimize --- Flow.Launcher.Core/Plugin/PluginManager.cs | 8 +- .../Flow.Launcher.Infrastructure.csproj | 2 + Flow.Launcher.Infrastructure/Logger/Log.cs | 25 +-- Flow.Launcher/ViewModel/MainViewModel.cs | 160 ++++++++++-------- Flow.Launcher/ViewModel/ResultsForUpdate.cs | 4 +- .../Search/WindowsIndex/IndexSearch.cs | 25 +-- 6 files changed, 122 insertions(+), 102 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 59f34de74..50ff27f08 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -157,7 +157,7 @@ namespace Flow.Launcher.Core.Plugin } } - public static async Task> QueryForPlugin(PluginPair pair, Query query, CancellationToken token) + public static async Task> QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token) { var results = new List(); try @@ -171,7 +171,7 @@ namespace Flow.Launcher.Core.Plugin token.ThrowIfCancellationRequested(); if (results == null) - return results; + return null; UpdatePluginMetadata(results, metadata, query); metadata.QueryCount += 1; @@ -184,10 +184,6 @@ namespace Flow.Launcher.Core.Plugin // null will be fine since the results will only be added into queue if the token hasn't been cancelled return null; } - catch (Exception e) - { - Log.Exception($"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", e); - } return results; } diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 2f919b5c9..a13c8f1e7 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -49,6 +49,8 @@ + + diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 94132b27f..f39430c65 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -5,6 +5,9 @@ using NLog; using NLog.Config; using NLog.Targets; using Flow.Launcher.Infrastructure.UserSettings; +using JetBrains.Annotations; +using NLog.Targets.Wrappers; +using System.Runtime.ExceptionServices; namespace Flow.Launcher.Infrastructure.Logger { @@ -23,11 +26,13 @@ namespace Flow.Launcher.Infrastructure.Logger } var configuration = new LoggingConfiguration(); - var target = new FileTarget(); - configuration.AddTarget("file", target); - target.FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt"; + var fileTarget = new FileTarget(); + fileTarget.FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt"; + + var fileTargetASyncWrapper = new AsyncTargetWrapper(fileTarget); + configuration.AddTarget("file", fileTargetASyncWrapper); #if DEBUG - var rule = new LoggingRule("*", LogLevel.Debug, target); + var rule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper); #else var rule = new LoggingRule("*", LogLevel.Info, target); #endif @@ -50,13 +55,12 @@ namespace Flow.Launcher.Infrastructure.Logger return valid; } - - - [MethodImpl(MethodImplOptions.Synchronized)] + public static void Exception(string className, string message, System.Exception exception, [CallerMemberName] string methodName = "") - { + { + exception = exception.Demystify(); #if DEBUG - throw exception; + ExceptionDispatchInfo.Capture(exception).Throw(); #else var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName); @@ -131,8 +135,9 @@ namespace Flow.Launcher.Infrastructure.Logger [MethodImpl(MethodImplOptions.Synchronized)] public static void Exception(string message, System.Exception e) { + e = e.Demystify(); #if DEBUG - throw e; + ExceptionDispatchInfo.Capture(e).Throw(); #else if (FormatValid(message)) { diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ee36e11d8..c7d8fa4a2 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -19,8 +19,10 @@ using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Storage; using Flow.Launcher.Infrastructure.Logger; +using Microsoft.VisualStudio.Threading; using System.Threading.Channels; using ISavable = Flow.Launcher.Plugin.ISavable; +using System.Windows.Threading; namespace Flow.Launcher.ViewModel { @@ -110,7 +112,9 @@ namespace Flow.Launcher.ViewModel } Log.Error("MainViewModel", "Unexpected ResultViewUpdate ends"); - }; + } + + ; void continueAction(Task t) { @@ -118,7 +122,7 @@ namespace Flow.Launcher.ViewModel throw t.Exception; #else Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}"); - _resultsViewUpdateTask = + _resultsViewUpdateTask = Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted); #endif } @@ -137,7 +141,8 @@ namespace Flow.Launcher.ViewModel if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken))) { Log.Error("MainViewModel", "Unable to add item to Result Update Queue"); - }; + } + ; } }; } @@ -237,21 +242,24 @@ namespace Flow.Launcher.ViewModel ReloadPluginDataCommand = new RelayCommand(_ => { - var msg = new Msg { Owner = Application.Current.MainWindow }; + var msg = new Msg + { + Owner = Application.Current.MainWindow + }; MainWindowVisibility = Visibility.Collapsed; PluginManager - .ReloadData() - .ContinueWith(_ => - Application.Current.Dispatcher.Invoke(() => - { - msg.Show( - InternationalizationManager.Instance.GetTranslation("success"), - InternationalizationManager.Instance.GetTranslation("completedSuccessfully"), - ""); - })) - .ConfigureAwait(false); + .ReloadData() + .ContinueWith(_ => + Application.Current.Dispatcher.Invoke(() => + { + msg.Show( + InternationalizationManager.Instance.GetTranslation("success"), + InternationalizationManager.Instance.GetTranslation("completedSuccessfully"), + ""); + })) + .ConfigureAwait(false); }); } @@ -422,7 +430,10 @@ namespace Flow.Launcher.ViewModel Title = string.Format(title, h.Query), SubTitle = string.Format(time, h.ExecutedDateTime), IcoPath = "Images\\history.png", - OriginQuery = new Query { RawQuery = h.Query }, + OriginQuery = new Query + { + RawQuery = h.Query + }, Action = _ => { SelectedResults = Results; @@ -448,7 +459,9 @@ namespace Flow.Launcher.ViewModel } } - private void QueryResults() + private readonly IReadOnlyList _emptyResult = new List(); + + private async void QueryResults() { _updateSource?.Cancel(); @@ -478,74 +491,73 @@ namespace Flow.Launcher.ViewModel var plugins = PluginManager.ValidPluginsForQuery(query); - Task.Run(async () => + if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign) + { + // Wait 45 millisecond for query change in global query + // if query changes, return so that it won't be calculated + await Task.Delay(45, currentCancellationToken); + if (currentCancellationToken.IsCancellationRequested) + return; + } + + _ = Task.Delay(200, currentCancellationToken).ContinueWith(_ => + { + // start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet + if (!currentCancellationToken.IsCancellationRequested && _isQueryRunning) { - if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign) - { - // Wait 45 millisecond for query change in global query - // if query changes, return so that it won't be calculated - await Task.Delay(45, currentCancellationToken); - if (currentCancellationToken.IsCancellationRequested) - return; - } + ProgressBarVisibility = Visibility.Visible; + } + }, currentCancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); - _ = Task.Delay(200, currentCancellationToken).ContinueWith(_ => - { - // start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet - if (!currentCancellationToken.IsCancellationRequested && _isQueryRunning) - { - ProgressBarVisibility = Visibility.Visible; - } - }, currentCancellationToken); + // plugins is ICollection, meaning LINQ will get the Count and preallocate Array - // plugins is ICollection, meaning LINQ will get the Count and preallocate Array + var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch + { + false => QueryTask(plugin), + true => Task.CompletedTask + }).ToArray(); - Task[] tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch - { - false => QueryTask(plugin), - true => Task.CompletedTask - }).ToArray(); - try - { - // Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first - await Task.WhenAll(tasks); - } - catch (OperationCanceledException) - { - // nothing to do here - } + try + { + // Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first + await Task.WhenAll(tasks); + } + catch (OperationCanceledException) + { + // nothing to do here + } - if (currentCancellationToken.IsCancellationRequested) - return; + if (currentCancellationToken.IsCancellationRequested) + return; - // this should happen once after all queries are done so progress bar should continue - // until the end of all querying - _isQueryRunning = false; - if (!currentCancellationToken.IsCancellationRequested) - { - // update to hidden if this is still the current query - ProgressBarVisibility = Visibility.Hidden; - } + // this should happen once after all queries are done so progress bar should continue + // until the end of all querying + _isQueryRunning = false; + if (!currentCancellationToken.IsCancellationRequested) + { + // update to hidden if this is still the current query + ProgressBarVisibility = Visibility.Hidden; + } - // Local function - async Task QueryTask(PluginPair plugin) - { - // Since it is wrapped within a Task.Run, the synchronous context is null - // Task.Yield will force it to run in ThreadPool - await Task.Yield(); + // Local function + async Task QueryTask(PluginPair plugin) + { + // Since it is wrapped within a Task.Run, the synchronous context is null + // Task.Yield will force it to run in ThreadPool + await Task.Yield(); - var results = await PluginManager.QueryForPlugin(plugin, query, currentCancellationToken); - if (currentCancellationToken.IsCancellationRequested || results == null) return; + IReadOnlyList results = await PluginManager.QueryForPluginAsync(plugin, query, currentCancellationToken); + + currentCancellationToken.ThrowIfCancellationRequested(); - if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken))) - { - Log.Error("MainViewModel", "Unable to add item to Result Update Queue"); - }; - } - }, currentCancellationToken) - .ContinueWith(t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception), - TaskContinuationOptions.OnlyOnFaulted); + results ??= _emptyResult; + + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken))) + { + Log.Error("MainViewModel", "Unable to add item to Result Update Queue"); + } + } } diff --git a/Flow.Launcher/ViewModel/ResultsForUpdate.cs b/Flow.Launcher/ViewModel/ResultsForUpdate.cs index 87d526fd6..94c6a923a 100644 --- a/Flow.Launcher/ViewModel/ResultsForUpdate.cs +++ b/Flow.Launcher/ViewModel/ResultsForUpdate.cs @@ -8,7 +8,7 @@ namespace Flow.Launcher.ViewModel { public struct ResultsForUpdate { - public List Results { get; } + public IReadOnlyList Results { get; } public PluginMetadata Metadata { get; } public string ID { get; } @@ -16,7 +16,7 @@ namespace Flow.Launcher.ViewModel public Query Query { get; } public CancellationToken Token { get; } - public ResultsForUpdate(List results, PluginMetadata metadata, Query query, CancellationToken token) + public ResultsForUpdate(IReadOnlyList results, PluginMetadata metadata, Query query, CancellationToken token) { Results = results; Metadata = metadata; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs index 0748b0cfe..cfb564924 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs @@ -17,20 +17,20 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex // Reserved keywords in oleDB private const string reservedStringPattern = @"^[`\@\#\^,\&\/\\\$\%_]+$"; - internal async static Task> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token) + internal static async Task> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token) { var results = new List(); var fileResults = new List(); try { - using var conn = new OleDbConnection(connectionString); + await using var conn = new OleDbConnection(connectionString); await conn.OpenAsync(token); token.ThrowIfCancellationRequested(); - using var command = new OleDbCommand(indexQueryString, conn); + await using var command = new OleDbCommand(indexQueryString, conn); // Results return as an OleDbDataReader. - using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader; + await using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader; token.ThrowIfCancellationRequested(); if (dataReaderResults.HasRows) @@ -42,18 +42,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex { // # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path var encodedFragmentPath = dataReaderResults - .GetString(1) - .Replace("#", "%23", StringComparison.OrdinalIgnoreCase); + .GetString(1) + .Replace("#", "%23", StringComparison.OrdinalIgnoreCase); var path = new Uri(encodedFragmentPath).LocalPath; if (dataReaderResults.GetString(2) == "Directory") { results.Add(ResultManager.CreateFolderResult( - dataReaderResults.GetString(0), - path, - path, - query, 0, true, true)); + dataReaderResults.GetString(0), + path, + path, + query, 0, true, true)); } else { @@ -63,6 +63,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex } } } + catch (OperationCanceledException) + { + // return empty result when cancelled + return results; + } catch (InvalidOperationException e) { // Internal error from ExecuteReader(): Connection closed. From e8abd7c23f1025b2d03ae2a4d15a9d5fb1bf5a27 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 11 Jun 2021 12:43:31 +0800 Subject: [PATCH 02/13] fix a variable name in Release --- Flow.Launcher.Infrastructure/Logger/Log.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index f39430c65..1784726d9 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -34,7 +34,7 @@ namespace Flow.Launcher.Infrastructure.Logger #if DEBUG var rule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper); #else - var rule = new LoggingRule("*", LogLevel.Info, target); + var rule = new LoggingRule("*", LogLevel.Info, fileTargetASyncWrapper); #endif configuration.LoggingRules.Add(rule); LogManager.Configuration = configuration; From a75a5c46604d3632a4f90ee07434227e4f849935 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 11 Jun 2021 12:44:48 +0800 Subject: [PATCH 03/13] inline initialization --- Flow.Launcher.Infrastructure/Logger/Log.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 1784726d9..4b69c7791 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -26,9 +26,11 @@ namespace Flow.Launcher.Infrastructure.Logger } var configuration = new LoggingConfiguration(); - var fileTarget = new FileTarget(); - fileTarget.FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt"; - + var fileTarget = new FileTarget + { + FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt" + }; + var fileTargetASyncWrapper = new AsyncTargetWrapper(fileTarget); configuration.AddTarget("file", fileTargetASyncWrapper); #if DEBUG From 8fe285bbecaa612a2dce66ffec84f692f32ce220 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 11 Jun 2021 15:08:26 +0800 Subject: [PATCH 04/13] Use Nlog Debug Target instead of direct print --- Flow.Launcher.Infrastructure/Logger/Log.cs | 24 ++++++++++++------- .../Logger/ProgramLogger.cs | 2 -- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 4b69c7791..8a899263e 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -32,13 +32,23 @@ namespace Flow.Launcher.Infrastructure.Logger }; var fileTargetASyncWrapper = new AsyncTargetWrapper(fileTarget); + + var debugTarget = new DebuggerTarget + { + Layout = "${level:uppercase=true}|${message}" + }; + configuration.AddTarget("file", fileTargetASyncWrapper); + configuration.AddTarget("console", debugTarget); #if DEBUG - var rule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper); + var fileRule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper); + var debugRule = new LoggingRule("*", LogLevel.Debug, debugTarget); #else var rule = new LoggingRule("*", LogLevel.Info, fileTargetASyncWrapper); + var debugRule = new LoggingRule("*", LogLevel.Info, consoleTarget); #endif - configuration.LoggingRules.Add(rule); + configuration.LoggingRules.Add(fileRule); + configuration.LoggingRules.Add(debugRule); LogManager.Configuration = configuration; } @@ -46,7 +56,6 @@ namespace Flow.Launcher.Infrastructure.Logger { var logger = LogManager.GetLogger("FaultyLogger"); message = $"Wrong logger message format <{message}>"; - System.Diagnostics.Debug.WriteLine($"FATAL|{message}"); logger.Fatal(message); } @@ -57,9 +66,9 @@ namespace Flow.Launcher.Infrastructure.Logger return valid; } - + public static void Exception(string className, string message, System.Exception exception, [CallerMemberName] string methodName = "") - { + { exception = exception.Demystify(); #if DEBUG ExceptionDispatchInfo.Capture(exception).Throw(); @@ -96,7 +105,6 @@ namespace Flow.Launcher.Infrastructure.Logger { var logger = LogManager.GetLogger(classAndMethod); - System.Diagnostics.Debug.WriteLine($"ERROR|{message}"); logger.Error("-------------------------- Begin exception --------------------------"); logger.Error(message); @@ -123,8 +131,6 @@ namespace Flow.Launcher.Infrastructure.Logger var prefix = parts[1]; var unprefixed = parts[2]; var logger = LogManager.GetLogger(prefix); - - System.Diagnostics.Debug.WriteLine($"{level.Name}|{message}"); logger.Log(level, unprefixed); } else @@ -134,6 +140,7 @@ namespace Flow.Launcher.Infrastructure.Logger } /// example: "|prefix|unprefixed" + /// Exception [MethodImpl(MethodImplOptions.Synchronized)] public static void Exception(string message, System.Exception e) { @@ -172,7 +179,6 @@ namespace Flow.Launcher.Infrastructure.Logger var logger = LogManager.GetLogger(classNameWithMethod); - System.Diagnostics.Debug.WriteLine($"{level.Name}|{message}"); logger.Log(level, message); } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs b/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs index 06264c06c..62ce539f3 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs @@ -48,8 +48,6 @@ namespace Flow.Launcher.Plugin.Program.Logger internal static void LogException(string classname, string callingMethodName, string loadingProgramPath, string interpretationMessage, Exception e) { - Debug.WriteLine($"ERROR{classname}|{callingMethodName}|{loadingProgramPath}|{interpretationMessage}"); - var logger = LogManager.GetLogger(""); var innerExceptionNumber = 1; From b955fde6e5190f2b7ca047f0a23fc5e94b1eee09 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 11 Jun 2021 21:39:12 +0800 Subject: [PATCH 05/13] Use NLog Exception Handler, and , NLog Debug Message Printer, and change layout --- Flow.Launcher.Core/Plugin/PluginManager.cs | 4 ++ .../Flow.Launcher.Infrastructure.csproj | 5 ++- Flow.Launcher.Infrastructure/Logger/Log.cs | 40 ++++++++----------- Flow.Launcher/Helper/ErrorReporting.cs | 4 +- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 50ff27f08..2f45121ca 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -184,6 +184,10 @@ namespace Flow.Launcher.Core.Plugin // null will be fine since the results will only be added into queue if the token hasn't been cancelled return null; } + catch (Exception e) + { + Log.Exception("PluginManager", "Exception", e); + } return results; } diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index a13c8f1e7..aea43506e 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -51,8 +51,9 @@ - - + + + diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 8a899263e..a19c0c365 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -6,8 +6,10 @@ using NLog.Config; using NLog.Targets; using Flow.Launcher.Infrastructure.UserSettings; using JetBrains.Annotations; +using NLog.Fluent; using NLog.Targets.Wrappers; using System.Runtime.ExceptionServices; +using System.Text; namespace Flow.Launcher.Infrastructure.Logger { @@ -26,29 +28,33 @@ namespace Flow.Launcher.Infrastructure.Logger } var configuration = new LoggingConfiguration(); + + const string layout = @"${logger}->${time}|${level}|${message}|${onexception:inner=${logger}->${date:format=HH\:mm\:ss}|${level}|${message}|${newline}${exception:format=toString}${newline}"; + var fileTarget = new FileTarget { - FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt" + FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt", + Layout = layout }; var fileTargetASyncWrapper = new AsyncTargetWrapper(fileTarget); - var debugTarget = new DebuggerTarget + var debugTarget = new OutputDebugStringTarget { - Layout = "${level:uppercase=true}|${message}" + Layout = layout }; - + configuration.AddTarget("file", fileTargetASyncWrapper); - configuration.AddTarget("console", debugTarget); + configuration.AddTarget("debug", debugTarget); + #if DEBUG var fileRule = new LoggingRule("*", LogLevel.Debug, fileTargetASyncWrapper); var debugRule = new LoggingRule("*", LogLevel.Debug, debugTarget); + configuration.LoggingRules.Add(debugRule); #else - var rule = new LoggingRule("*", LogLevel.Info, fileTargetASyncWrapper); - var debugRule = new LoggingRule("*", LogLevel.Info, consoleTarget); + var fileRule = new LoggingRule("*", LogLevel.Info, fileTargetASyncWrapper); #endif configuration.LoggingRules.Add(fileRule); - configuration.LoggingRules.Add(debugRule); LogManager.Configuration = configuration; } @@ -105,22 +111,9 @@ namespace Flow.Launcher.Infrastructure.Logger { var logger = LogManager.GetLogger(classAndMethod); + var messageBuilder = new StringBuilder(); - logger.Error("-------------------------- Begin exception --------------------------"); - logger.Error(message); - - do - { - logger.Error($"Exception full name:\n <{e.GetType().FullName}>"); - logger.Error($"Exception message:\n <{e.Message}>"); - logger.Error($"Exception stack trace:\n <{e.StackTrace}>"); - logger.Error($"Exception source:\n <{e.Source}>"); - logger.Error($"Exception target site:\n <{e.TargetSite}>"); - logger.Error($"Exception HResult:\n <{e.HResult}>"); - e = e.InnerException; - } while (e != null); - - logger.Error("-------------------------- End exception --------------------------"); + logger.Error(e, message); } private static void LogInternal(string message, LogLevel level) @@ -141,7 +134,6 @@ namespace Flow.Launcher.Infrastructure.Logger /// example: "|prefix|unprefixed" /// Exception - [MethodImpl(MethodImplOptions.Synchronized)] public static void Exception(string message, System.Exception e) { e = e.Demystify(); diff --git a/Flow.Launcher/Helper/ErrorReporting.cs b/Flow.Launcher/Helper/ErrorReporting.cs index 94e2ed2bc..f3f590167 100644 --- a/Flow.Launcher/Helper/ErrorReporting.cs +++ b/Flow.Launcher/Helper/ErrorReporting.cs @@ -3,6 +3,8 @@ using System.Windows.Threading; using NLog; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Exception; +using NLog.Fluent; +using Log = Flow.Launcher.Infrastructure.Logger.Log; namespace Flow.Launcher.Helper { @@ -45,4 +47,4 @@ namespace Flow.Launcher.Helper return info; } } -} +} \ No newline at end of file From da6dfcdf6d9b7a15bd069b14f9555e3653b166a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sun, 13 Jun 2021 22:33:51 +0800 Subject: [PATCH 06/13] CherryPick DirectoryInfoSearch.cs Exception Refactor --- .../Search/DirectoryInfo/DirectoryInfoSearch.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs index 14833bae9..14c90d57f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -21,7 +21,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo RecurseSubdirectories = true }, query, search, criteria, token); - return DirectorySearch(new EnumerationOptions(), query, search, criteria, token); // null will be passed as default + return DirectorySearch(new EnumerationOptions(), query, search, criteria, + token); // null will be passed as default } public static string ConstructSearchCriteria(string search) @@ -57,7 +58,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { var directoryInfo = new System.IO.DirectoryInfo(path); - foreach (var fileSystemInfo in directoryInfo.EnumerateFileSystemInfos(searchCriteria, enumerationOption)) + foreach (var fileSystemInfo in directoryInfo.EnumerateFileSystemInfos(searchCriteria, enumerationOption) + ) { if (fileSystemInfo is System.IO.DirectoryInfo) { @@ -74,17 +76,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo } catch (Exception e) { - if (!(e is ArgumentException)) - throw e; - + Log.Exception("Flow.Plugin.Explorer.", nameof(DirectoryInfoSearch), e); results.Add(new Result {Title = e.Message, Score = 501}); return results; - -#if DEBUG // Please investigate and handle error from DirectoryInfo search -#else - Log.Exception($"|Flow.Launcher.Plugin.Explorer.DirectoryInfoSearch|Error from performing DirectoryInfoSearch", e); -#endif } // Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection. From 4f13433913d34247ea8fb254cbc2d9a04786ed23 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Tue, 22 Jun 2021 13:05:38 +0800 Subject: [PATCH 07/13] CherryPick Layout change and ProgramLogger.cs Fix --- Flow.Launcher.Core/Plugin/PluginManager.cs | 4 ---- .../Logger/ProgramLogger.cs | 22 +------------------ 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 2f45121ca..50ff27f08 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -184,10 +184,6 @@ namespace Flow.Launcher.Core.Plugin // null will be fine since the results will only be added into queue if the token hasn't been cancelled return null; } - catch (Exception e) - { - Log.Exception("PluginManager", "Exception", e); - } return results; } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs b/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs index 62ce539f3..cbf4960a3 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs @@ -20,27 +20,6 @@ namespace Flow.Launcher.Plugin.Program.Logger { public const string DirectoryName = "Logs"; - static ProgramLogger() - { - var path = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Version); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - - var configuration = new LoggingConfiguration(); - var target = new FileTarget(); - configuration.AddTarget("file", target); - target.FileName = path.Replace(@"\", "/") + "/${shortdate}.txt"; -#if DEBUG - var rule = new LoggingRule("*", LogLevel.Debug, target); -#else - var rule = new LoggingRule("*", LogLevel.Error, target); -#endif - configuration.LoggingRules.Add(rule); - LogManager.Configuration = configuration; - } - /// /// Logs an exception /// @@ -101,6 +80,7 @@ namespace Flow.Launcher.Plugin.Program.Logger { var logger = LogManager.GetLogger(""); logger.Error(e, $"fail to log exception in program logger, parts length is too small: {parts.Length}, message: {message}"); + return; } var classname = parts[0]; From 89bb169fee7737833d46afbd33b7804e5ee73d8a Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Tue, 22 Jun 2021 23:52:53 +0800 Subject: [PATCH 08/13] allow warning pass exception (for known exception) --- Flow.Launcher.Plugin/IPublicAPI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/IPublicAPI.cs b/Flow.Launcher.Plugin/IPublicAPI.cs index d9cdf5581..214d6c116 100644 --- a/Flow.Launcher.Plugin/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/IPublicAPI.cs @@ -161,7 +161,7 @@ namespace Flow.Launcher.Plugin /// /// Log warning message /// - void LogWarn(string className, string message, [CallerMemberName] string methodName = ""); + void LogWarn(string className, string message, Exception e = null, [CallerMemberName] string methodName = ""); /// /// Log an Exception. Will throw if in debug mode so developer will be aware, From 11ca5f9bf370368f0402e950f9e6e8f358f76599 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 25 Jun 2021 14:43:47 +0800 Subject: [PATCH 09/13] revert unintended remove of await TaskScheduler.Default back --- Flow.Launcher/ViewModel/MainViewModel.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c7d8fa4a2..262c1848b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -482,6 +482,9 @@ namespace Flow.Launcher.ViewModel ProgressBarVisibility = Visibility.Hidden; _isQueryRunning = true; + // Switch to ThreadPool thread + await TaskScheduler.Default; + var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins); // handle the exclusiveness of plugin using action keyword @@ -543,7 +546,7 @@ namespace Flow.Launcher.ViewModel // Local function async Task QueryTask(PluginPair plugin) { - // Since it is wrapped within a Task.Run, the synchronous context is null + // Since it is wrapped within a ThreadPool Thread, the synchronous context is null // Task.Yield will force it to run in ThreadPool await Task.Yield(); From 9d9b5323c6b898fcad906ece573db34bae9ecb91 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Sat, 26 Jun 2021 15:42:27 +0800 Subject: [PATCH 10/13] check cancellation to avoid racing issue. --- Flow.Launcher/ViewModel/MainViewModel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 262c1848b..1bdf6af1e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -485,6 +485,9 @@ namespace Flow.Launcher.ViewModel // Switch to ThreadPool thread await TaskScheduler.Default; + if (currentCancellationToken.IsCancellationRequested) + return; + var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.NonGlobalPlugins); // handle the exclusiveness of plugin using action keyword From 486048c88422390e9c5e8975f0275ecc30e59826 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Tue, 22 Jun 2021 23:52:53 +0800 Subject: [PATCH 11/13] Revert Allow Warn paasing Exception --- Flow.Launcher.Plugin/IPublicAPI.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/IPublicAPI.cs b/Flow.Launcher.Plugin/IPublicAPI.cs index 214d6c116..d9cdf5581 100644 --- a/Flow.Launcher.Plugin/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/IPublicAPI.cs @@ -161,7 +161,7 @@ namespace Flow.Launcher.Plugin /// /// Log warning message /// - void LogWarn(string className, string message, Exception e = null, [CallerMemberName] string methodName = ""); + void LogWarn(string className, string message, [CallerMemberName] string methodName = ""); /// /// Log an Exception. Will throw if in debug mode so developer will be aware, From caf7cb5188f4bfb72de42301444c5fc430fca57c Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Fri, 25 Jun 2021 17:52:42 +0800 Subject: [PATCH 12/13] CherryPick Adjust Logging Layout --- Flow.Launcher.Infrastructure/Logger/Log.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index a19c0c365..dc4207279 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -29,7 +29,11 @@ namespace Flow.Launcher.Infrastructure.Logger var configuration = new LoggingConfiguration(); - const string layout = @"${logger}->${time}|${level}|${message}|${onexception:inner=${logger}->${date:format=HH\:mm\:ss}|${level}|${message}|${newline}${exception:format=toString}${newline}"; + const string layout = + @"${date:format=HH\:mm\:ss.ffffK} - " + + @"${level:uppercase=true} - ${logger} - ${message:l}" + + @"${onexception:${newline}${newline}" + + @"EXCEPTION OCCURS\: ${exception:format=tostring}${newline}}"; var fileTarget = new FileTarget { From d7ec0c183447ea3028d77d1743abbab36d985064 Mon Sep 17 00:00:00 2001 From: Kevin Zhang Date: Sat, 26 Jun 2021 18:11:36 +0800 Subject: [PATCH 13/13] Add padding and Remove one newline indicating Exception --- Flow.Launcher.Infrastructure/Logger/Log.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index dc4207279..26e305ace 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -31,8 +31,8 @@ namespace Flow.Launcher.Infrastructure.Logger const string layout = @"${date:format=HH\:mm\:ss.ffffK} - " + - @"${level:uppercase=true} - ${logger} - ${message:l}" + - @"${onexception:${newline}${newline}" + + @"${level:uppercase=true:padding=-5} - ${logger} - ${message:l}" + + @"${onexception:${newline}" + @"EXCEPTION OCCURS\: ${exception:format=tostring}${newline}}"; var fileTarget = new FileTarget