第27章 日志与调试:日志级别、--stacktrace与--scan、Gradle Console

说实话,Gradle 构建跑不起来的时候,最怕的就是两眼一抹黑。我早期带团队的时候,有个同事跑构建报错,日志就一行「BUILD FAILED」,他盯着屏幕看了十分钟,愣是不知道哪里挂了。后来我过去加了个 --stacktrace,好家伙,错误堆栈直接定位到某个插件版本冲突。所以这一章,咱们就把 Gradle 的日志和调试工具彻底捋一遍。

27.1 日志级别:从 QUIET 到 DEBUG

Gradle 的日志系统,说白了就是给你一个「信息过滤器」。你想想看,构建过程中有成百上千条消息,如果全打印出来,你根本找不到重点。所以 Gradle 定义了六个级别,从最安静到最啰嗦:

级别用途典型场景
ERROR只显示错误构建失败时的关键信息
QUIET重要提示生命周期通知、任务结果摘要
WARNING警告信息API 废弃、配置问题
LIFECYCLE默认级别正常构建进度
INFO详细信息任务执行细节、依赖解析
DEBUG调试信息类加载、脚本执行、内部状态

我个人习惯,平时用默认的 LIFECYCLE 就够了。但一旦遇到诡异的问题,我会直接上 --info 甚至 --debug。举个例子:

# 只看关键输出
gradle build -q

# 看详细信息(比如依赖冲突)
gradle dependencies --info

# 看所有内部细节(慎用,输出量巨大)
gradle build --debug
我的小技巧: 如果你觉得 --debug 刷屏太快,可以配合 2>&1 | grep '关键字符串' 过滤。我在排查插件加载顺序时就这么干,效率翻倍。

27.2 --stacktrace:让错误不再「裸奔」

默认情况下,Gradle 只显示错误摘要。比如「Task 'compileJava' failed」。但为什么失败?不知道。这时候 --stacktrace 就是你的救命稻草。

它有两个变体:

  • --stacktrace(短格式):显示 Gradle 内部的调用栈,但会裁剪掉一些无关的框架层。
  • --full-stacktrace(长格式):显示完整的 Java 堆栈,包括 Gradle 内部实现细节。

我一般先用短格式,如果定位不到,再上长格式。比如:

gradle test --stacktrace

输出会告诉你:哪个脚本的哪一行调用了哪个任务,然后哪个插件抛了异常。我曾经遇到一个坑:自定义任务里用了 project.file(),但路径传了个 null。没有 --stacktrace 时只显示「NullPointerException」,加了之后直接定位到第 47 行——原来是我少了个判断。

注意: --full-stacktrace 输出非常长,建议重定向到文件查看:gradle build --full-stacktrace > build.log 2>&1。别在终端里硬看,眼睛会瞎。

27.3 --scan:构建的「CT 扫描」

如果说 --stacktrace 是放大镜,那 --scan 就是核磁共振。它会生成一个 HTML 报告,里面包含:

  • 每个任务的耗时(精确到毫秒)
  • 依赖解析的详细树
  • 插件和脚本的执行顺序
  • 缓存命中/未命中情况
  • 构建环境信息(JDK 版本、Gradle 版本、操作系统)

用法极其简单:

gradle build --scan

执行完后,终端会输出一个链接(比如 https://scans.gradle.com/s/abc123)。打开它,你会看到一个交互式页面。我记得有一次项目构建从 2 分钟突然变成 10 分钟,我打开 scan 一看,发现某个自定义任务居然在每次构建时都重新下载依赖——因为它的 inputs 声明漏了一个文件。这种问题,光看日志根本看不出来。

核心价值: --scan 特别适合团队协作。你可以把链接分享给同事,大家一起分析构建瓶颈。而且它是免费的,Gradle 官方提供的服务,不需要额外配置。

27.4 Gradle Console:实时监控的「仪表盘」

如果你在终端里运行 gradle build,默认会看到一个动态更新的控制台界面。这就是 Gradle Console。它有几个关键区域:

  • 任务树:显示所有任务及其当前状态(待执行、执行中、成功、失败)。
  • 进度条:整体构建的百分比。
  • 日志区域:滚动显示当前正在输出的日志行。
  • 构建结果:最终的成功/失败状态,以及耗时。

我个人特别喜欢它的「任务树」视图。当构建卡住时,你能一眼看到是哪个任务在「转圈圈」。比如有一次,我发现 :app:compileDebugKotlin 一直卡在 80%,就知道是 Kotlin 编译器在吃内存。然后我加了 --max-workers=1 限制并行度,问题就解决了。

如果你想禁用这个控制台界面(比如在 CI 环境里),可以用 --no-daemon --console=plain

gradle build --console=plain

这样输出就是纯文本,适合被其他工具捕获。

27.5 知识体系:日志与调试全景图

下面这张图,把本章的核心逻辑串起来了。你可以把它当作调试时的「导航地图」:

Gradle 日志与调试全景图 构建遇到问题 调整日志级别 -q (QUIET) --info --debug 启用堆栈跟踪 --stacktrace --full-stacktrace 生成构建扫描 --scan Gradle Console 实时监控 虚线表示 Gradle Console 可以同时展示所有调试信息

你看,整个调试流程其实就三步:先调日志级别缩小范围,再用堆栈跟踪定位代码,最后用构建扫描做全局分析。而 Gradle Console 就像你的驾驶舱仪表盘,实时反馈每一步的状态。

27.6 避坑指南:我踩过的三个坑

嗯,这里分享几个真实教训:

  • 别在 CI 里用 --console=auto:默认的自动模式会输出 ANSI 转义字符,导致日志系统解析乱码。我吃过一次亏,排查了半天才发现是控制台颜色代码污染了日志文件。后来统一用 --console=plain
  • --scan 链接别随便公开:虽然 Gradle 官方说扫描数据是匿名的,但里面会包含项目路径、任务名称、依赖版本。如果你公司有安全要求,建议自建 Gradle Enterprise 或者用 --no-scan 禁用。
  • DEBUG 日志别开太久:有一次我忘了关 --debug,结果构建跑了 20 分钟还没结束——因为日志输出太多,I/O 成了瓶颈。记住:调试完立刻切回默认级别。
我的日常调试组合拳:gradle build --info --stacktrace,如果还搞不定,再加 --scan。这套组合能覆盖 90% 的问题。剩下的 10%,嗯… 那就得看源码了。

好了,日志和调试这块就聊到这儿。工具都是死的,关键是形成自己的调试节奏。下次构建挂了,别慌,按这张图一步步来,问题总会现形的。

公众号:蓝海资料掘金营,微信 deep3321