capture<T> static method
Runs body with everything it logs collected into sink.
Parallel tasks each get their own buffer, printed as one block when the task finishes. Interleaving them live would produce a transcript nobody could read, and the alternative — prefixing every line with a task name — still cannot keep a multi-line tool error together.
The log file is unaffected: it is timestamped, so it can carry everything in the order it actually happened.
Implementation
static Future<T> capture<T>(
StringSink sink,
Future<T> Function() body,
) =>
runZoned(
body,
zoneValues: {
_zoneSink: sink,
_zoneIndent: _Counter(indentLevel),
},
);