Explorar o código

Enhanced crash reports

CPKreuz hai 1 ano
pai
achega
16705ea919

+ 3 - 3
src/PixiEditor/Helpers/CrashHelper.cs

@@ -89,7 +89,7 @@ internal class CrashHelper
             while (innerException != null)
             {
                 builder
-                    .Append("\n-----Inner exception-----\n")
+                    .Append("\n------Inner exception------\n")
                     .Append(innerException.GetType().ToString())
                     .Append(": ")
                     .Append(innerException.Message);
@@ -98,14 +98,14 @@ internal class CrashHelper
         }
 
         builder
-            .Append("\n\n-------Stack trace-------\n")
+            .Append("\n\n--------Stack trace--------\n")
             .Append(e.StackTrace);
         {
             var innerException = e.InnerException;
             while (innerException != null)
             {
                 builder
-                    .Append("\n-----Inner exception-----\n")
+                    .Append("\n------Inner exception------\n")
                     .Append(innerException.StackTrace);
                 innerException = innerException.InnerException;
             }

+ 3 - 0
src/PixiEditor/Models/Commands/CommandController.cs

@@ -25,6 +25,8 @@ internal class CommandController
     public CommandCollection Commands { get; }
 
     public List<CommandGroup> CommandGroups { get; }
+    
+    public CommandLog.CommandLog Log { get; }
 
     public OneToManyDictionary<string, Command> FilterCommands { get; }
     
@@ -37,6 +39,7 @@ internal class CommandController
     public CommandController()
     {
         Current ??= this;
+        Log = new CommandLog.CommandLog();
 
         ShortcutsPath = Path.Join(
             Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),

+ 43 - 0
src/PixiEditor/Models/Commands/CommandLog/CommandLog.cs

@@ -0,0 +1,43 @@
+using System.Globalization;
+using System.Text;
+using PixiEditor.Models.Commands.Commands;
+
+namespace PixiEditor.Models.Commands.CommandLog;
+
+internal class CommandLog
+{
+    private readonly List<CommandLogEntry> list = new(MaxEntries);
+
+    private const int MaxEntries = 8;
+
+    public void Log(Command command, bool? canExecute)
+    {
+        if (canExecute.HasValue && !list[0].CanExecute.HasValue)
+        {
+            list[0].CanExecute = canExecute;
+            return;
+        }
+        
+        if (list.Count >= MaxEntries)
+        {
+            list.RemoveRange(MaxEntries - 1, list.Count - MaxEntries + 1);
+        }
+        
+        list.Insert(0, new CommandLogEntry(command, canExecute, DateTime.Now));
+    }
+
+    public string GetSummary(DateTime relativeTime)
+    {
+        var builder = new StringBuilder();
+
+        foreach (var entry in list)
+        {
+            var relativeSpan = entry.DateTime - relativeTime;
+            string canExecute = entry.CanExecute.HasValue ? entry.CanExecute.ToString() : "not executed";
+            
+            builder.AppendLine($"{entry.Command.InternalName} | CanExecute: {canExecute} | {entry.DateTime.ToString("O", CultureInfo.InvariantCulture)} | {relativeSpan.ToString("G", CultureInfo.InvariantCulture)}");
+        }
+
+        return builder.ToString();
+    }
+}

+ 19 - 0
src/PixiEditor/Models/Commands/CommandLog/CommandLogEntry.cs

@@ -0,0 +1,19 @@
+using PixiEditor.Models.Commands.Commands;
+
+namespace PixiEditor.Models.Commands.CommandLog;
+
+internal class CommandLogEntry
+{
+    public Command Command { get; }
+
+    public bool? CanExecute { get; set; }
+    
+    public DateTime DateTime { get; }
+    
+    public CommandLogEntry(Command command, bool? commandMethod, DateTime dateTime)
+    {
+        Command = command;
+        CanExecute = commandMethod;
+        DateTime = dateTime;
+    }
+}

+ 19 - 3
src/PixiEditor/Models/Commands/CommandMethods.cs

@@ -1,4 +1,5 @@
-using PixiEditor.Models.Commands.Commands;
+using PixiEditor.Models.Commands.CommandLog;
+using PixiEditor.Models.Commands.Commands;
 using PixiEditor.Models.Commands.Evaluators;
 
 namespace PixiEditor.Models.Commands;
@@ -18,11 +19,26 @@ internal class CommandMethods
 
     public void Execute(object parameter)
     {
-        if (CanExecute(parameter))
+        var log = CommandController.Current?.Log;
+        ToLog(log, null);
+        
+        if (!CanExecute(parameter))
         {
-            _execute(parameter);
+            ToLog(log, false);
+            return;
         }
+        ToLog(log, true);
+
+        _execute(parameter);
     }
 
     public bool CanExecute(object parameter) => _canExecute.CallEvaluate(_command, parameter);
+
+    private void ToLog(CommandLog.CommandLog? log, bool? canExecute)
+    {
+        if (log != null && _command != null)
+        {
+            log.Log(_command, canExecute);
+        }
+    }
 }

+ 27 - 0
src/PixiEditor/Models/DataHolders/CrashReport.cs

@@ -5,7 +5,9 @@ using System.IO.Compression;
 using System.Reflection;
 using System.Text;
 using Newtonsoft.Json;
+using PixiEditor.Extensions.Common.UserPreferences;
 using PixiEditor.Helpers;
+using PixiEditor.Models.Commands;
 using PixiEditor.Parser;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
@@ -56,6 +58,31 @@ internal class CrashReport : IDisposable
             builder.AppendLine($"Error ({memE.GetType().FullName}: {memE.Message}) while gathering memory information, skipping...");
         }
 
+        builder.AppendLine("\n--------Command Log--------\n");
+
+        try
+        {
+            builder.Append(CommandController.Current.Log.GetSummary(currentTime.LocalDateTime));
+        }
+        catch (Exception cemLogException)
+        {
+            builder.AppendLine($"Error ({cemLogException.GetType().FullName}: {cemLogException.Message}) while gathering command log, skipping...");
+        }
+        
+        builder.AppendLine("\n-----------State-----------");
+
+        try
+        {
+            builder.AppendLine($"Current Tool: {ViewModelMain.Current?.ToolsSubViewModel?.ActiveTool}");
+            builder.AppendLine($"Autosaving Enabled: {IPreferences.Current.GetPreference(PreferencesConstants.AutosavePeriodMinutes, PreferencesConstants.AutosavePeriodDefault).ToString(CultureInfo.InvariantCulture)}");
+        }
+        catch (Exception stateException)
+        {
+            builder.AppendLine($"Error ({stateException.GetType().FullName}: {stateException.Message}) while gathering command log, skipping...");
+        }
+        
+        builder.AppendLine("\n-----------Exception-----------");
+
         CrashHelper.AddExceptionMessage(builder, exception);
 
         string filename = $"crash-{currentTime:yyyy-MM-dd_HH-mm-ss_fff}.zip";