Fehlerbehandlung, Logging und feldbezogene Validierung (Kapitel 13.2)
Zentrale Exception-Behandlung (Dispatcher.UIThread.UnhandledException, AppDomain, TaskScheduler) verhindert Abstürze und protokolliert Fehler über AppLogger in eine rotierende Log-Datei im App-Datenverzeichnis. Toast-Benachrichtigungen zeigen Erfolg/Fehler global an. Alle Dialoge mit Formularfeldern zeigen Validierungsmeldungen jetzt direkt am betroffenen Feld statt in einem Sammel-Label. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
namespace LehrerApp.Core.Services;
|
||||
|
||||
public enum LogLevel { Info, Warning, Error }
|
||||
|
||||
/// <summary>
|
||||
/// Schreibt Log-Zeilen in eine tägliche Datei im App-Datenverzeichnis
|
||||
/// (<c><AppData>/LehrerApp/logs/lehrerapp-JJJJ-MM-TT.log</c>).
|
||||
/// Beim Start werden Dateien entfernt, die älter als <see cref="RetentionDays"/> sind.
|
||||
/// </summary>
|
||||
public class AppLogger
|
||||
{
|
||||
private const int RetentionDays = 14;
|
||||
private readonly object _lock = new();
|
||||
private readonly string _logDirectory;
|
||||
|
||||
public string LogDirectory => _logDirectory;
|
||||
|
||||
public AppLogger(string appDataPath)
|
||||
{
|
||||
_logDirectory = Path.Combine(appDataPath, "logs");
|
||||
Directory.CreateDirectory(_logDirectory);
|
||||
RotateOldFiles();
|
||||
}
|
||||
|
||||
public void Info(string message) => Write(LogLevel.Info, message, null);
|
||||
public void Warn(string message) => Write(LogLevel.Warning, message, null);
|
||||
public void Error(string message, Exception? exception = null) => Write(LogLevel.Error, message, exception);
|
||||
|
||||
private void Write(LogLevel level, string message, Exception? exception)
|
||||
{
|
||||
var levelLabel = level switch
|
||||
{
|
||||
LogLevel.Info => "INFO ",
|
||||
LogLevel.Warning => "WARN ",
|
||||
LogLevel.Error => "ERROR",
|
||||
_ => "? ",
|
||||
};
|
||||
var line = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{levelLabel}] {message}";
|
||||
if (exception is not null)
|
||||
line += Environment.NewLine + exception;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.AppendAllText(CurrentLogFile(), line + Environment.NewLine);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Logging darf die App nie zum Absturz bringen (z.B. Datenträger voll/gesperrt).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string CurrentLogFile() =>
|
||||
Path.Combine(_logDirectory, $"lehrerapp-{DateTime.Now:yyyy-MM-dd}.log");
|
||||
|
||||
private void RotateOldFiles()
|
||||
{
|
||||
var cutoff = DateTime.Now.AddDays(-RetentionDays);
|
||||
try
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(_logDirectory, "lehrerapp-*.log"))
|
||||
{
|
||||
if (File.GetLastWriteTime(file) < cutoff)
|
||||
{
|
||||
try { File.Delete(file); }
|
||||
catch { /* nächster Start versucht es erneut */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Verzeichnis nicht lesbar o.ä. — Logging soll trotzdem weiterlaufen können.
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user