diff --git a/lib/main.dart b/lib/main.dart index 2c6b159..a6c8f11 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -54,6 +54,8 @@ Future main() async { FirebaseCrashlytics.instance.recordError(error, stack, fatal: false); return true; } + AppLogger.e('PlatformDispatcher', 'Kezeletlen kivétel', + error: error, stack: stack); FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); return true; }; diff --git a/lib/services/app_logger.dart b/lib/services/app_logger.dart index 6861e27..086d8f5 100644 --- a/lib/services/app_logger.dart +++ b/lib/services/app_logger.dart @@ -9,6 +9,7 @@ // Log fájl helye: /sdcard/Android/data/hu.app_dev.terepi_seged/files/logs/ // Elérhető: Android Studio Device Explorer, adb pull, vagy fájlkezelő app +import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; @@ -16,6 +17,8 @@ import 'package:intl/intl.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; +import 'package:terepi_seged/services/device_identity_service.dart'; enum _Level { info, warning, error } @@ -73,17 +76,23 @@ class AppLogger extends GetxService { // ── Publikus API ────────────────────────────────────────────────── /// Info szintű log - static void i(String tag, String message) => - _write(_Level.info, tag, message); + static void i(String tag, String message) { + _write(_Level.info, tag, message); + _remoteLog("INFO", tag, message, null, null); + } /// Figyelmeztetés - static void w(String tag, String message, {Object? error}) => - _write(_Level.warning, tag, message, error: error); + static void w(String tag, String message, {Object? error}) { + _write(_Level.warning, tag, message, error: error); + _remoteLog("WARN", tag, message, error, null); + } /// Hiba static void e(String tag, String message, - {Object? error, StackTrace? stack}) => - _write(_Level.error, tag, message, error: error, stack: stack); + {Object? error, StackTrace? stack}) { + _write(_Level.error, tag, message, error: error, stack: stack); + _remoteLog("ERROR", tag, message, error, stack); + } /// Szeparátor — jól látható elválasztó a logban static void separator(String label) { @@ -236,4 +245,101 @@ class AppLogger extends GetxService { await files.removeAt(0).delete(); } } + + // ── Távoli (Supabase) hiba-napló ────────────────────────────────── + + static final Map _remoteLogDedup = {}; + static const _remoteLogDedupWindow = Duration(seconds: 60); + + static void _remoteLog( + String type, String tag, String message, Object? error, StackTrace? stack, + [String? info, Map? params]) { + final key = '$tag|$message'; + final last = _remoteLogDedup[key]; + final now = DateTime.now(); + if (last != null && now.difference(last) < _remoteLogDedupWindow) { + return; // ugyanaz a hiba nemrég már felment — ne floodoljuk + } + _remoteLogDedup[key] = now; + + unawaited(() async { + try { + String? deviceId; + String? appVersion; + String? model; + String? appInstanceId; + String? platform; + if (Get.isRegistered()) { + final d = DeviceIdentityService.to; + deviceId = d.isReady ? d.deviceId : null; + appVersion = d.isReady ? d.appInfo : null; + model = d.isReady ? d.model : null; + appInstanceId = d.isReady ? d.appInstanceId : null; + platform = d.isReady ? d.info.platform : null; + } + final userId = Supabase.instance.client.auth.currentUser?.id; + + await Supabase.instance.client.from('terepi_seged_logs').insert({ + 'tag': tag, + 'message': message, + 'error_text': error?.toString(), + 'stack_text': stack != null + ? stack.toString().split('\n').take(8).join('\n') + : null, + 'app_version': appVersion, + 'device_id': deviceId, + 'user_id': userId, + 'app_id': appInstanceId, + 'model': model, + 'platform': platform, + 'info': info, + 'params': params + }).timeout(const Duration(seconds: 5)); + } catch (_) { + // Szándékosan néma — a távoli naplózás hibája NEM okozhat + // újabb naplóbejegyzést (végtelen ciklus elkerülése). + } + }()); + } + + // ── Egyszerű, "Firebase Analytics"-stílusú esemény-napló ────────── + // NEM a Firebase-be megy — ugyanabba a Supabase-be, mint a hiba-napló, + // hogy a hiba ÉS a használati esemény is egy helyen, azonnal + // lekérdezhető legyen (a valódi Firebase Analytics konzolja akár + // 24 órás késleltetéssel jelenít meg adatokat). + + static void event(String name, [String? info, Map? params]) { + unawaited(() async { + try { + String? deviceId; + String? appVersion; + String? model; + String? appInstanceId; + String? platform; + if (Get.isRegistered()) { + final d = DeviceIdentityService.to; + deviceId = d.isReady ? d.deviceId : null; + appVersion = d.isReady ? d.appInfo : null; + model = d.isReady ? d.model : null; + appInstanceId = d.isReady ? d.appInstanceId : null; + platform = d.isReady ? d.info.platform : null; + } + final userId = Supabase.instance.client.auth.currentUser?.id; + + await Supabase.instance.client.from('terepi_seged_events').insert({ + 'event_name': name, + 'params': params, + 'app_version': appVersion, + 'device_id': deviceId, + 'user_id': userId, + 'app_id': appInstanceId, + 'model': model, + 'platform': platform, + 'info': info + }).timeout(const Duration(seconds: 5)); + } catch (_) { + // Néma — az esemény-naplózás hibája nem árthat a funkciónak. + } + }()); + } }