skip to content

How does Gradle decide which messages to show for a chosen log level, and what happens to standard out and standard error?

level: middleimportance: should knowfreq 35%

answer

  1. shows chosen level + everything below
  2. System.out -> QUIET, System.err -> ERROR
  3. println survives -q
  4. use logger.info/lifecycle for level-aware
  5. QUIET/ERROR sit at bottom of scale

basics

~10 s

A chosen level shows messages at that level and all less-verbose levels below it. Standard out is captured at QUIET and standard error at ERROR, so both stay visible even at the default level.

solid answer

~40 s

Gradle's levels form a single ordered scale: **ERROR < QUIET < WARNING < LIFECYCLE < INFO < DEBUG** (least to most verbose). When you select a level, Gradle shows every message logged **at or below it in verbosity** — selecting INFO shows ERROR, QUIET, WARNING, LIFECYCLE *and* INFO, but hides DEBUG. Crucially, Gradle **redirects process output streams** into this system: anything written to **`System.out`** is treated as a **QUIET** message and anything on **`System.err`** as **ERROR**. That's why a stray `println` in a build script appears even at the default LIFECYCLE level and even under `-q`. Build authors who want level-aware output should avoid raw printing and use the **`Logger`** API (`logger.info`, `logger.lifecycle`, `logger.quiet`), so their messages obey the active level instead of being pinned to QUIET/ERROR.

code

kotlin · 7 lines
kotlin
tasks.register("diag") {
    doLast {
        logger.lifecycle("visible by default")
        logger.info("only with -i")
        logger.debug("only with -d")
    }
}

go deeper

for a junior

State that a level shows itself plus everything below it on the verbosity scale.

for a middle

Explain the System.out->QUIET / System.err->ERROR capture and why println survives -q.

for a senior

Recommend logger.info/lifecycle over raw printing so output is level-aware, with the API example.

for a principal

Set a logging convention (no raw println; diagnostics at INFO) so default consoles stay clean across teams and CI.

## The single verbosity scale Gradle has one ordered list of levels: ``` ERROR < QUIET < WARNING < LIFECYCLE < INFO < DEBUG (least verbose / shows least) (most verbose / shows most) ``` ## Filtering rule: 'this level and everything below it' Pick a level and Gradle shows messages logged at that level **and all lower-verbosity levels**. Concretely: - **QUIET** → ERROR, QUIET - **WARNING** → ERROR, QUIET, WARNING - **LIFECYCLE** (default) → ERROR, QUIET, WARNING, LIFECYCLE - **INFO** → all of the above + INFO - **DEBUG** → everything So a message logged at LIFECYCLE is hidden when you run at QUIET, but a message logged at QUIET is shown at every level. ## Standard streams are captured Gradle **redirects** the JVM's output streams into its logging system during a build: - `System.out` (and Groovy/Kotlin `println`) → mapped to **QUIET**. - `System.err` → mapped to **ERROR**. Because QUIET and ERROR are at the very bottom of the scale, this output survives almost every level — it shows at the default and even under `--quiet`. That's a frequent surprise: people add a `println` to debug and it never disappears. ## Use the Logger API for level-aware output To make build output respect the active level, log through Gradle's `Logger` instead of printing: ```kotlin tasks.register("report") { doLast { logger.quiet("Always shown") // QUIET logger.lifecycle("Shown by default") // LIFECYCLE logger.info("Only with -i / --info") // INFO logger.debug("Only with -d / --debug") // DEBUG // println("...") // avoid: pinned to QUIET, ignores the level } } ``` This lets a user dial verbosity up or down and have your messages follow, instead of being stuck at QUIET/ERROR. ## Why it matters Understanding the mapping explains two everyday observations: (1) why `println` is impossible to silence with `-q`, and (2) why moving noisy diagnostics to `logger.info(...)` keeps the default console clean while still being reachable with `-i`.

  • Why can't you hide a println with --quiet?
    Gradle maps System.out to the QUIET level, which is at the bottom of the verbosity scale and shown even when QUIET is the active level.
  • How do you make a diagnostic message appear only when the user asks for more detail?
    Log it with logger.info(...) so it appears only under -i/--info (or -d), keeping the default console clean.

saying these in an interview costs you the question

  • Saying a higher level hides lower-level messages — it's the opposite; lower-verbosity messages always show.
  • Believing println respects the chosen log level — it is pinned to QUIET.

context