captureToFile static method
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);
}
}