namespace LehrerApp.Core.Services; public enum LogLevel { Info, Warning, Error } /// /// Schreibt Log-Zeilen in eine tägliche Datei im App-Datenverzeichnis /// (<AppData>/LehrerApp/logs/lehrerapp-JJJJ-MM-TT.log). /// Beim Start werden Dateien entfernt, die älter als sind. /// 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. } } }