Michal Kordas
Michal Kordas

Reputation: 10925

Show stacktraces only for unexpected exceptions in Gradle

In my build files I always set option to show stacktraces by default

gradle.startParameter.showStacktrace = org.gradle.api.logging.configuration.ShowStacktrace.ALWAYS 

This is very useful when unexpected failure happens. However, there are some types of failures and causes that are typical (like compilation failure or code quality violation) and in such cases I don't want stacktrace - just meaningful output on console is enough.

Is there a way to disable showing stacktrace for some certain whitelist of exceptions or tasks?

Upvotes: 3

Views: 594

Answers (1)

Michael Easter
Michael Easter

Reputation: 24468

Here is one way, though it is somewhat involved. The idea is based on the notion of a Custom Logger.

Imagine that we have a Java project with 2 extra tasks:

apply plugin: 'java'

task foo() << {
    throw new IllegalStateException("from foo")
}

task bar() << {
    throw new GradleException("from bar") 
}

Suppose further that we want to suppress stacktraces (or print a condensed version) for IllegalStateException and CompilationFailedException (but not GradleException). To this end, consider the following init.gradle file:

useLogger(new CustomEventLogger())

class CustomEventLogger extends BuildAdapter implements TaskExecutionListener {

    def exceptionWhitelist = ["IllegalStateException", "CompilationFailedException"]

    public void beforeExecute(Task task) {
        println "[$task.name]"
    }

    public void afterExecute(Task task, TaskState state) {
        println()
    }
    private def getCauses(def throwable) {
        def causes = []

        def t = throwable

        while (t != null) {
            causes << t.class.simpleName
            t = t.cause
        } 

        causes
    }
    public void buildFinished(BuildResult result) {
        println 'build completed'
        def throwable = result.failure
        if (throwable != null) {
            println "TRACER failed with: " + throwable.class
            def causes = getCauses(throwable)
            if (!hasCauseInWhitelist(causes)) {
                throwable.printStackTrace()
            } else {
                causes.each { println it }
            }
        }
    }
}

The init.gradle must be specified on the command-line. e.g. gradle -I init.gradle compileJava.

It will print condensed info for the two exceptions specified. (Note that walks the hierarchy of causes to find a match.)

The downside is that this "completely disables Gradle's default output", so there may be further tweaks required, depending on requirements.

For example, if I intentionally put a syntax error in Java:

bash$ gradle -I init.gradle compileJava
[compileJava]
~/src/main/java/net/codetojoy/Employee.java:4: error: class, interface, or enum expected
public clazz Employee {
       ^
1 error

build completed
TRACER failed with: class org.gradle.internal.exceptions.LocationAwareException
LocationAwareException
TaskExecutionException
CompilationFailedException

then we observe the condensed info for the stacktrace.

Upvotes: 1

Related Questions