とあるプロジェクトで、 gradle で findbugs task を実行したときに
Pass 1: Analyzing classes (538 / 552) - 97% complete
Pass 1: Analyzing classes (539 / 552) - 97% complete
みたいな内容がブワーッと出力されて、大事なログが埋もれてしまうようになってしまった。
必ずしも (どのようなプロジェクトでも) おきるわけではなくって、
- gradle task を parallel 実行している (
org.gradle.parallel=true
)- しかも並列度が高い場合?
- FindBugs の実行対象が多い
場合に再現するようである。
これを、根本治療が難しかったので、ちょっと hack をしてログに出力されないようにした、というお話。
原因
- gradle (現時点で 2.12) で parallel processing を有効にしている場合、 標準出力を capture する機構 (
logging.captureStandardOutput()
) がうまくいかない (ことがある?) GRADLE-3000 - gradle の FindBugs plugin は、実行時オプションとして
-progress
をつけている-
Pass 1: Analyzing classes
みたいに出力しているのは progress option の結果 - 上記の stdout capturing がうまく働いた場合、この progress の出力も capture されて log には出力されないはず
-
対処
GRADLE-3000 が直れば一番いいんだけど、一年以上対応される様子もなく、簡単に直す方法も思いつかなかった。ので、とりあえず FindBugs にわたすオプションから -progress
を削除することで対処した。
ざっくりいうと、デフォルトの FindBugs plugin (org.gradle.api.plugins.quality.FindBugsPlugin
) を継承して -progress
を渡さない plugin をつくり、それを使用する、ということ。
具体的には、プロジェクトに
buildSrc/src/main/groovy/FindBugsWithoutProgressPlugin.groovy
という名前で以下のファイルをおいておく。
// groovy は package scope の関数等にアクセスできるみたいだけど一応 package を揃えとく
package org.gradle.api.plugins.quality
import org.gradle.api.JavaVersion
import org.gradle.api.logging.LogLevel
import org.gradle.api.plugins.quality.internal.findbugs.*
class FindBugsWithoutProgressPlugin extends FindBugsPlugin {
// 本来必要ないけど configureTaskDefaults() で extension 使っているので用意しておく
private FindBugsExtension extension
@Override
protected Class<FindBugs> getTaskType() {
return FindBugsWithoutProgress
}
// ここで extension 埋めておく
@Override
protected CodeQualityExtension createExtension() {
extension = super.createExtension() as FindBugsExtension
return extension
}
}
class FindBugsWithoutProgress extends FindBugs {
// FindBugs#run() のほぼそのままのコピペ
@Override
void run() {
new FindBugsClasspathValidator(JavaVersion.current()).validateClasspath(getFindbugsClasspath().files*.name)
// FindBugs の options から -progress を除去する
FindBugsSpec spec = generateSpec()
List<String> args = spec.getArguments()
args.remove(args.indexOf("-progress"))
FindBugsWorkerManager manager = new FindBugsWorkerManager()
logging.captureStandardOutput(LogLevel.DEBUG)
logging.captureStandardError(LogLevel.DEBUG)
FindBugsResult result = manager.runWorker(getProject().getProjectDir(), workerProcessBuilderFactory, getFindbugsClasspath(), spec)
evaluateResult(result);
}
}
あとは
apply plugin: "findbugs"
のように plugin を読み込んでいるところを
apply plugin: FindBugsWithoutProgressPlugin
のように変えればよい。 (findbugs plugin の設定部分はそのままでよい)