What does logging.captureStandardOutput(LogLevel) do, and when would a plugin author use it?
answer
- LoggingManager via project/task .logging
- routes System.out to a LogLevel
- defaults: out=QUIET, err=ERROR
- captureStandardError counterpart
- tame noisy third-party println
basics
~10 sIt routes anything written to System.out (or System.err via captureStandardError) to a chosen Gradle log level. So a stray println becomes, say, an INFO message instead of always-visible raw output.
solid answer
~40 s`captureStandardOutput(LogLevel)` is on the `LoggingManager` (reachable via `project.logging`, `task.logging`, or `gradle.logging`). It tells Gradle to redirect everything written to `System.out` into the logging system at the given level. By default Gradle captures `System.out` at QUIET and `System.err` at ERROR; calling `logging.captureStandardOutput(LogLevel.INFO)` lowers stdout to INFO, so noisy third-party `println` output only appears when the user runs with `-i`. There is a matching `captureStandardError(LogLevel)`. Plugin authors use it to tame chatty libraries they call into — wrapping a code block so the library's raw stdout is treated as INFO/DEBUG rather than cluttering normal builds. Scope matters: setting it on `task.logging` affects that task's execution; on `project.logging` it has broader effect. It is a blunt instrument — prefer using the `logger` directly when you control the code.
code
kotlin · 8 linestasks.register("runNoisyTool") {
doLast {
// Demote the tool's raw stdout/stderr so it only shows with -i
logging.captureStandardOutput(LogLevel.INFO)
logging.captureStandardError(LogLevel.INFO)
NoisyLibrary().run() // its println(...) now becomes INFO output
}
}go deeper
Likely out of scope; at most know that Gradle captures System.out so println still appears.
Know the method exists on the logging manager and routes System.out to a chosen LogLevel.
Explain defaults (out=QUIET, err=ERROR), scoping via task vs project logging, and the noisy-library use case.
Set guidance discouraging stdout reliance and standardizing how library noise is demoted across builds.
## The problem it solves Third-party libraries (and legacy code) often write directly to `System.out`/`System.err` with `println`. That output bypasses Gradle's level system and would otherwise always show. Gradle *captures* standard streams so this text still flows through the logging pipeline — and `captureStandardOutput`/`captureStandardError` let you choose **at which level** that captured text is emitted. ## The API The method lives on `org.gradle.api.logging.LoggingManager`, exposed as the `logging` property on `Project`, `Task`, `Gradle`, and `Script`: ```kotlin // Treat anything printed to System.out during this configuration as INFO logging.captureStandardOutput(LogLevel.INFO) logging.captureStandardError(LogLevel.WARN) ``` - **Default behavior:** Gradle captures `System.out` at `QUIET` and `System.err` at `ERROR`. (QUIET means a raw println is visible even in fairly quiet runs.) - Lowering stdout to INFO/DEBUG means that output is hidden in a normal build and only surfaces under `-i`/`-d`. ## Scope and lifecycle The `LoggingManager` you call it on determines scope: - `task.logging.captureStandardOutput(...)` — applies during that task's execution. - `project.logging` / `gradle.logging` — broader scope. Because stream capture is process-global state, Gradle manages save/restore around the scoped region so concurrent tasks are not corrupted. ## When to reach for it - You invoke a noisy library inside a task and want its raw stdout demoted to INFO. - You are migrating an old build where `println` is everywhere and you want it level-controlled without rewriting every call. ## When NOT to - For your own messages, call `logger.info(...)` / `logger.lifecycle(...)` directly — it is clearer and avoids global stream juggling. - It does not give you per-message control; everything on that stream gets the one level. ## Mental model Think of it as a funnel: all of `System.out` -> one chosen `LogLevel` -> Gradle's visibility rules. It changes the *level tag* of un-tagged output, not the destination.
- At what levels does Gradle capture System.out and System.err by default?System.out is captured at QUIET and System.err at ERROR by default, so raw println/printStackTrace output is visible in normal builds.
- Why prefer logger.info over relying on captureStandardOutput for your own code?captureStandardOutput is global, blunt, and applies one level to all stream output; calling logger.info directly is explicit, per-message, and avoids manipulating process-wide stream state.
- Where does the captureStandardOutput method live?On org.gradle.api.logging.LoggingManager, reached via the `logging` property of Project, Task, Gradle, or Script.
saying these in an interview costs you the question
- Saying it redirects output to a file (it changes the log level, not the destination).
- Claiming the default capture level for stdout is LIFECYCLE (it is QUIET).
- Confusing it with the logger methods — captureStandardOutput is about un-tagged System.out, not logger calls.