import 'dart:async'; import 'dart:convert'; import 'dart:io'; // Pont VM Service — rend visibles les traces `dart:developer log()` de l'app. // // ## Pourquoi ce fichier existe // // `flutter run` **n'imprime pas** ces traces sur stdout : elles partent au VM Service, ni sur // la console, ni dans `logcat`. Tout ce que `NymeaService._log()` journalise — locale demandée // et retenue, aller-retours RPC, séquence d'écriture, télémétrie poussée — est donc invisible // depuis le poste tant qu'on n'est pas branché ici. // // Éprouvé le 2026-08-25, premier passage de l'app sur appareil (Redmi Note 9S) : sans ce pont, // aucun constat du journal de vérification n'était atteignable. // // ## Usage // // flutter run -d --use-application-binary=build/app/outputs/flutter-apk/app-debug.apk // # relever « A Dart VM Service on … is available at: http://127.0.0.1:PORT/TOKEN=/ » // dart tools/devlog/vm_logs.dart 'ws://127.0.0.1:PORT/TOKEN=/ws' // // Le `/ws` final est obligatoire, et les guillemets aussi — le jeton contient un `=`. // // ## Le piège d'horodatage, déjà payé une fois // // Le VM Service livre **l'historique bufférisé d'un coup** au moment du `streamListen`. // Horodater à la réception écrase donc toute la chronologie sous une seule seconde — c'est ce // qui est arrivé au premier essai. On lit `event.timestamp`, jamais `DateTime.now()`. Future main(List args) async { final uri = args.first; final ws = await WebSocket.connect(uri); var id = 0; void call(String method, [Map params = const {}]) { ws.add(jsonEncode({ 'jsonrpc': '2.0', 'id': (++id).toString(), 'method': method, 'params': params, })); } ws.listen((raw) { final m = jsonDecode(raw as String) as Map; if (m['method'] != 'streamNotify') return; final ev = (m['params'] as Map)['event'] as Map; final kind = ev['kind']; // L'heure de l'ENREGISTREMENT, pas celle de la réception : le VM Service livre // l'historique bufférisé d'un coup au moment du streamListen, et horodater à la // réception écraserait toute la chronologie sous une seule seconde. final micros = (ev['timestamp'] as num?)?.toInt(); final ts = micros == null ? '--:--:--' : DateTime.fromMillisecondsSinceEpoch(micros) .toIso8601String() .substring(11, 23); if (kind == 'Logging') { final rec = ev['logRecord'] as Map; final name = (rec['loggerName'] as Map?)?['valueAsString'] ?? ''; final msg = (rec['message'] as Map?)?['valueAsString'] ?? ''; print('$ts [$name] $msg'); } else if (kind == 'WriteEvent') { final bytes = ev['bytes'] as String?; if (bytes != null) { stdout.write('$ts [stdout] ${utf8.decode(base64.decode(bytes))}'); } } }); call('streamListen', {'streamId': 'Logging'}); call('streamListen', {'streamId': 'Stdout'}); call('streamListen', {'streamId': 'Stderr'}); print('--- branché sur $uri ---'); await Future.delayed(const Duration(hours: 2)); }