Gradle 构建 trace 只剩后一次会话,为每次调用使用独立路径
Gradle 的 trace 文件前缀属于一次会话,后续会话复用它会覆盖旧日志。为可控调用分别指定路径,并检查不受控的附加会话是否仍继承同一前缀。
采集了很久的 Gradle build-operation trace,最后文件却只剩一次短模型查询,先检查是否有第二个会话复用了同一个 trace base 路径。文件存在和任务成功,都不能证明它仍是第一次构建的记录。
Gradle 9.7.1 有过一个精确复现:先执行 :hello,再通过 Tooling API 请求构建模型,两次使用相同 base。第一次的 trace 有任务操作,第二次结束后相同文件只保留模型会话。根因是新会话打开已有 <base>-log.txt 时先删除它,再创建文件;这个参数指定的是一份会话输出的文件前缀,不是自动累积目录。
Gradle 9.8.1 的正式实现仍保留这个旧参数契约。不要把一个新目录参数的已合入补丁当成已发行功能,也不要直接对现有日志使用追加操作:不同会话的结构与辅助文件需要一起对应,简单拼接未必得到工具能正确解释的记录。
能够控制每次调用时,为它们提供不同 base。例如对两次明确的命令:
./gradlew :hello -Dorg.gradle.internal.operations.trace=/tmp/gradle-task-session
./gradlew <另一次任务> -Dorg.gradle.internal.operations.trace=/tmp/gradle-second-session
这些名字只是示例,实际采集还应避免与已保存记录撞名。可以先创建一次独立目录,再为该次受控调用指定其中的 base:
trace_dir=$(mktemp -d /tmp/gradle-trace.XXXXXX)
./gradlew <原任务> "-Dorg.gradle.internal.operations.trace=$trace_dir/task"
不要把这个 base 放进会被全部后续会话继承的公共 JVM 参数,再误以为目录唯一就足够。若同一目录中的 task 被第二个会话继续复用,仍可能覆盖第一份记录。Tooling API 客户端也需要给自己启动的会话设置独立前缀;只修改终端那一次调用,不会自动修改 IDE 后台连接。
原案例没有证明 SonarScanner 就是发起第二次连接的进程,排查时应核对真正的调用来源。无法控制隐藏会话参数时,不能承诺上述命令解决全部覆盖;应采用能隔离采集环境或控制客户端参数的方式,并及时保存已完成输出,保留缺口说明。
验收分别记录每次完成时输出的 resolved trace 路径,查看任务操作、会话时长和辅助 tree 文件是否对应。再执行第二次调用,确认第一份文件内容与哈希没有变化,第二份输出落在另一条路径。不能只看文件修改时间或文件仍存在。
这是 Gradle 内部诊断选项,没有稳定公共 API 保证。正式的常规构建或其他性能采集工具有各自接口;这里的范围是明确使用 operations.trace 时避免会话文件碰撞,不保证恢复已经被覆盖的旧 trace。


