日志是构建工具的主要" UI". 如果太冗长,则很容易掩盖真正的警告和问题. 另一方面,您需要相关信息来确定是否出错. 摇篮定义6个日志级别,如图日志级别 . 除了通常可能看到的级别以外,还有两种特定于Gradle的日志级别. 这些级别是QUIETLIFECYCLE . 后者是默认设置,用于报告构建进度.

Log levels

ERROR

错误讯息

QUIET

重要信息消息

WARNING

警告讯息

LIFECYCLE

进度信息消息

INFO

Information messages

DEBUG

调试信息

无论使用什么日志级别,都会显示控制台的丰富组件(构建状态和正在进行的工作区域). 在Gradle 4.0之前,这些丰富的组件仅在日志级别LIFECYCLE或以下显示.

Choosing a log level

您可以使用" 日志级别"命令行选项中显示的命令行开关来选择不同的日志级别. 您还可以使用gradle.properties配置日志级别,请参阅Gradle属性 . 在Stacktrace命令行选项中,您会找到影响stacktrace日志记录的命令行开关.

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

没有记录选项

生命周期及更高

-q or --quiet

安静及更高

-w or --warn

警告及更高

-i or --info

INFO及更高

-d or --debug

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

Stacktrace command-line options

-s or --stacktrace

打印出截断的堆栈跟踪. 我们建议在整个堆栈跟踪中使用此方法. Groovy的全踪迹非常详细(由于底层的动态调用机制.然而,他们通常不包含什么在你的代码出了问题相关的信息.)此选项使得踪迹弃用警告.

-S or --full-stacktrace

完整的堆栈跟踪信息将被打印出来. 此选项为过时警告呈现堆栈跟踪.

<No stacktrace options>

如果发生构建错误(例如,编译错误),则不会将任何堆栈跟踪记录打印到控制台. 仅在内部异常的情况下,才会打印堆栈跟踪. 如果选择了DEBUG日志级别,则始终打印被截断的堆栈跟踪.

Writing your own log messages

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

示例1.使用stdout编写日志消息
build.gradle
println 'A message which is logged at QUIET level'
build.gradle.kts
println("A message which is logged at QUIET level")

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

例子2.编写自己的日志消息
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.')
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.")

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

例子3.用占位符写一条日志消息
build.gradle
logger.info('A {} log message', 'info')
build.gradle.kts
logger.info("A {} log message", "info")

您还可以从构建中使用的其他类(例如,来自buildSrc目录的类)中插入Gradle的日志系统. 只需使用SLF4J记录器. 您可以使用与在构建脚本中使用提供的记录器相同的方式来使用此记录器.

例子4.使用SLF4J写入日志消息
build.gradle
import org.slf4j.LoggerFactory

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

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

Logging from external tools and libraries

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

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

例子5.配置标准输出捕获
build.gradle
logging.captureStandardOutput LogLevel.INFO
println 'A message which is logged at INFO level'
build.gradle.kts
logging.captureStandardOutput(LogLevel.INFO)
println("A message which is logged at INFO level")

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

示例6.为任务配置标准输出捕获
build.gradle
task logInfo {
    logging.captureStandardOutput LogLevel.INFO
    doFirst {
        println 'A task message which is logged at INFO level'
    }
}
build.gradle.kts
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的日志记录系统.

Changing what Gradle logs

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

例子7.自定义Gradle日志
customLogger.init.gradle
useLogger(new CustomEventLogger())

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()
        }
    }
}
customLogger.init.gradle.kts
useLogger(CustomEventLogger())

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.printStackTrace()
        }
    }
}
$ 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
$ 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

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