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 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 _logs = []; late final String _deviceModel; bool _initialized = false; Future 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) void error(String message, [Object? error, StackTrace? stackTrace]) { final entry = LogEntry( level: 'ERROR', message: message, stackTrace: '$error\n$stackTrace', deviceModel: _deviceModel, ); _logs.add(entry); debugPrint('❌ ERROR: $message'); _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 _uploadIfError(LogEntry entry) async { debugPrint('📤 Uploading ERROR immediately: ${entry.message}'); await _uploadLogs(); } /// Hochladen der Logs zum Server Future _uploadLogs() async { if (_logs.isEmpty) return; try { final logsToUpload = List.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 flush() async { await _uploadLogs(); } int get logCount => _logs.length; } /// Global Logger Instance final logger = LoggerService();