Add an option to pass "-quiet" to Findbugs plugin

Currently the Findbugs logs a lot of messages regarding Analyzing…, Scanning archives…, analysis passes, etc. These can be suppressed by adding -quiet to the command line or adding the following line to FindBugsExecuter:

commandLine.parse(new String[]{"-quiet"});

The biggest issue is that some of these messages get picket as targets by Jenkins, which totally ruins the layout of the build report page.

I tried to override the FindBugsExecuter from the buildSrc, but it was not picked up.

1 Like

I am interested in the same thing. Did you ever find a workaround?

not really - I patched the class in the jar, but this is not a solution

In case anybody is looking for workaround - this is what we ended up doing:

afterEvaluate { Project project ->
    project.tasks.withType(FindBugs) {
        logging.captureStandardError(LogLevel.INFO)
    }
}

Raised as GRADLE-2993.

This would be a nice contribution if someone is willing.

I would like to fix this issue, and passing the -quiet option is easy, but the problem is that I can’t even reproduce the problem. All I get as output when analyzing a project with FindBugs violations is

:findbugsMain

FindBugs rule violations were found. See the report at: file:///Users/jb/projects/foo/build/reports/findbugs/main.html

:compileTestJava

Could you please tell me which version of Gradle you’re using, and post a minimal example build file and Java source file which produces all those traces that you would like to avoid, along with an example of those traces?

Odd. We see the “Scanning” output on our CI server (Jenkins on Ubuntu), but no on our local machines (Mac OS X).

The only way I seem to be able to reproduce this is through a parallel build when 2 tasks are executing findbugs at the same time.

In parallel builds I’ll also get some odd errors from findbugs that never happen when I run it on a single project

Pass 2: Analyzing classes (39 / 575) - 06% complete
                                                  Pass 2: Analyzing classes (78 / 575) - 13% complete
                                               t
Pass 2: Analyzing classes (156 / 575) - 26% complete
                                              5
Pass 2: Analyzing classes (194 / 575) - 33% complete
                                              i
Pass 2: Analyzing classes (233 / 575) - 40% complete
                                              l
Pass 2: Analyzing classes (271 / 575) - 47% complete
                                              2
Pass 2: Analyzing classes (310 / 575) - 53% complete
                                              a
Pass 2: Analyzing classes (349 / 575) - 60% complete
                                              c
Pass 2: Analyzing classes (387 / 575) - 67% complete
                                                 Pass 2: Analyzing classes (426 / 575) - 74% complete
                                              :
Pass 2: Analyzing classes (465 / 575) - 80% complete
                                              8
Pass 2: Analyzing classes (503 / 575) - 87% complete
                                              s
Pass 2: Analyzing classes (542 / 575) - 94% complete
                                              s
Pass 2: Analyzing classes (575 / 575) - 100% complete
Done with analysis
The following errors occurred during analysis:
  Cannot open codebase filesystem:/Users/jengelman/workspace/bloom/bloomhealth/webapps/consumer/build/classes/application.properties
    java.io.IOException: Wrong magic bytes of 23477261 for zip file /Users/jengelman/workspace/bloom/bloomhealth/webapps/consumer/build/classes/application.properties of 148 bytes
      At edu.umd.cs.findbugs.classfile.impl.ZipFileCodeBase.<init>(ZipFileCodeBase.java:85)
      At edu.umd.cs.findbugs.classfile.impl.ZipCodeBaseFactory.makeZipCodeBase(ZipCodeBaseFactory.java:39)
      At edu.umd.cs.findbugs.classfile.impl.ClassFactory.createFilesystemCodeBase(ClassFactory.java:117)
      At edu.umd.cs.findbugs.classfile.impl.FilesystemCodeBaseLocator.openCodeBase(FilesystemCodeBaseLocator.java:75)
      At edu.umd.cs.findbugs.classfile.impl.ClassPathBuilder.processWorkList(ClassPathBuilder.java:601)
      At edu.umd.cs.findbugs.classfile.impl.ClassPathBuilder.build(ClassPathBuilder.java:221)
      At edu.umd.cs.findbugs.FindBugs2.buildClassPath(FindBugs2.java:795)
      At edu.umd.cs.findbugs.FindBugs2.execute(FindBugs2.java:218)
      At org.gradle.api.plugins.quality.internal.findbugs.FindBugsExecuter.runFindbugs(FindBugsExecuter.java:44)
      At org.gradle.api.plugins.quality.internal.findbugs.FindBugsWorkerServer.execute(FindBugsWorkerServer.java:44)
      At org.gradle.api.plugins.quality.internal.findbugs.FindBugsWorkerServer.execute(FindBugsWorkerServer.java:35)
      At org.gradle.api.plugins.quality.internal.findbugs.FindBugsWorkerServer.execute(FindBugsWorkerServer.java:26)
      At org.gradle.process.internal.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:78)
      At org.gradle.process.internal.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:35)
      At org.gradle.process.internal.child.ImplementationClassLoaderWorker.execute(ImplementationClassLoaderWorker.java:85)
      At org.gradle.process.internal.child.ImplementationClassLoaderWorker.execute(ImplementationClassLoaderWorker.java:41)
      At org.gradle.process.internal.child.IsolatedApplicationClassLoaderWorker.call(IsolatedApplicationClassLoaderWorker.java:48)
      At org.gradle.process.internal.child.IsolatedApplicationClassLoaderWorker.call(IsolatedApplicationClassLoaderWorker.java:30)
      At org.gradle.process.internal.launcher.GradleWorkerMain.run(GradleWorkerMain.java:32)
      At org.gradle.process.internal.launcher.GradleWorkerMain.main(GradleWorkerMain.java:37)
The following classes needed for analysis were missing:
  grails.plugins.springsecurity.SpringSecurityService
  org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

Ok, I think I tracked it down to the following: FindBugsSpecBuilder adds the ‘-progress’ argument for FindBugs. That causes the TextUICommandLine class to do the following (from FindBugsExecutor)

findBugs.setProgressCallback(new TextUIProgressCallback(System.out))

Where ‘findBugs’ is an instance of FindBugs2. It appears that when this task is executed in a GradleWorker thread (parallel), then the “System.out” is not captured the same way that it is when the task is run in the GradleMain thread (non-parallel).

Here’s some output with the “debug” flag: https://gist.github.com/johnrengelman/10794363

The output is a little weird, you have to scroll to the write to see it all. That’s copied from my terminal. I’m wondering if the parallel tasks being executed are stepping on each other on the OutputStream.

—Update— I’ve tried redirecting the stream to a file and looking at that and I see a bunch of ^M’s in the file where the terminal output gets wonky. I went back to the TextUIProgressCallback and it has this method:

private void printMessage(String msg) {
        if (msg.length() > 79) {
            msg = msg.substring(0, 79);
        }
        out.print("\r" + msg);
    }

Perhaps the “\r” is causing some issues because it’s not ever printing a new line?

Last night I tried a couple different things by patching the FindBugs library and found no difference in the output.

Digging through the Gradle code, I think it has to do with how StdOut and StdErr are captured from a GradleWorkerProcess.

The FindBugs task itself spawns a new WorkerProcess through the WorkerProcessFactory to actually execute the FindBugs task. When you run non-parallel, then the FindBugs task executes on GradleMain and it spawns a GradleWorkerMain and you don’t get any output.

However, when running in parallel mode, then GradleMain spawns a GradleWorkerMain to execute the FindBugs tasks, which itself spawns another GradleWorkMain to execute the actual FindBugs code and then the output appears on the console.

So it appears that when spawning a WorkerProcess from another WorkerProcess, StdOut and StdErr are not fowarded properly all the way back to the LoggingManager in GradleMain.

And I lied, parallel mode doesn’t use GradleWorkMains to execute each task, those are on Threads inside GradleMain.

Ok, I’ve got to switch off this for awhile. But I did notice that the CodeNarc plugin has the same issue when executing in a parallel build, it’s output ends up on System.out instead of being captured by the LoggingManager.

I looked and the CodeNarc class does:

logging.captureStandardOutput(LogLevel.INFO)

and then executes an Ant task.

So it seems that that capturing just isn’t working correctly in parallel builds when a child process is being launched. I don’t think I can take this one any further.