Browse Source

Extended crash reports

CPKreuz 3 years ago
parent
commit
6694b97bac
2 changed files with 176 additions and 16 deletions
  1. 173 16
      PixiEditor/Helpers/CrashHelper.cs
  2. 3 0
      PixiEditor/Models/Dialogs/ResizeDocumentDialog.cs

+ 173 - 16
PixiEditor/Helpers/CrashHelper.cs

@@ -1,25 +1,134 @@
-using System;
-using System.Collections.Generic;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.DataHolders;
+using PixiEditor.Parser;
+using PixiEditor.ViewModels;
+using System;
 using System.IO;
-using System.Linq;
+using System.IO.Compression;
+using System.Management;
+using System.Runtime.InteropServices;
 using System.Text;
-using System.Threading.Tasks;
 
 namespace PixiEditor.Helpers
 {
     public static class CrashHelper
     {
-        public static void SaveCrashInfo(Exception e)
+        public static void SaveCrashInfo(Exception exception)
         {
-            StringBuilder builder = new System.Text.StringBuilder();
+            StringBuilder builder = new();
             DateTime currentTime = DateTime.Now;
 
             builder
-                .Append($"PixiEditor crashed on {currentTime:yyyy.MM.dd} at {currentTime:HH:mm:ss}\n\n")
-                .Append("-------Crash message-------\n")
+                .AppendLine($"PixiEditor crashed on {currentTime:yyyy.MM.dd} at {currentTime:HH:mm:ss}\n")
+                .AppendLine("-----System Information----")
+                .AppendLine("General:")
+                .AppendLine($"  OS: {Environment.OSVersion.VersionString}")
+                .AppendLine();
+
+            try
+            {
+                GetCPUInformation(builder);
+            }
+            catch (Exception cpuE)
+            {
+                builder.AppendLine($"Error ({cpuE.GetType().FullName}: {cpuE.Message}) while gathering CPU information, skipping...");
+            }
+
+            try
+            {
+                GetGPUInformation(builder);
+            }
+            catch (Exception gpuE)
+            {
+                builder.AppendLine($"Error ({gpuE.GetType().FullName}: {gpuE.Message}) while gathering GPU information, skipping...");
+            }
+
+            try
+            {
+                GetMemoryInformation(builder);
+            }
+            catch (Exception memE)
+            {
+                builder.AppendLine($"Error ({memE.GetType().FullName}: {memE.Message}) while gathering memory information, skipping...");
+            }
+
+            AddExceptionMessage(builder, exception);
+
+            string filename = $"crash-{currentTime:yyyy-MM-dd_HH-mm-ss_fff}.zip";
+            string path = Path.Combine(
+                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                "PixiEditor",
+                "crash_logs");
+            Directory.CreateDirectory(path);
+
+            string filePath = Path.Combine(path, filename);
+            string report = builder.ToString();
+
+            try
+            {
+                CreateZip(filePath, report);
+            }
+            catch
+            {
+                File.WriteAllText(Path.ChangeExtension(filePath, ".txt"), report);
+            }
+        }
+
+        private static void GetCPUInformation(StringBuilder builder)
+        {
+            builder.AppendLine("CPU:");
+
+            ManagementClass processorClass = new("Win32_Processor");
+            ManagementObjectCollection processorsCollection = processorClass.GetInstances();
+
+            foreach (var processor in processorsCollection)
+            {
+                builder
+                    .AppendLine($"  ID: {processor.Properties["DeviceID"].Value}")
+                    .AppendLine($"  Name: {processor.Properties["Name"].Value}");
+            }
+        }
+
+        private static void GetGPUInformation(StringBuilder builder)
+        {
+            builder.AppendLine("\nGPU:");
+
+            ManagementClass gpuClass = new("Win32_VideoController");
+            ManagementObjectCollection gpuCollection = gpuClass.GetInstances();
+
+            foreach (var gpu in gpuCollection)
+            {
+                builder
+                    .AppendLine($"  ID: {gpu.Properties["DeviceID"].Value}")
+                    .AppendLine($"  Name: {gpu.Properties["Name"].Value}");
+            }
+        }
+
+        private static void GetMemoryInformation(StringBuilder builder)
+        {
+            builder.AppendLine("\nMemory:");
+
+            // TODO: Make this work
+            if (TryGetMemoryStatus(out MemoryStatus status))
+            {
+                builder.AppendLine($"  Usage: {status.dwMemoryLoad}%");
+                builder.AppendLine($"  Available Memory: {status.ullAvailPhys}");
+                builder.AppendLine($"  Total Memory: {status.ullTotalPhys}");
+            }
+            else
+            {
+                throw new InvalidOperationException($"Getting memory failed: {Marshal.GetLastWin32Error()}");
+            }
+        }
+
+        private static void AddExceptionMessage(StringBuilder builder, Exception e)
+        {
+
+            builder
+                .AppendLine("\n-------Crash message-------")
                 .Append(e.GetType().ToString())
                 .Append(": ")
-                .Append(e.Message);
+                .AppendLine(e.Message);
             {
                 var innerException = e.InnerException;
                 while (innerException != null)
@@ -46,14 +155,62 @@ namespace PixiEditor.Helpers
                     innerException = innerException.InnerException;
                 }
             }
+        }
 
-            string filename = $"crash-{currentTime:yyyy-MM-dd_HH-mm-ss_fff}.txt";
-            string path = Path.Combine(
-                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
-                "PixiEditor",
-                "crash_logs");
-            Directory.CreateDirectory(path);
-            File.WriteAllText(Path.Combine(path, filename), builder.ToString());
+        private static void CreateZip(string filePath, string report)
+        {
+            using FileStream zipStream = new(/*Path.Combine(path, filename)*/filePath, FileMode.Create, FileAccess.Write);
+            using ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create);
+
+            using (Stream reportStream = archive.CreateEntry("report.txt").Open())
+            {
+                reportStream.Write(Encoding.UTF8.GetBytes(report));
+            }
+
+            foreach (Document document in ViewModelMain.Current.BitmapManager.Documents)
+            {
+                try
+                {
+                    string documentPath =
+                        $"{(string.IsNullOrWhiteSpace(document.DocumentFilePath) ? "Unsaved" : Path.GetFileNameWithoutExtension(document.DocumentFilePath))}-{document.OpenedUTC}.pixi";
+                    using Stream documentStream = archive.CreateEntry($"Documents/{documentPath}").Open();
+
+                    PixiParser.Serialize(document.ToSerializable(), documentStream);
+                }
+                catch
+                { }
+            }
         }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+        private struct MemoryStatus
+        {
+            public uint dwLength;
+            public uint dwMemoryLoad;
+            public ulong ullTotalPhys;
+            public ulong ullAvailPhys;
+            public ulong ullTotalPageFile;
+            public ulong ullAvailPageFile;
+            public ulong ullTotalVirtual;
+            public ulong ullAvailVirtual;
+            public ulong ullAvailExtendedVirtual;
+        }
+
+        private static unsafe bool TryGetMemoryStatus(out MemoryStatus status)
+        {
+            MemoryStatus memoryStatus = new();
+            memoryStatus.dwLength = (uint)sizeof(MemoryStatus);
+
+            bool success = GlobalMemoryStatusEx(memoryStatus);
+
+            status = memoryStatus;
+
+            return success;
+        }
+
+        // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
+        [return: MarshalAs(UnmanagedType.Bool)]
+        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+        private static extern bool GlobalMemoryStatusEx([In, Out] MemoryStatus lpBuffer);
     }
 }

+ 3 - 0
PixiEditor/Models/Dialogs/ResizeDocumentDialog.cs

@@ -10,6 +10,9 @@ namespace PixiEditor.Models.Dialogs
 
         public ResizeDocumentDialog(int currentWidth, int currentHeight, bool openResizeCanvas = false)
         {
+            // Remove this
+            throw new System.Exception("Just doing some testing stuff");
+
             Width = currentWidth;
             Height = currentHeight;
             OpenResizeCanvas = openResizeCanvas;