initRuntimeLogging static method

int initRuntimeLogging({
  1. SynheartCoreFFI? ffi,
  2. String? envFilter,
  3. void onLine(
    1. String line
    )?,
  4. bool preferBuffered = true,
})

Initialize Runtime tracing once per process (call before create if you need a custom filter or sink). See the book: book/src/abi/logging.md.

Prefers buffered (pull-based) mode: the runtime formats lines into an internal ring buffer and this bridge polls them on a Timer.periodic, so no function pointer crosses FFI. This is the fix for the Flutter hot-restart crash (Callback invoked after it has been deleted) — the dying isolate can't invalidate a pointer the runtime never held.

Falls back to the legacy push-callback path automatically when the running runtime is too old to export the buffered symbols, so a lagging vendored native lib still logs (it just keeps the old crash exposure on hot restart until the lib is updated).

onLine receives each decoded line in either mode. Returns 0 on success, 1 if already initialized, negative on failure.

Implementation

static int initRuntimeLogging({
  SynheartCoreFFI? ffi,
  String? envFilter,
  void Function(String line)? onLine,
  bool preferBuffered = true,
}) {
  if (_loggingInstalled) return 1;

  final lib = ffi ?? SynheartCoreFFI.load();
  if (lib == null) return -2;

  if (preferBuffered) {
    final rc = _initRuntimeLoggingBuffered(lib, envFilter, onLine);
    // null => buffered symbols unavailable on this runtime; fall through.
    if (rc != null) return rc;
    if (kDebugMode) {
      debugPrint(
        '[synheart] buffered logging unavailable on this runtime; '
        'falling back to callback mode (hot-restart crash exposure remains)',
      );
    }
  }
  return _initRuntimeLoggingCallback(lib, envFilter, onLine);
}