Verläufer Diagnose
Report
This commit is contained in:
160
Shared/Core/DiagnosticContext.cs
Normal file
160
Shared/Core/DiagnosticContext.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace BS.Shared.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Sammelt Systemkontext-Informationen, die einer Exception-Mail
|
||||
/// beigelegt werden können, um Support/Debugging zu erleichtern.
|
||||
/// </summary>
|
||||
public static class DiagnosticContext
|
||||
{
|
||||
// Ringpuffer für die letzten User-Aktionen (Thread-safe)
|
||||
private static readonly ConcurrentQueue<string> _actionLog = new ConcurrentQueue<string>();
|
||||
private const int MaxActionLogEntries = 10;
|
||||
|
||||
private static readonly DateTime _appStartTime = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// Optionale Mapping-Funktion: MachineName -> "sprechender" Servername.
|
||||
/// Vom Aufrufer beim Start gesetzt, z. B. aus einer Config.
|
||||
/// </summary>
|
||||
public static Func<string, string> MachineNameResolver { get; set; }
|
||||
= machineName => machineName; // Fallback: keine Übersetzung
|
||||
|
||||
/// <summary>
|
||||
/// Registriert eine User-Aktion im Ringpuffer (z. B. Button-Klicks, Commands, Navigation).
|
||||
/// Am besten zentral im Command-Handling oder Navigation-Service aufrufen.
|
||||
/// </summary>
|
||||
public static void LogAction(string action)
|
||||
{
|
||||
_actionLog.Enqueue($"{DateTime.UtcNow:HH:mm:ss.fff} - {action}");
|
||||
while (_actionLog.Count > MaxActionLogEntries)
|
||||
{
|
||||
_actionLog.TryDequeue(out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Baut den vollständigen Diagnose-Report als String, z. B. zum Anhängen an eine Exception-Mail.
|
||||
/// </summary>
|
||||
public static string BuildReport(Exception ex = null, string currentView = null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine("=== SYSTEM ===");
|
||||
var machineName = Environment.MachineName;
|
||||
var friendlyName = MachineNameResolver(machineName);
|
||||
sb.AppendLine($"MachineName: {machineName}" +
|
||||
(friendlyName != machineName ? $" ({friendlyName})" : ""));
|
||||
sb.AppendLine($"Systemzeit (UTC): {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}");
|
||||
sb.AppendLine($"Systemzeit (lokal): {DateTime.Now:yyyy-MM-dd HH:mm:ss} ({TimeZoneInfo.Local.Id})");
|
||||
sb.AppendLine($"OS: {RuntimeInformation.OSDescription}");
|
||||
sb.AppendLine($"Architektur: {RuntimeInformation.OSArchitecture} / Prozess: {RuntimeInformation.ProcessArchitecture}");
|
||||
sb.AppendLine($"CPU Cores: {Environment.ProcessorCount}");
|
||||
sb.AppendLine($"Angemeldeter User:{Environment.UserName}");
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=== RESSOURCEN ===");
|
||||
try
|
||||
{
|
||||
using (var proc = Process.GetCurrentProcess())
|
||||
{
|
||||
sb.AppendLine($"Working Set: {proc.WorkingSet64 / 1024 / 1024} MB");
|
||||
sb.AppendLine($"Prozess-Uptime: {DateTime.UtcNow - _appStartTime:hh\\:mm\\:ss}");
|
||||
sb.AppendLine($"Prozess-ID: {proc.Id}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
sb.AppendLine($"(Fehler beim Auslesen der Prozessdaten: {e.Message})");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var drive = new DriveInfo(System.IO.Path.GetPathRoot(AppDomain.CurrentDomain.BaseDirectory) ?? "C:\\");
|
||||
sb.AppendLine($"Freier Speicher: {drive.AvailableFreeSpace / 1024 / 1024 / 1024} GB " +
|
||||
$"von {drive.TotalSize / 1024 / 1024 / 1024} GB auf {drive.Name}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
sb.AppendLine($"(Fehler beim Auslesen des Speicherplatzes: {e.Message})");
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=== ANWENDUNG ===");
|
||||
var assembly = Assembly.GetEntryAssembly();
|
||||
sb.AppendLine($"App-Version: {assembly?.GetName().Version}");
|
||||
sb.AppendLine($".NET Runtime: {RuntimeInformation.FrameworkDescription}");
|
||||
sb.AppendLine($"Environment: {AppEnvironmentInfo.CurrentEnvironmentName}"); // an deine bestehende Environment-Detection anpassen
|
||||
//if (!string.IsNullOrEmpty(currentView))
|
||||
// sb.AppendLine($"Aktuelle View: {currentView}");
|
||||
|
||||
//sb.AppendLine();
|
||||
//sb.AppendLine("=== NETZWERK / BACKEND ===");
|
||||
//sb.AppendLine($"Ollama erreichbar: {CheckHostReachable("localhost", 500)}"); // Host/Port anpassen
|
||||
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=== LETZTE USER-AKTIONEN ===");
|
||||
if (_actionLog.IsEmpty)
|
||||
{
|
||||
sb.AppendLine("(keine erfasst)");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var entry in _actionLog)
|
||||
sb.AppendLine(entry);
|
||||
}
|
||||
|
||||
if (ex != null)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=== EXCEPTION ===");
|
||||
AppendExceptionDetails(sb, ex);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void AppendExceptionDetails(StringBuilder sb, Exception ex, int level = 0)
|
||||
{
|
||||
var indent = new string(' ', level * 2);
|
||||
sb.AppendLine($"{indent}Typ: {ex.GetType().FullName}");
|
||||
sb.AppendLine($"{indent}Message: {ex.Message}");
|
||||
sb.AppendLine($"{indent}HResult: {ex.HResult}");
|
||||
sb.AppendLine($"{indent}Source: {ex.Source}");
|
||||
|
||||
if (ex.Data.Count > 0)
|
||||
{
|
||||
sb.AppendLine($"{indent}Data:");
|
||||
foreach (var key in ex.Data.Keys)
|
||||
sb.AppendLine($"{indent} {key}: {ex.Data[key]}");
|
||||
}
|
||||
|
||||
sb.AppendLine($"{indent}StackTrace:");
|
||||
sb.AppendLine(ex.StackTrace);
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
sb.AppendLine($"{indent}--- InnerException ---");
|
||||
AppendExceptionDetails(sb, ex.InnerException, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Platzhalter — an deine bestehende Environment-Detection-Logik anbinden
|
||||
internal static class AppEnvironmentInfo
|
||||
{
|
||||
public static string CurrentEnvironmentName { get; set; } = "Unknown";
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,6 @@ namespace BS.Shared.Core
|
||||
message.ReplyToList.Add(new MailAddress(fromAddress, fromName));
|
||||
}
|
||||
|
||||
|
||||
message.BodyEncoding = Encoding.UTF8;
|
||||
message.IsBodyHtml = false;
|
||||
|
||||
|
||||
@@ -119,6 +119,9 @@
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization">
|
||||
<RequiredTargetFramework>3.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
@@ -146,6 +149,7 @@
|
||||
<Compile Include="Core\BeWoFault.cs" />
|
||||
<Compile Include="Core\ComplexWohnheimbuchungsRelationHelper.cs" />
|
||||
<Compile Include="Core\AbstractIDSpecificDefaultClass.cs" />
|
||||
<Compile Include="Core\DiagnosticContext.cs" />
|
||||
<Compile Include="Core\Facade\HttpClientFacade.cs" />
|
||||
<Compile Include="Core\Facade\JsonHttpClientFacade.cs" />
|
||||
<Compile Include="Core\JsonUtils.cs" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
|
||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net452" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user