/** * Verbose-Logging-Toggle: console.log laesst sich global stummschalten. * console.warn/console.error bleiben immer an — Fehler will man immer sehen. * * Default: an (true). Toggle ueber Settings → Protokoll → Verbose Logging. * Beim Start wird der gespeicherte Wert geladen, vorher loggen wir normal. */ import AsyncStorage from '@react-native-async-storage/async-storage'; import { Platform } from 'react-native'; import rvs from './rvs'; export const VERBOSE_LOGGING_KEY = 'aria_verbose_logging'; // Original-console.log retten, damit wir die Wrapper jederzeit wieder // "scharf" stellen koennen (sonst waere ein Toggle-an nach -aus tot). const originalLog = console.log.bind(console); const noop = () => {}; let _verbose = true; function applyState(): void { console.log = _verbose ? originalLog : noop; } /** Wert aus AsyncStorage laden und anwenden. Beim App-Start aufrufen. */ export async function initLogger(): Promise { try { const v = await AsyncStorage.getItem(VERBOSE_LOGGING_KEY); _verbose = v !== 'false'; // default: true } catch {} applyState(); } export function isVerboseLogging(): boolean { return _verbose; } export function setVerboseLogging(verbose: boolean): void { _verbose = verbose; applyState(); AsyncStorage.setItem(VERBOSE_LOGGING_KEY, String(verbose)).catch(() => {}); } // ─── App-Crash-Reporting via RVS ──────────────────────────────────── // // Wenn die App crasht — egal ob React-Render-Fehler (ErrorBoundary) oder // ungefangener JS-Error (ErrorUtils-Handler) — schicken wir den Crash // als RVS-Message vom Typ "app_log" an die Bridge. Die schreibt in // /shared/logs/app.log, sodass wir/Diagnostic die Crashes mitlesen // koennen ohne ADB. interface AppErrorEvent { scope: string; message: string; stack?: string; level?: 'error' | 'warn' | 'info'; } let _reportingInstalled = false; /** Schickt einen App-Fehler via RVS an die Bridge. */ export function reportAppError(ev: AppErrorEvent): void { try { rvs.send('app_log' as any, { ts: Date.now(), platform: Platform.OS, level: ev.level || 'error', scope: ev.scope, message: ev.message, stack: (ev.stack || '').slice(0, 8000), }); } catch { // RVS noch nicht connected — Fehler geht im console weiter. } // Plus lokal: console.error, damit Stefan's adb (wenn doch mal verfuegbar) // den Crash sieht. console.error(`[app-error scope=${ev.scope}]`, ev.message, '\n', ev.stack || ''); } /** Installiert einen globalen JS-Error-Handler der ungefangene Errors via * RVS an die Bridge schickt. Beim App-Start aufrufen. */ export function installGlobalCrashReporter(): void { if (_reportingInstalled) return; _reportingInstalled = true; try { const g: any = global as any; const prev = g.ErrorUtils?.getGlobalHandler?.(); g.ErrorUtils?.setGlobalHandler?.((err: any, isFatal: boolean) => { reportAppError({ scope: isFatal ? 'global-fatal' : 'global-nonfatal', message: (err && err.message) || String(err), stack: err && err.stack, }); // Original-Handler weiterhin aufrufen damit React-Native das System- // Crash-Overlay zeigt (im Dev-Build) bzw. in Production sauber stirbt. if (typeof prev === 'function') { try { prev(err, isFatal); } catch {} } }); // unhandled Promise-Rejections — manche RN-Versionen haben das nicht // automatisch im ErrorUtils. g.HermesInternal?.enablePromiseRejectionTracker?.({ allRejections: true, onUnhandled: (id: number, err: any) => { reportAppError({ scope: 'promise-unhandled', level: 'warn', message: (err && err.message) || String(err), stack: err && err.stack, }); }, }); } catch { // ErrorUtils nicht da → nix machen } }