构建日志是 Gradle 传达构建过程中发生的事情的主要方式。清晰的日志记录有助于您快速了解构建状态、识别问题并有效排除故障。日志中过多的干扰信息会掩盖重要的警告或错误。
Gradle 提供了灵活的日志控制,使您能够根据需要调整详细程度和内容。
Gradle 日志级别
Gradle 定义了六个主要的日志级别
级别 | 描述 |
---|---|
|
错误消息 |
|
重要的信息消息 |
|
警告消息 |
|
进度信息消息 |
|
信息消息 |
|
调试消息 |
默认日志级别为 LIFECYCLE
,提供进度更新,但不会包含过多细节。
选择和设置日志级别
您可以通过命令行选项或配置 gradle.properties
文件来设置日志级别。
CLI 选项 | 属性 | 输出的日志级别 |
---|---|---|
|
|
QUIET 及以上 |
|
|
WARN 及以上 |
无日志选项时 |
LIFECYCLE 及以上 |
|
|
|
INFO 及以上 |
|
|
DEBUG 及以上 (所有日志消息) |
例如,要在项目的 gradle.properties
文件中设置一致的日志级别
org.gradle.logging.level=info
类似地,在命令行中
$ ./gradlew run --info
您可以使用 Gradle 内置的 logger 直接从构建脚本和任务中发出日志消息
tasks.register("logtask") {
doLast {
logger.lifecycle("Lifecycle: Build progress info.")
logger.info("Info: Additional insights.")
logger.debug("Debug: Detailed troubleshooting info.")
}
}
tasks.register('logtask') {
doLast {
logger.lifecycle('Lifecycle: Build progress info.')
logger.info('Info: Additional insights.')
logger.debug('Debug: Detailed troubleshooting info.')
}
}
使用适当的日志级别 (lifecycle
, info
, debug
) 来确保您的构建输出清晰且信息丰富。
DEBUG 日志级别可能会 向控制台暴露敏感安全信息。 |
堆栈跟踪选项
堆栈跟踪对于诊断构建失败期间的问题非常有用。您可以通过命令行选项或属性控制堆栈跟踪的输出
CLI 选项 | Gradle 属性 | 显示的堆栈跟踪 |
---|---|---|
|
|
打印截断的堆栈跟踪。我们推荐此选项而非完整的堆栈跟踪。Groovy 完整的堆栈跟踪由于底层动态调用机制而非常冗长。但它们通常不包含关于您的代码中出现问题的相关信息。此选项会为弃用警告渲染堆栈跟踪。 |
|
|
打印完整的堆栈跟踪。此选项会为弃用警告渲染堆栈跟踪。 |
(无) |
(无) |
在构建错误(例如,编译错误)时,不会向控制台打印堆栈跟踪。仅当发生内部异常时才会打印堆栈跟踪。如果选择了 |
例如,要在构建错误时始终显示完整的堆栈跟踪,请在 gradle.properties
中设置
org.gradle.logging.stacktrace=full
记录敏感信息
使用 DEBUG
日志级别运行 Gradle 可能会向控制台和构建日志暴露敏感信息。
这些信息可能包括
-
环境变量
-
私有仓库凭据
-
构建缓存和 Develocity 凭据
-
插件门户发布凭据
在公共持续集成 (CI) 服务上运行时,务必避免使用 DEBUG
日志级别。这些服务上的构建日志是公开可访问的,可能会暴露敏感信息。即使在私有 CI 服务上,记录敏感凭据也可能存在风险,具体取决于您组织的安全威胁模型。建议与您组织的安全团队讨论此事。
一些 CI 提供商试图从日志中编辑敏感凭据,但此过程并非万无一失,通常只编辑预配置密钥的精确匹配项。
如果您怀疑某个 Gradle 插件可能会无意中暴露敏感信息,请联系我们的安全团队以协助披露。
自定义日志消息
在您的构建文件中进行日志记录的一个简单选项是将消息写入标准输出。Gradle 会将写入标准输出的任何内容重定向到其日志系统,级别为 QUIET
println("A message which is logged at QUIET level")
println 'A message which is logged at QUIET level'
Gradle 还为构建脚本提供了一个 logger
属性,它是 Logger 的实例。该接口扩展了 SLF4J Logger
接口并添加了一些 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
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 模式 在日志消息中用实际值替换占位符。
logger.info("A {} log message", "info")
logger.info('A {} log message', 'info')
您还可以通过 SLF4J logger,在构建中使用的其他类(例如,buildSrc
目录中的类)中接入 Gradle 的日志系统。您可以使用此 logger 的方式与在构建脚本中使用提供的 logger 的方式相同。
import org.slf4j.LoggerFactory
val slf4jLogger = LoggerFactory.getLogger("some-logger")
slf4jLogger.info("An info log message logged using SLF4j")
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
级别。此行为可配置。
project
对象提供了一个 LoggingManager,允许您在评估构建脚本时更改标准输出或错误重定向到的日志级别。
logging.captureStandardOutput(LogLevel.INFO)
println("A message which is logged at INFO level")
logging.captureStandardOutput LogLevel.INFO
println 'A message which is logged at INFO level'
要在任务执行期间更改标准输出或错误的日志级别,请使用 LoggingManager。
tasks.register("logInfo") {
logging.captureStandardOutput(LogLevel.INFO)
doFirst {
println("A task message which is logged at INFO level")
}
}
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,使用您自己的实现。如果您想以某种方式自定义 UI——记录更多或更少信息,或者更改格式,可以这样做。只需使用 Gradle.useLogger(java.lang.Object) 方法替换日志记录即可。这可以从构建脚本、init 脚本或通过嵌入式 API 访问。请注意,这将完全禁用 Gradle 的默认输出。下面是一个示例 init 脚本,它更改了任务执行和构建完成的日志记录方式
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()
}
}
}
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()
}
}
}
$ ./gradlew -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
$ ./gradlew -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
您的 logger 可以实现下面列出的任何监听器接口。当您注册 logger 时,只会替换其实现的接口的日志记录。其他接口的日志记录保持不变。您可以在 构建生命周期事件 中找到更多关于监听器接口的信息。