🔧 Fix Log-Upload System: ERROR-Level sofort hochladen + Navidrome-Fehler tracken
- error() ist jetzt async mit await — ERROR-Logs werden SOFORT zum Server hochgeladen
- Alle Navidrome API-Fehler nutzen logger.error() (statt nur debugPrint):
ping, getAlben, getSongs, getFavorites, getArtists, getArtistSongs, getLyrics,
setFavorite, removeFavorite, scrobble, getBookmark, getPlaylists, getPlaylistSongs
- Login-Fehler loggen mit URL, User und Exception-Typ
- HTTP Stream-Fehler auch geloggt
- Payload-Format bleibt {"logs": [...]} Array (https://logs.baka-net.de/api/logs)
Alle 70 Tests bestanden ✅
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SiRmGyzAMkzHMqBsBe2h3n
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
323a67e3a2
commit
61e28d128f
@@ -5,6 +5,13 @@ Format angelehnt an [Keep a Changelog](https://keepachangelog.com/de/1.0.0/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [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!
|
### 🎉 RELEASE BUILD v3: Phase 2 + Login + Auto-Bugreport System!
|
||||||
**Build Date:** 2026-08-19 21:30
|
**Build Date:** 2026-08-19 21:30
|
||||||
**APK (Release/Universal):** `app-release.apk` (22.3 MB) — **Mit Auto-Logger + Login-Improvements!**
|
**APK (Release/Universal):** `app-release.apk` (22.3 MB) — **Mit Auto-Logger + Login-Improvements!**
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class LoggerService extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Logge einen Fehler (wird sofort zum Server geschickt)
|
/// Logge einen Fehler (wird sofort zum Server geschickt)
|
||||||
void error(String message, [Object? error, StackTrace? stackTrace]) {
|
Future<void> error(String message, [Object? error, StackTrace? stackTrace]) async {
|
||||||
final entry = LogEntry(
|
final entry = LogEntry(
|
||||||
level: 'ERROR',
|
level: 'ERROR',
|
||||||
message: message,
|
message: message,
|
||||||
@@ -67,7 +67,7 @@ class LoggerService extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
_logs.add(entry);
|
_logs.add(entry);
|
||||||
debugPrint('❌ ERROR: $message');
|
debugPrint('❌ ERROR: $message');
|
||||||
_uploadIfError(entry);
|
await _uploadIfError(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Logge eine Warnung
|
/// Logge eine Warnung
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class NavidromeService {
|
|||||||
FormatException() => 'FORMAT (URL unparsbar?)',
|
FormatException() => 'FORMAT (URL unparsbar?)',
|
||||||
_ => 'SONSTIGE',
|
_ => 'SONSTIGE',
|
||||||
};
|
};
|
||||||
logger.error(
|
await logger.error(
|
||||||
'Navidrome Ping Fehler [$art] '
|
'Navidrome Ping Fehler [$art] '
|
||||||
'url=$_serverUrl '
|
'url=$_serverUrl '
|
||||||
'scheme=${ziel?.scheme ?? '-'} host=${ziel?.host ?? '-'} '
|
'scheme=${ziel?.scheme ?? '-'} host=${ziel?.host ?? '-'} '
|
||||||
@@ -187,7 +187,7 @@ class NavidromeService {
|
|||||||
final list = data['subsonic-response']?['albumList']?['album'] as List? ?? [];
|
final list = data['subsonic-response']?['albumList']?['album'] as List? ?? [];
|
||||||
return list.map((j) => SubsonicAlbum.fromJson(j)).toList();
|
return list.map((j) => SubsonicAlbum.fromJson(j)).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome getAlben Fehler: $e');
|
await logger.error('Navidrome getAlben Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ class NavidromeService {
|
|||||||
final songs = data['subsonic-response']?['album']?['song'] as List? ?? [];
|
final songs = data['subsonic-response']?['album']?['song'] as List? ?? [];
|
||||||
return songs.map((j) => SubsonicSong.fromJson(j)).toList();
|
return songs.map((j) => SubsonicSong.fromJson(j)).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome getSongs Fehler: $e');
|
await logger.error('Navidrome getSongs Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,7 +218,7 @@ class NavidromeService {
|
|||||||
final r = await http.get(_uri('star.view', {'id': songId})).timeout(const Duration(seconds: 10));
|
final r = await http.get(_uri('star.view', {'id': songId})).timeout(const Duration(seconds: 10));
|
||||||
return r.statusCode == 200;
|
return r.statusCode == 200;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome setFavorite Fehler: $e');
|
await logger.error('Navidrome setFavorite Fehler: $e', e, StackTrace.current);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ class NavidromeService {
|
|||||||
final r = await http.get(_uri('unstar.view', {'id': songId})).timeout(const Duration(seconds: 10));
|
final r = await http.get(_uri('unstar.view', {'id': songId})).timeout(const Duration(seconds: 10));
|
||||||
return r.statusCode == 200;
|
return r.statusCode == 200;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome removeFavorite Fehler: $e');
|
await logger.error('Navidrome removeFavorite Fehler: $e', e, StackTrace.current);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,7 +241,7 @@ class NavidromeService {
|
|||||||
final songs = data['subsonic-response']?['starred']?['song'] as List? ?? [];
|
final songs = data['subsonic-response']?['starred']?['song'] as List? ?? [];
|
||||||
return songs.map((j) => SubsonicSong.fromJson(j)).toList();
|
return songs.map((j) => SubsonicSong.fromJson(j)).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome getFavorites Fehler: $e');
|
await logger.error('Navidrome getFavorites Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,7 +261,7 @@ class NavidromeService {
|
|||||||
}
|
}
|
||||||
return artists;
|
return artists;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome getArtists Fehler: $e');
|
await logger.error('Navidrome getArtists Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ class NavidromeService {
|
|||||||
}
|
}
|
||||||
return songs;
|
return songs;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome getArtistSongs Fehler: $e');
|
await logger.error('Navidrome getArtistSongs Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ class NavidromeService {
|
|||||||
final lyrics = data['subsonic-response']?['lyrics']?['value'] as String?;
|
final lyrics = data['subsonic-response']?['lyrics']?['value'] as String?;
|
||||||
return Lyrics.fromText(lyrics);
|
return Lyrics.fromText(lyrics);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Navidrome getLyrics Fehler: $e');
|
await logger.error('Navidrome getLyrics Fehler: $e', e, StackTrace.current);
|
||||||
return Lyrics.empty();
|
return Lyrics.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ class NavidromeService {
|
|||||||
final response = await http.Client().send(request).timeout(const Duration(seconds: 30));
|
final response = await http.Client().send(request).timeout(const Duration(seconds: 30));
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
debugPrint('Stream-Fehler: HTTP ${response.statusCode}');
|
await logger.error('Stream-Fehler: HTTP ${response.statusCode}');
|
||||||
return streamUri;
|
return streamUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ class NavidromeService {
|
|||||||
debugPrint('Cache-Speicherung erfolgreich: ${cacheFile.path}');
|
debugPrint('Cache-Speicherung erfolgreich: ${cacheFile.path}');
|
||||||
return Uri.file(cacheFile.path);
|
return Uri.file(cacheFile.path);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('streamAndCacheToLocal Fehler: $e');
|
await logger.error('streamAndCacheToLocal Fehler: $e', e, StackTrace.current);
|
||||||
return streamUrl(songId);
|
return streamUrl(songId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,7 +345,7 @@ class NavidromeService {
|
|||||||
await http.get(uri).timeout(const Duration(seconds: 10));
|
await http.get(uri).timeout(const Duration(seconds: 10));
|
||||||
debugPrint('Scrobble erfolgreich: Song=$songId, Position=${positionSeconds}s');
|
debugPrint('Scrobble erfolgreich: Song=$songId, Position=${positionSeconds}s');
|
||||||
} catch (e) {
|
} 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');
|
debugPrint('Bookmark geladen: Song=$songId, Position=${position}ms');
|
||||||
return position;
|
return position;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('Bookmark Fehler: $e');
|
await logger.error('Bookmark Fehler: $e', e, StackTrace.current);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +395,7 @@ class NavidromeService {
|
|||||||
.map(SubsonicPlaylist.fromJson)
|
.map(SubsonicPlaylist.fromJson)
|
||||||
.toList();
|
.toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('getPlaylists Fehler: $e');
|
await logger.error('getPlaylists Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,7 +420,7 @@ class NavidromeService {
|
|||||||
|
|
||||||
return songs.cast<Map<String, dynamic>>().map(SubsonicSong.fromJson).toList();
|
return songs.cast<Map<String, dynamic>>().map(SubsonicSong.fromJson).toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('getPlaylistSongs Fehler: $e');
|
await logger.error('getPlaylistSongs Fehler: $e', e, StackTrace.current);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
if (ctx.mounted) Navigator.pop(ctx);
|
if (ctx.mounted) Navigator.pop(ctx);
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
} else if (ctx.mounted) {
|
} else if (ctx.mounted) {
|
||||||
logger.error(
|
await logger.error(
|
||||||
'Login fehlgeschlagen: url=${urlCtrl.text} '
|
'Login fehlgeschlagen: url=${urlCtrl.text} '
|
||||||
'user=$selectedUser pwLeer=${passCtrl.text.isEmpty}');
|
'user=$selectedUser pwLeer=${passCtrl.text.isEmpty}');
|
||||||
setDialogState(() =>
|
setDialogState(() =>
|
||||||
|
|||||||
Reference in New Issue
Block a user