Patrick Schurig 17b2f03ce0 tools(devlog): garder le pont VM Service au dépôt
flutter run n'imprime pas les traces dart:developer log() — elles partent au VM
Service, ni sur stdout ni dans logcat. Ce pont est ce qui a rendu le passage sur
appareil du 2026-08-25 exploitable ; il ne vivait que dans un scratchpad de session,
alors que le RECAP le donnait « à récupérer au prochain passage ».

Mode d'emploi en tête, avec le piège déjà payé une fois : le VM Service livre
l'historique bufférisé d'un coup au streamListen, donc horodater à la réception
écrase toute la chronologie sous une seule seconde. On lit event.timestamp.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPUo3RMr8SzK6qbFtfBm8H
2026-08-25 21:44:05 +02:00

59 lines
2.1 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
// Capte les traces `dart:developer log()` de l'app en cours d'exécution.
//
// `flutter run` ne les imprime PAS sur stdout (elles partent au VM Service, pas à
// stdout ni à logcat). Sans ce pont, tout ce que `NymeaService._log()` journalise est
// invisible depuis le poste — donc les traces de locale, de télémétrie et d'écriture
// aussi.
//
// Usage : dart vm_logs.dart ws://127.0.0.1:PORT/TOKEN=/ws
Future<void> main(List<String> args) async {
final uri = args.first;
final ws = await WebSocket.connect(uri);
var id = 0;
void call(String method, [Map<String, dynamic> 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<String, dynamic>;
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<void>.delayed(const Duration(hours: 2));
}