Browse Source

Improved unhandled exceptions

Kenric Nugteren 1 year ago
parent
commit
ad1543fac8
1 changed files with 76 additions and 4 deletions
  1. 76 4
      prs.desktop/App.xaml.cs

+ 76 - 4
prs.desktop/App.xaml.cs

@@ -318,11 +318,50 @@ namespace PRSDesktop
             };
         }
 
+        private class UnhandledException
+        {
+            private string _message;
+            public string Message
+            {
+                get => _message;
+                set
+                {
+                    _message = value;
+                    Hash = GenerateExceptionHash(value);
+                }
+            }
+
+            public DateTime OriginalTime { get; set; }
+
+            public DateTime LastTime { get; set; }
+
+            public DateTime LastPrinted { get; set; }
+
+            public int Occurences { get; set; }
+
+            public int Hash { get; private set; }
+        }
+
+        private static TimeSpan RepeatedExceptionThreshold = TimeSpan.FromSeconds(10);
+
+        private static Queue<UnhandledException> PreviousUnhandledExceptions { get; set; } = new Queue<UnhandledException>();
+
+        private static int GenerateExceptionHash(string message)
+        {
+            return message.GetHashCode();
+        }
+
+        private static void ClearUnhandledExceptions()
+        {
+            while (PreviousUnhandledExceptions.TryPeek(out var e) && DateTime.Now - e.LastTime > RepeatedExceptionThreshold)
+            {
+                PreviousUnhandledExceptions.Dequeue();
+            }
+        }
+
         private void LogUnhandledException(Exception exception, string source)
         {
-            // Hacky Hack Hack FastReport.WPF throwing errors here
-            if (exception.Message.Contains("Must create DependencySource on same Thread as the DependencyObject."))
-                return;
+            ClearUnhandledExceptions();
             
             var messages = new List<string>();
             var e2 = exception;
@@ -332,7 +371,40 @@ namespace PRSDesktop
                 e2 = e2.InnerException;
             }
 
-            MainLogger.Send(LogType.Error, "", string.Join("\n", messages));
+            var unhandled = new UnhandledException
+            {
+                Message = string.Join("\n", messages),
+                OriginalTime = DateTime.Now,
+                Occurences = 1
+            };
+            unhandled.LastTime = unhandled.OriginalTime;
+            unhandled.LastPrinted = unhandled.OriginalTime;
+
+            UnhandledException? found = null;
+            foreach(var e in PreviousUnhandledExceptions)
+            {
+                if(e.Hash == unhandled.Hash)
+                {
+                    e.LastTime = unhandled.LastTime;
+                    e.Occurences++;
+                    found = e;
+                    break;
+                }
+            }
+            if (found is null)
+            {
+                PreviousUnhandledExceptions.Enqueue(unhandled);
+                MainLogger.Send(LogType.Error, "", string.Join("\n", messages));
+            }
+            else
+            {
+                if((DateTime.Now - found.LastPrinted).TotalSeconds >= 1)
+                {
+                    MainLogger.Send(LogType.Error, "", $"Recurrent Error occurred {found.Occurences} times; See {found.OriginalTime}");
+                    found.LastPrinted = DateTime.Now;
+                }
+            }
+
 
             // if (exception.Message.StartsWith("Dispatcher processing has been suspended"))
             //     try