From 2c3c3873dc1e09e7c94348bc04a3d40f09bb78cc Mon Sep 17 00:00:00 2001 From: Edison Jwa Date: Wed, 3 Jun 2026 18:09:25 +0900 Subject: [PATCH] fix(diag): record bridge and audio interruption diagnostics (#18) * fix(diag): record bridge events in diagnostics page Connection lost/reconnecting/disconnected and iOS audio interruption events now appear in the diagnostics dialog alongside existing error snackbar entries. * fix(diag): reduce audio callback sample verbosity to debug The render callback diagnostic sample logged every 100 callbacks (~2s) at INFO level, flooding the 256-entry release log buffer and pushing out useful events. Changed to DEBUG so it only appears in debug builds with the larger 4096-entry buffer. * fix(diag): add timestamps to Rust diagnostic log entries --- apps/chanora_flutter/lib/main.dart | 5 +++++ crates/chanora_audio/src/ios_voice_unit.rs | 2 +- crates/chanora_diagnostics/src/lib.rs | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/chanora_flutter/lib/main.dart b/apps/chanora_flutter/lib/main.dart index e0b71f0..8f76a24 100644 --- a/apps/chanora_flutter/lib/main.dart +++ b/apps/chanora_flutter/lib/main.dart @@ -624,6 +624,7 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver { }); unawaited(_refreshSnapshot(recordActivity: false, reportErrors: true)); case rust.BridgeEvent_Lost(:final reason): + _recordUiDiagnostic('connection', 'lost: $reason'); setState(() { _phase = ConnectionPhase.reconnecting; _lostReason = reason; @@ -631,12 +632,14 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver { _reconnectDelay = null; }); case rust.BridgeEvent_Reconnecting(:final attempt, :final delaySecs): + _recordUiDiagnostic('connection', 'reconnecting attempt=$attempt delay=${delaySecs}s'); setState(() { _phase = ConnectionPhase.reconnecting; _reconnectAttempt = attempt; _reconnectDelay = delaySecs; }); case rust.BridgeEvent_Disconnected(): + _recordUiDiagnostic('connection', 'disconnected'); setState(() { _resetConnectionUiState(phase: ConnectionPhase.disconnected); }); @@ -708,6 +711,7 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver { if (!mounted) return; final messenger = ScaffoldMessenger.of(context); if (began) { + _recordUiDiagnostic('audio', 'interruption began'); messenger.showSnackBar( SnackBar( content: Text(AppL10n.of(context).iosAudioInterrupted), @@ -716,6 +720,7 @@ class _BetaHomeState extends State<_BetaHome> with WidgetsBindingObserver { ), ); } else if (shouldResume) { + _recordUiDiagnostic('audio', 'interruption ended, resuming'); messenger.showSnackBar( SnackBar( content: Text(AppL10n.of(context).iosAudioResuming), diff --git a/crates/chanora_audio/src/ios_voice_unit.rs b/crates/chanora_audio/src/ios_voice_unit.rs index 7f0ac3a..0b73985 100644 --- a/crates/chanora_audio/src/ios_voice_unit.rs +++ b/crates/chanora_audio/src/ios_voice_unit.rs @@ -877,7 +877,7 @@ impl IosVoiceUnit { last_num_frames = num_frames; cb_count = cb_count.wrapping_add(1); if cb_count.is_multiple_of(100) { - info!( + debug!( target: "chanora_audio", cb = cb_count, num_frames, diff --git a/crates/chanora_diagnostics/src/lib.rs b/crates/chanora_diagnostics/src/lib.rs index 31701e0..cf1b1c6 100644 --- a/crates/chanora_diagnostics/src/lib.rs +++ b/crates/chanora_diagnostics/src/lib.rs @@ -471,9 +471,14 @@ where let mut visitor = FormatVisitor::default(); event.record(&mut visitor); + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default(); + let secs = now.as_secs(); let line = format!( - "[{lvl}] {target}: {msg}{fields}", + "[{lvl}] {ts} {target}: {msg}{fields}", lvl = event.metadata().level(), + ts = secs, target = event.metadata().target(), msg = visitor.message, fields = visitor.rest