日志是构建工具的主要“UI”。如果日志过于冗长,真正的警告和问题很容易被隐藏起来。另一方面,你需要相关信息来确定是否出现问题。Gradle 定义了 6 个日志级别,如 日志级别 中所示。除了你通常可能看到的日志级别外,还有两个特定于 Gradle 的日志级别。这些级别是QUIETLIFECYCLE。后者是默认级别,用于报告构建进度。

日志级别

ERROR

错误消息

QUIET

重要信息消息

WARNING

警告消息

LIFECYCLE

进度信息消息

INFO

信息消息

DEBUG

调试消息

无论使用何种日志级别,控制台的丰富组件(构建状态和正在进行的工作区域)都将显示。在 Gradle 4.0 之前,这些丰富组件仅在日志级别 LIFECYCLE 或更低级别显示。

选择日志级别

您可以使用 日志级别命令行选项 中所示的命令行开关来选择不同的日志级别。您还可以使用 gradle.properties 配置日志级别,请参阅 Gradle 属性。在 堆栈跟踪命令行选项 中,您可以找到影响堆栈跟踪日志记录的命令行开关。

表 1. 日志级别命令行选项
选项 输出日志级别

-q--quiet

QUIET 及更高

-w--warn

WARN 及更高

无日志选项

LIFECYCLE 及更高

-i--info

INFO 及更高

-d--debug

DEBUG 及更高(即所有日志消息)

DEBUG 日志级别可以 向控制台公开安全敏感信息

堆栈跟踪命令行选项

-s--stacktrace

打印截断的堆栈跟踪。我们建议使用此选项,而不是完整的堆栈跟踪。Groovy 完整的堆栈跟踪非常冗长(由于底层的动态调用机制。然而,它们通常不包含与您的代码中出错相关的信息)。此选项为弃用警告呈现堆栈跟踪。

-S--full-stacktrace

打印完整的堆栈跟踪。此选项为弃用警告呈现堆栈跟踪。

<无堆栈跟踪选项>

在发生构建错误(例如编译错误)时,不会向控制台打印堆栈跟踪。只有在发生内部异常时才会打印堆栈跟踪。如果选择了 DEBUG 日志级别,则始终打印截断的堆栈跟踪。

记录敏感信息

使用 DEBUG 日志级别运行 Gradle 可能会向控制台和构建日志公开安全敏感信息。

此信息可能包括但不限于

  • 环境变量

  • 私有存储库凭据

  • 构建缓存和 Develocity 凭据

  • 插件门户 发布凭据

在公共持续集成服务上运行时,不应使用 DEBUG 日志级别。公共持续集成服务的构建日志是世界可视的,并且可能会公开这些敏感信息。根据您组织的威胁模型,在私有 CI 中记录敏感凭据也可能是一个漏洞。请与您组织的安全团队讨论此事。

一些 CI 提供商尝试从日志中清除敏感凭据;但是,这并不完美,通常只清除预先配置的机密的完全匹配项。

如果您认为 Gradle 插件可能会泄露敏感信息,请联系 [email protected] 以获得披露帮助。

编写您自己的日志消息

在构建文件中记录的简单选项是将消息写入标准输出。Gradle 会将写入标准输出的任何内容重定向到其日志记录系统,日志级别为 QUIET

build.gradle.kts
println("A message which is logged at QUIET level")
build.gradle
println 'A message which is logged at QUIET level'

Gradle 还为构建脚本提供了一个 logger 属性,它是 Logger 的一个实例。此接口扩展了 SLF4J Logger 接口,并向其中添加了一些 Gradle 特定的方法。以下是构建脚本中如何使用它的示例

build.gradle.kts
logger.quiet("An info log message which is always logged.")
logger.error("An error log message.")
logger.warn("A warning log message.")
logger.lifecycle("A lifecycle info log message.")
logger.info("An info log message.")
logger.debug("A debug log message.")
logger.trace("A trace log message.") // Gradle never logs TRACE level logs
build.gradle
logger.quiet('An info log message which is always logged.')
logger.error('An error log message.')
logger.warn('A warning log message.')
logger.lifecycle('A lifecycle info log message.')
logger.info('An info log message.')
logger.debug('A debug log message.')
logger.trace('A trace log message.') // Gradle never logs TRACE level logs

使用 典型的 SLF4J 模式 将占位符替换为实际值,作为日志消息的一部分。

build.gradle.kts
logger.info("A {} log message", "info")
build.gradle
logger.info('A {} log message', 'info')

您还可以从构建中使用的其他类(例如来自 buildSrc 目录的类)中连接到 Gradle 的日志记录系统。只需使用 SLF4J 记录器即可。您可以像在构建脚本中使用提供的记录器一样使用此记录器。

build.gradle.kts
import org.slf4j.LoggerFactory

val slf4jLogger = LoggerFactory.getLogger("some-logger")
slf4jLogger.info("An info log message logged using SLF4j")
build.gradle
import org.slf4j.LoggerFactory

def slf4jLogger = LoggerFactory.getLogger('some-logger')
slf4jLogger.info('An info log message logged using SLF4j')

从外部工具和库进行日志记录

在内部,Gradle 使用 Ant 和 Ivy。两者都有自己的日志记录系统。Gradle 将其日志输出重定向到 Gradle 日志记录系统。Ant/Ivy 日志级别与 Gradle 日志级别之间存在 1:1 映射,但 Ant/Ivy TRACE 日志级别除外,它映射到 Gradle DEBUG 日志级别。这意味着默认的 Gradle 日志级别不会显示任何 Ant/Ivy 输出,除非它是一个错误或警告。

有很多工具仍然使用标准输出进行日志记录。默认情况下,Gradle 将标准输出重定向到 QUIET 日志级别,将标准错误重定向到 ERROR 级别。此行为是可配置的。项目对象提供了一个 LoggingManager,允许您在评估构建脚本时更改标准输出或错误重定向到的日志级别。

build.gradle.kts
logging.captureStandardOutput(LogLevel.INFO)
println("A message which is logged at INFO level")
build.gradle
logging.captureStandardOutput LogLevel.INFO
println 'A message which is logged at INFO level'

要更改任务执行期间的标准输出或错误日志级别,任务还提供一个 LoggingManager

build.gradle.kts
tasks.register("logInfo") {
    logging.captureStandardOutput(LogLevel.INFO)
    doFirst {
        println("A task message which is logged at INFO level")
    }
}
build.gradle
tasks.register('logInfo') {
    logging.captureStandardOutput LogLevel.INFO
    doFirst {
        println 'A task message which is logged at INFO level'
    }
}

Gradle 还提供了与 Java Util Logging、Jakarta Commons Logging 和 Log4j 日志工具包的集成。您的构建类使用这些日志工具包编写的任何日志消息都将被重定向到 Gradle 的日志系统。

更改 Gradle 日志记录的内容

配置缓存限制了自定义 Gradle 日志记录 UI 的能力。自定义记录器只能实现 受支持的侦听器接口。当配置缓存条目被重用时,这些接口不会收到事件,因为整个配置阶段都被跳过了。

您可以用自己的内容替换 Gradle 的大部分日志记录 UI。例如,如果您想以某种方式自定义 UI(记录更多或更少的信息,或更改格式),则可以这样做。您可以使用 Gradle.useLogger(java.lang.Object) 方法替换日志记录。这可以通过构建脚本、初始化脚本或嵌入式 API 访问。请注意,这会完全禁用 Gradle 的默认输出。下面是一个示例初始化脚本,它更改了任务执行和构建完成的日志记录方式。

customLogger.init.gradle.kts
useLogger(CustomEventLogger())

@Suppress("deprecation")
class CustomEventLogger() : BuildAdapter(), TaskExecutionListener {

    override fun beforeExecute(task: Task) {
        println("[${task.name}]")
    }

    override fun afterExecute(task: Task, state: TaskState) {
        println()
    }

    override fun buildFinished(result: BuildResult) {
        println("build completed")
        if (result.failure != null) {
            (result.failure as Throwable).printStackTrace()
        }
    }
}
customLogger.init.gradle
useLogger(new CustomEventLogger())

@SuppressWarnings("deprecation")
class CustomEventLogger extends BuildAdapter implements TaskExecutionListener {

    void beforeExecute(Task task) {
        println "[$task.name]"
    }

    void afterExecute(Task task, TaskState state) {
        println()
    }
    
    void buildFinished(BuildResult result) {
        println 'build completed'
        if (result.failure != null) {
            result.failure.printStackTrace()
        }
    }
}
$ gradle -I customLogger.init.gradle.kts build

> Task :compile
[compile]
compiling source

> Task :testCompile
[testCompile]
compiling test source

> Task :test
[test]
running unit tests

> Task :build
[build]

build completed
3 actionable tasks: 3 executed
$ gradle -I customLogger.init.gradle build

> Task :compile
[compile]
compiling source

> Task :testCompile
[testCompile]
compiling test source

> Task :test
[test]
running unit tests

> Task :build
[build]

build completed
3 actionable tasks: 3 executed

您的记录器可以实现下面列出的任何侦听器接口。注册记录器时,仅替换它实现的接口的日志记录。其他接口的日志记录保持不变。您可以在 构建生命周期事件 中了解有关侦听器接口的更多信息。


1。与配置缓存不兼容。