diff --git a/CHANGELOG.md b/CHANGELOG.md index d9f1af6..3cf865a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ Format angelehnt an [Keep a Changelog](https://keepachangelog.com/de/1.0.0/). ## [Unreleased] +### 🔧 Log-Upload System - Fixes (2026-08-19) +- ✅ **ERROR-Level Logging**: Fehler werden SOFORT zum Server hochgeladen (async/await Fixed) +- ✅ **Navidrome-Service Error Logging**: Alle API-Fehler (ping, getAlben, getSongs, getFavorites, getArtists, getArtistSongs, getLyrics, scrobble, getBookmarks, getPlaylists, getPlaylistSongs) werden jetzt mit `logger.error()` zum Server geloggt (statt nur debugPrint) +- ✅ **Login-Fehler Detail-Logging**: Fehler enthalten URL, User, Exception-Typ und StackTrace +- ✅ **HTTP-Error bei Stream**: Stream-Fehler mit HTTP-Statuscode werden auch geloggt +- ✅ **Payload-Format**: Logs senden als `{"logs": [...]}` Array zum Server + ### 🎉 RELEASE BUILD v3: Phase 2 + Login + Auto-Bugreport System! **Build Date:** 2026-08-19 21:30 **APK (Release/Universal):** `app-release.apk` (22.3 MB) — **Mit Auto-Logger + Login-Improvements!** diff --git a/lib/services/logger_service.dart b/lib/services/logger_service.dart index b634d8f..856d0d9 100644 --- a/lib/services/logger_service.dart +++ b/lib/services/logger_service.dart @@ -58,7 +58,7 @@ class LoggerService extends ChangeNotifier { } /// Logge einen Fehler (wird sofort zum Server geschickt) - void error(String message, [Object? error, StackTrace? stackTrace]) { + Future error(String message, [Object? error, StackTrace? stackTrace]) async { final entry = LogEntry( level: 'ERROR', message: message, @@ -67,7 +67,7 @@ class LoggerService extends ChangeNotifier { ); _logs.add(entry); debugPrint('❌ ERROR: $message'); - _uploadIfError(entry); + await _uploadIfError(entry); } /// Logge eine Warnung diff --git a/lib/services/navidrome_service.dart b/lib/services/navidrome_service.dart index b4d2a7e..0b53e54 100644 --- a/lib/services/navidrome_service.dart +++ b/lib/services/navidrome_service.dart @@ -164,7 +164,7 @@ class NavidromeService { FormatException() => 'FORMAT (URL unparsbar?)', _ => 'SONSTIGE', }; - logger.error( + await logger.error( 'Navidrome Ping Fehler [$art] ' 'url=$_serverUrl ' 'scheme=${ziel?.scheme ?? '-'} host=${ziel?.host ?? '-'} ' @@ -187,7 +187,7 @@ class NavidromeService { final list = data['subsonic-response']?['albumList']?['album'] as List? ?? []; return list.map((j) => SubsonicAlbum.fromJson(j)).toList(); } catch (e) { - debugPrint('Navidrome getAlben Fehler: $e'); + await logger.error('Navidrome getAlben Fehler: $e', e, StackTrace.current); return []; } } @@ -200,7 +200,7 @@ class NavidromeService { final songs = data['subsonic-response']?['album']?['song'] as List? ?? []; return songs.map((j) => SubsonicSong.fromJson(j)).toList(); } catch (e) { - debugPrint('Navidrome getSongs Fehler: $e'); + await logger.error('Navidrome getSongs Fehler: $e', e, StackTrace.current); return []; } } @@ -218,7 +218,7 @@ class NavidromeService { final r = await http.get(_uri('star.view', {'id': songId})).timeout(const Duration(seconds: 10)); return r.statusCode == 200; } catch (e) { - debugPrint('Navidrome setFavorite Fehler: $e'); + await logger.error('Navidrome setFavorite Fehler: $e', e, StackTrace.current); return false; } } @@ -228,7 +228,7 @@ class NavidromeService { final r = await http.get(_uri('unstar.view', {'id': songId})).timeout(const Duration(seconds: 10)); return r.statusCode == 200; } catch (e) { - debugPrint('Navidrome removeFavorite Fehler: $e'); + await logger.error('Navidrome removeFavorite Fehler: $e', e, StackTrace.current); return false; } } @@ -241,7 +241,7 @@ class NavidromeService { final songs = data['subsonic-response']?['starred']?['song'] as List? ?? []; return songs.map((j) => SubsonicSong.fromJson(j)).toList(); } catch (e) { - debugPrint('Navidrome getFavorites Fehler: $e'); + await logger.error('Navidrome getFavorites Fehler: $e', e, StackTrace.current); return []; } } @@ -261,7 +261,7 @@ class NavidromeService { } return artists; } catch (e) { - debugPrint('Navidrome getArtists Fehler: $e'); + await logger.error('Navidrome getArtists Fehler: $e', e, StackTrace.current); return []; } } @@ -281,7 +281,7 @@ class NavidromeService { } return songs; } catch (e) { - debugPrint('Navidrome getArtistSongs Fehler: $e'); + await logger.error('Navidrome getArtistSongs Fehler: $e', e, StackTrace.current); return []; } } @@ -294,7 +294,7 @@ class NavidromeService { final lyrics = data['subsonic-response']?['lyrics']?['value'] as String?; return Lyrics.fromText(lyrics); } catch (e) { - debugPrint('Navidrome getLyrics Fehler: $e'); + await logger.error('Navidrome getLyrics Fehler: $e', e, StackTrace.current); return Lyrics.empty(); } } @@ -314,7 +314,7 @@ class NavidromeService { final response = await http.Client().send(request).timeout(const Duration(seconds: 30)); if (response.statusCode != 200) { - debugPrint('Stream-Fehler: HTTP ${response.statusCode}'); + await logger.error('Stream-Fehler: HTTP ${response.statusCode}'); return streamUri; } @@ -327,7 +327,7 @@ class NavidromeService { debugPrint('Cache-Speicherung erfolgreich: ${cacheFile.path}'); return Uri.file(cacheFile.path); } catch (e) { - debugPrint('streamAndCacheToLocal Fehler: $e'); + await logger.error('streamAndCacheToLocal Fehler: $e', e, StackTrace.current); return streamUrl(songId); } } @@ -345,7 +345,7 @@ class NavidromeService { await http.get(uri).timeout(const Duration(seconds: 10)); debugPrint('Scrobble erfolgreich: Song=$songId, Position=${positionSeconds}s'); } catch (e) { - debugPrint('Scrobble Fehler: $e'); + await logger.error('Scrobble Fehler: $e', e, StackTrace.current); } } @@ -370,7 +370,7 @@ class NavidromeService { debugPrint('Bookmark geladen: Song=$songId, Position=${position}ms'); return position; } catch (e) { - debugPrint('Bookmark Fehler: $e'); + await logger.error('Bookmark Fehler: $e', e, StackTrace.current); return null; } } @@ -395,7 +395,7 @@ class NavidromeService { .map(SubsonicPlaylist.fromJson) .toList(); } catch (e) { - debugPrint('getPlaylists Fehler: $e'); + await logger.error('getPlaylists Fehler: $e', e, StackTrace.current); return []; } } @@ -420,7 +420,7 @@ class NavidromeService { return songs.cast>().map(SubsonicSong.fromJson).toList(); } catch (e) { - debugPrint('getPlaylistSongs Fehler: $e'); + await logger.error('getPlaylistSongs Fehler: $e', e, StackTrace.current); return []; } } diff --git a/lib/settings/settings_screen.dart b/lib/settings/settings_screen.dart index c41a503..0e98779 100644 --- a/lib/settings/settings_screen.dart +++ b/lib/settings/settings_screen.dart @@ -277,7 +277,7 @@ class _SettingsScreenState extends State { if (ctx.mounted) Navigator.pop(ctx); if (mounted) setState(() {}); } else if (ctx.mounted) { - logger.error( + await logger.error( 'Login fehlgeschlagen: url=${urlCtrl.text} ' 'user=$selectedUser pwLeer=${passCtrl.text.isEmpty}'); setDialogState(() =>