skip to content

The Logger API

project.logger with its level methods, the LogLevel enum, and routing standard output to a chosen level. Interviewers ask because println in a build script is exactly the habit this replaces.

on this pageshow

questions

5

What is project.logger in a Gradle build, and how do you use it to print messages?

level: juniorimportance: must knowfreq 55%

answer

  1. Logger extends SLF4J Logger
  2. lifecycle = default visible level
  3. use {} placeholders not concat
  4. available on Project, Task, Settings
  5. prefer over println

basics

~10 s

project.logger is Gradle's built-in logger. You call methods like logger.lifecycle("msg"), logger.info(...), logger.quiet(...), logger.error(...) instead of println to emit messages at the right log level.

solid answer

~30 s

Every Gradle `Project` (and `Task`) exposes a `logger` property of type `org.gradle.api.logging.Logger`. It is the idiomatic way to emit build output instead of `println`, because each message is tagged with a level and Gradle decides whether to show it based on the current verbosity. The everyday method is `logger.lifecycle("...")` — the default visible level, used for high-signal progress messages. Other methods map to levels: `quiet`, `info`, `debug`, `warn`, `error`. Because `Logger` extends SLF4J's `Logger`, you also get the standard SLF4J methods and `{}` placeholder formatting (`logger.info("Built {} in {} ms", name, ms)`), which avoids string concatenation when the level is disabled.

code

kotlin · 7 lines
kotlin
tasks.register("report") {
    doLast {
        logger.lifecycle("Generating report...")        // shown by default
        logger.info("Scanned {} files", 42)               // only with --info
        logger.error("Missing config file")               // always shown
    }
}

go deeper

for a junior

Know that logger.lifecycle/info/error exist and are preferred over println for build output.

for a middle

Explain that Logger extends SLF4J, the level-to-method mapping, and {} placeholder deferral.

for a senior

Discuss obtaining a logger in a plugin via Logging.getLogger, and per-task vs per-project loggers.

for a principal

Frame logging discipline as part of build observability and standardize level conventions across a multi-team build.

## What `project.logger` is Every Gradle `Project` object exposes a read-only `logger` property. Its type is `org.gradle.api.logging.Logger`, which **extends `org.slf4j.Logger`** — so it is both a Gradle logger (with Gradle-specific levels) and a fully standard SLF4J logger. The same `logger` is also available on `Task`, `Settings`, `Gradle`, and `Script`, so build scripts and plugins share one logging API. ## Why not `println`? `println` writes straight to `System.out`. Gradle *captures* standard out (see `captureStandardOutput`) and re-routes it, but you lose level information: a `println` cannot be suppressed when the user runs at a quieter level, and it bypasses Gradle's rich console rendering. Using `logger.<level>(...)` lets Gradle decide visibility based on the run's verbosity. ## The methods Gradle adds level-specific convenience methods on top of SLF4J: - `logger.error(...)` — failures. - `logger.warn(...)` — warnings. - `logger.lifecycle(...)` — **the default visible level**; progress/high-signal messages. - `logger.quiet(...)` — always shown unless `--quiet` hides everything below WARN? (no — QUIET is *above* lifecycle: shown even with `-q`). - `logger.info(...)` — shown with `-i`/`--info`. - `logger.debug(...)` — shown with `-d`/`--debug`. There are also generic overloads taking a `LogLevel`: `logger.log(LogLevel.INFO, "...")`. ## SLF4J placeholders Because it is an SLF4J `Logger`, use `{}` placeholders rather than concatenation: ```kotlin logger.info("Processed {} files in {} ms", count, elapsed) ``` If INFO is disabled, the arguments are never converted to strings — this is the standard SLF4J performance benefit. ## Where to get a logger - In a build script: just `logger`. - In a custom task: `logger` is inherited (a per-task logger). - In a plugin class with no project handy: `org.gradle.api.logging.Logging.getLogger(MyClass::class.java)`.

  • Why is `logger.info("x={}", value)` better than `logger.info("x=" + value)`?
    The `{}` form defers string building: if INFO is disabled the arguments are never concatenated, saving the cost. The `+` form always builds the string regardless of level.
  • What type does project.logger have, and why does that matter?
    `org.gradle.api.logging.Logger`, which extends `org.slf4j.Logger`. That means standard SLF4J methods work, plus Gradle adds `lifecycle` and `quiet`.

saying these in an interview costs you the question

  • Saying you should use System.out.println for normal build messages.
  • Claiming logger is only on Project (it is also on Task, Settings, Gradle).
  • Thinking Gradle's Logger is unrelated to SLF4J.

context

open as a page

Describe the LogLevel enum in Gradle and how its levels are ordered relative to each other.

level: middleimportance: must knowfreq 45%

basics

~10 s

org.gradle.api.logging.LogLevel has six values: DEBUG, INFO, LIFECYCLE, WARN, QUIET, ERROR — from most to least verbose. Each maps to a logger method; the active level decides which messages show.

open as a page

When and why would you guard a logging call with logger.isInfoEnabled() or isDebugEnabled()?

level: middleimportance: should knowfreq 22%

basics

~10 s

Wrap a log call in an is...Enabled() check when building the message is expensive. The guard skips that work entirely when the level is off, instead of computing a string that gets thrown away.

open as a page

What does logging.captureStandardOutput(LogLevel) do, and when would a plugin author use it?

level: seniorimportance: should knowfreq 25%

basics

~10 s

It 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.

open as a page

Inside a custom plugin or task class (not a build script), how do you obtain a logger correctly?

level: seniorimportance: should knowfreq 20%

basics

~10 s

In a Task subclass, just use the inherited logger. In a plain plugin class with no project handy, call org.gradle.api.logging.Logging.getLogger(MyClass::class.java) to get a Gradle Logger.

open as a page