From d78b668e317a6f01560dfea0455a970035d82298 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 30 May 2026 20:27:29 +0200 Subject: [PATCH] =?UTF-8?q?feat(app):=20reportAppDebug=20=E2=80=94=20Live-?= =?UTF-8?q?Debug-Logs=20an=20Bridge=20ohne=20ADB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stefan-Anforderung: Background-Wake-Word-Pipeline klappt noch nicht, ADB nicht zur Hand → Debug via RVS-Log-Pipeline. Logger: - reportAppDebug(scope, message) analog zu reportAppError aber level=info, kein console.error, fuer Live-Diagnose Strategische Log-Punkte: - wakeword.ts: start() emits 'wake.start armed' - wakeword.ts: onWakeDetected emits 'wake.detect state=X' beim Native-Trigger-Empfang - ChatScreen.tsx wake-callback: 'wake.cb callback fired', 'wake.cb startRecording=X', 'wake.cb gong played' - backgroundAudio.ts: 'bg.start slot=X', 'bg.stop service stopped', 'bg.start.fail msg' wenn Service nicht hochkommt Abruf live via curl http://172.0.2.33:3001/api/app-log?lines=100 Damit kann Stefan nach APK-Build (mit allen Native-Fixes + Logger) im Background-Test exakt sehen wo es klemmt: - Kommt 'wake.detect' im Hintergrund an? (WakeLock-Frage) - Kommt 'wake.cb callback fired'? (JS-Bridge-Frage) - Geht 'bg.start slot=wake' durch? (Service-Start-Frage) APK neu bauen. Co-Authored-By: Claude Opus 4.7 (1M context) --- android/src/screens/ChatScreen.tsx | 3 +++ android/src/services/backgroundAudio.ts | 3 +++ android/src/services/logger.ts | 16 ++++++++++++++++ android/src/services/wakeword.ts | 4 ++++ 4 files changed, 26 insertions(+) diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx index 2c56bfe..cdf6efa 100644 --- a/android/src/screens/ChatScreen.tsx +++ b/android/src/screens/ChatScreen.tsx @@ -1270,9 +1270,11 @@ const ChatScreen: React.FC = () => { useEffect(() => { const unsubWake = wakeWordService.onWakeWord(async () => { console.log('[Chat] Gespraechsmodus — starte Auto-Aufnahme'); + import('../services/logger').then(m => m.reportAppDebug('wake.cb', 'callback fired, calling startRecording')).catch(()=>{}); // Conversation-Window: User hat X Sekunden um anzufangen, sonst Konversation aus const windowMs = await loadConvWindowMs(); const started = await audioService.startRecording(true, windowMs); + import('../services/logger').then(m => m.reportAppDebug('wake.cb', `startRecording returned ${started}`)).catch(()=>{}); if (started) { // Erst JETZT signalisieren dass das Mikro wirklich offen ist — // vorher war's noch in der Init-Phase. So weiss der User exakt @@ -1280,6 +1282,7 @@ const ChatScreen: React.FC = () => { // ueber Settings → Wake-Word abschaltbar. ToastAndroid.show('🎤 Mikro offen — sprich jetzt', ToastAndroid.SHORT); playWakeReadySound().catch(() => {}); + import('../services/logger').then(m => m.reportAppDebug('wake.cb', 'gong played + recording started')).catch(()=>{}); } else { // Mikrofon nicht verfuegbar, naechsten Versuch wakeWordService.resume(); diff --git a/android/src/services/backgroundAudio.ts b/android/src/services/backgroundAudio.ts index 2d46fb6..fc3d24c 100644 --- a/android/src/services/backgroundAudio.ts +++ b/android/src/services/backgroundAudio.ts @@ -48,6 +48,7 @@ async function applyState(): Promise { if (slots.size === 0) { try { await BackgroundAudio.stop(); } catch {} console.log('[BackgroundAudio] Service gestoppt (keine Slots)'); + import('./logger').then(m => m.reportAppDebug('bg.stop', 'service stopped')).catch(()=>{}); return; } const reason = topReason(); @@ -55,8 +56,10 @@ async function applyState(): Promise { await BackgroundAudio.start(reason); console.log('[BackgroundAudio] Service aktiv (slot=%s, slots=%s)', reason, [...slots].join('+')); + import('./logger').then(m => m.reportAppDebug('bg.start', `slot=${reason} all=[${[...slots].join(',')}]`)).catch(()=>{}); } catch (err: any) { console.warn('[BackgroundAudio] start fehlgeschlagen:', err?.message || err); + import('./logger').then(m => m.reportAppDebug('bg.start.fail', err?.message || String(err))).catch(()=>{}); } } diff --git a/android/src/services/logger.ts b/android/src/services/logger.ts index f7de265..719fec4 100644 --- a/android/src/services/logger.ts +++ b/android/src/services/logger.ts @@ -78,6 +78,22 @@ export function reportAppError(ev: AppErrorEvent): void { console.error(`[app-error scope=${ev.scope}]`, ev.message, '\n', ev.stack || ''); } +/** Schickt eine Debug-/Info-Message via RVS an die Bridge. Landet ebenfalls + * in /shared/logs/app.log — abrufbar via `curl /api/app-log?lines=N`. + * Im Gegensatz zu reportAppError: keine Stacktrace, level=info, kein + * console.error. Fuer Live-Diagnose im Hintergrund wenn ADB nicht da ist. */ +export function reportAppDebug(scope: string, message: string): void { + try { + rvs.send('app_log' as any, { + ts: Date.now(), + platform: Platform.OS, + level: 'info', + scope, + message: String(message).slice(0, 2000), + }); + } catch {} +} + /** Installiert einen globalen JS-Error-Handler der ungefangene Errors via * RVS an die Bridge schickt. Beim App-Start aufrufen. */ export function installGlobalCrashReporter(): void { diff --git a/android/src/services/wakeword.ts b/android/src/services/wakeword.ts index 7b5f591..18ee4e2 100644 --- a/android/src/services/wakeword.ts +++ b/android/src/services/wakeword.ts @@ -179,6 +179,8 @@ class WakeWordService { try { await OpenWakeWord.start(); console.log('[WakeWord] armed — warte auf "%s"', this.keyword); + // Debug-Log via RVS damit wir auch ohne ADB sehen wann es greift + import('./logger').then(m => m.reportAppDebug('wake.start', `armed, keyword=${this.keyword}`)).catch(()=>{}); ToastAndroid.show(`Lausche auf "${KEYWORD_LABELS[this.keyword]}"`, ToastAndroid.SHORT); this.setState('armed'); return true; @@ -236,6 +238,8 @@ class WakeWordService { } console.log('[WakeWord] Wake-Word "%s" erkannt! (state=%s, barge=%s)', this.keyword, this.state, this.bargeListening); + import('./logger').then(m => m.reportAppDebug('wake.detect', + `keyword=${this.keyword} state=${this.state} barge=${this.bargeListening}`)).catch(()=>{}); this.lastTriggerAt = now; if (this.nativeReady && OpenWakeWord) { try { await OpenWakeWord.stop(); } catch {}