Capturing task output

How can I capture output of a task?

In this case, I’d like to capture the output of JavaCompile so that I can produce reports on the warning count. (If anyone knows of an existing plugin to do that, that would be even better, but I’ve already searched and couldn’t find anything.)

What I can’t do is replace System.out, because other tasks may be running in parallel.

Hello,

The user doc has a section on integration third party tools logs with Gradle builds here:

https://docs.gradle.org/current/userguide/logging.html#sec:external_tools

When looking at the javadoc of the LoggingManager (Gradle API 7.0.2) you’ll notice that one can do more than redirecting streams with the add listener methods:

tasks.named('compileTestJava', JavaCompile).configure {
    def warnings = project.layout.buildDirectory.file('compileTestJava.stderr')
    logging.addStandardErrorListener((StandardOutputListener) { CharSequence message ->
        warnings.get().asFile << message
    })
    options.compilerArgs << '-Xlint:all'
}

The nice thing with this code is its simplicity. The less nice thing is that it requires to open/close the underlying output stream for each line I think. If performance is paramount, maybe something like that could be better:

ext {
    warningFile = null
}

tasks.named('compileTestJava', JavaCompile).configure {
    logging.addStandardErrorListener((StandardOutputListener) { CharSequence message ->
        warningFile << message
    })
    options.compilerArgs << '-Xlint:all'
}

gradle.taskGraph.addTaskExecutionListener(new TaskExecutionListener (){

    void beforeExecute(Task task) {
        if (task.name == 'compileTestJava') { // or task instanceof AbstractCompile
            File file = project.file("${project.buildDir}/${task.name}.stderr")
            file.parentFile.mkdirs()
            warningFile = file.newWriter()
        }
    }

    void afterExecute(Task task, TaskState state) {
        if (task.name == 'compileTestJava') { // reuse same condition as in beforeExecute
            warningFile?.close()
        }
    }
})

Both approaches should net the same result in the end:

[/tmp/foo]$ gradle clean test

> Task :compileTestJava
/tmp/foo/src/test/java/FooTest.java:8: warning: [rawtypes] found raw type: List
        List list = new ArrayList();
        ^
  missing type arguments for generic class List<E>
  where E is a type-variable:
    E extends Object declared in interface List
/tmp/foo/src/test/java/FooTest.java:8: warning: [rawtypes] found raw type: ArrayList
        List list = new ArrayList();
                        ^
  missing type arguments for generic class ArrayList<E>
  where E is a type-variable:
    E extends Object declared in class ArrayList
2 warnings

BUILD SUCCESSFUL in 1s
3 actionable tasks: 2 executed, 1 up-to-date
[/tmp/foo]$ cat build/compileTestJava.stderr 
/tmp/foo/src/test/java/FooTest.java:8: warning: [rawtypes] found raw type: List
        List list = new ArrayList();
        ^
  missing type arguments for generic class List<E>
  where E is a type-variable:
    E extends Object declared in interface List
/tmp/foo/src/test/java/FooTest.java:8: warning: [rawtypes] found raw type: ArrayList
        List list = new ArrayList();
                        ^
  missing type arguments for generic class ArrayList<E>
  where E is a type-variable:
    E extends Object declared in class ArrayList
2 warnings