captureToFile static method

void captureToFile(
  1. String path, {
  2. bool append = false,
})

Redirect the process-wide stderr FILE* to path so llama.cpp / ggml log lines (which always go to stderr) become readable to the host app. Idempotent: a second call replaces the active capture file. Call restoreStderr to revert.

On Android the host app should tail this file (e.g. via a periodic read loop) and forward lines to debugPrint / logcat — neither print nor stderr.writeln reach logcat by default.

append mode keeps prior content; otherwise the file is truncated.

Implicitly calls useDefault so log output reaches stderr.

Implementation

static void captureToFile(String path, {bool append = false}) {
  useDefault();

  final libc = _libc;
  final stderrFp = _stderrFilePtr(libc);
  if (stderrFp == null || stderrFp == nullptr) {
    throw const LlamaLogException(
      'could not resolve stderr FILE* for capture',
    );
  }

  final pathPtr = path.toNativeUtf8();
  final modePtr = (append ? 'a' : 'w').toNativeUtf8();
  try {
    final freopen = libc
        .lookupFunction<
          Pointer<Void> Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Void>),
          Pointer<Void> Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Void>)
        >('freopen');
    final result = freopen(pathPtr, modePtr, stderrFp);
    if (result == nullptr) {
      throw LlamaLogException('freopen($path) failed for stderr capture');
    }
    _captureFilePath = path;

    // _IONBF=2: make stderr unbuffered so log lines are visible immediately.
    libc.lookupFunction<
      Int32 Function(Pointer<Void>, Pointer<Char>, Int32, IntPtr),
      int Function(Pointer<Void>, Pointer<Char>, int, int)
    >('setvbuf')(stderrFp, nullptr, 2, 0);
  } finally {
    malloc.free(pathPtr);
    malloc.free(modePtr);
  }
}