Files
Melo/lib/services/logger_service.dart
T
Hermes (Server)andClaude Haiku 4.5 61e28d128f 🔧 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
2026-08-19 22:36:58 +02:00

138 lines
3.6 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:device_info_plus/device_info_plus.dart';
import 'dart:convert';
import 'dart:io';
class LogEntry {
final String level; // DEBUG, INFO, WARNING, ERROR
final String message;
final String? stackTrace;
final DateTime timestamp;
final String? userAgent;
final String? deviceModel;
LogEntry({
required this.level,
required this.message,
this.stackTrace,
DateTime? timestamp,
this.userAgent,
this.deviceModel,
}) : timestamp = timestamp ?? DateTime.now();
Map<String, dynamic> toJson() => {
'level': level,
'message': message,
'stackTrace': stackTrace,
'timestamp': timestamp.toIso8601String(),
'userAgent': userAgent,
'deviceModel': deviceModel,
};
}
/// Centralized Logging Service mit Auto-Upload zu Server
class LoggerService extends ChangeNotifier {
static const String _logServerUrl = 'https://logs.baka-net.de/api/logs';
static const int _batchSize = 5;
final List<LogEntry> _logs = [];
late final String _deviceModel;
bool _initialized = false;
Future<void> init() async {
if (_initialized) return;
try {
final deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
final info = await deviceInfo.androidInfo;
_deviceModel = '${info.manufacturer} ${info.model}';
} else {
_deviceModel = 'Unknown Device';
}
} catch (e) {
_deviceModel = 'Unknown Device';
}
_initialized = true;
debugPrint('✅ LoggerService initialized for $_deviceModel');
}
/// Logge einen Fehler (wird sofort zum Server geschickt)
Future<void> error(String message, [Object? error, StackTrace? stackTrace]) async {
final entry = LogEntry(
level: 'ERROR',
message: message,
stackTrace: '$error\n$stackTrace',
deviceModel: _deviceModel,
);
_logs.add(entry);
debugPrint('❌ ERROR: $message');
await _uploadIfError(entry);
}
/// Logge eine Warnung
void warning(String message) {
final entry = LogEntry(
level: 'WARNING',
message: message,
deviceModel: _deviceModel,
);
_logs.add(entry);
debugPrint('⚠️ WARNING: $message');
_checkAndFlush();
}
/// Logge Info-Event
void info(String message) {
final entry = LogEntry(
level: 'INFO',
message: message,
deviceModel: _deviceModel,
);
_logs.add(entry);
debugPrint('️ INFO: $message');
_checkAndFlush();
}
void _checkAndFlush() {
if (_logs.length >= _batchSize) {
_uploadLogs();
}
}
Future<void> _uploadIfError(LogEntry entry) async {
debugPrint('📤 Uploading ERROR immediately: ${entry.message}');
await _uploadLogs();
}
/// Hochladen der Logs zum Server
Future<void> _uploadLogs() async {
if (_logs.isEmpty) return;
try {
final logsToUpload = List<LogEntry>.from(_logs);
await http.post(
Uri.parse(_logServerUrl),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'logs': logsToUpload.map((l) => l.toJson()).toList(),
'timestamp': DateTime.now().toIso8601String(),
}),
).timeout(const Duration(seconds: 10));
_logs.clear();
debugPrint('✅ Logs uploaded successfully (${logsToUpload.length} entries)');
} catch (e) {
debugPrint('⚠️ Failed to upload logs: $e');
}
}
/// Manuelles Flushen (z.B. vor App-Exit)
Future<void> flush() async {
await _uploadLogs();
}
int get logCount => _logs.length;
}
/// Global Logger Instance
final logger = LoggerService();