Measure total run time per task - including its dependent tasks time

Hi
I have a few tasks defined in my build.gradle file, and some dependencies between them.

For example:
task taskA{} ,task preTaskA{…}, task taskA1{…},
task taskB{…}, task taskB1{…}
task taskC{…},(and much more…)

All these tasks have dependencies set up between them, using dependsOn and mustRunAfter statements. for example something like that:

taskA.dependsOn preTaskA ....
preTaskA.dependsOn taskA1
taskB.dependsOn taskA, taskB1 ...
taskC.mustRunAfter…

Now, the tasks that a user executes from the command line are only the main ones. for example:
taskA, taskB, taskC.
I want to measure the total time per the main “user executed" tasks and not per “actual” Gradle invoked tasks.

so for example, if I run this:
./gradlew taskA taskC
I want to see the total time it took to run the entire taskA and taskC (including their dependent tasks), and not the total time per executed task like preTaskA, taskA1 and so on.

What I tried to do is:
I have a listener that implements TaskExecutionListener, BuildListener
At beforeExecute and afterExecute for every task I sum the time until I have a map contains all the executed tasks and their time.
Then, at buildFinished method I go over this map and grouping the sub-tasks to know the total execution per user-input “main” task.

class TimingsListener implements TaskExecutionListener, BuildListener {
    private long taskStartTime
    private taskTiming = [:]
    private tasksTreeMap = [
                        "taskA":["preTaskA","taskA1", "taskA"],
                        "taskB":["preTaskA", "taskA1", "taskB", "taskB1"],
                        "taskC":["..."]
                        ].withDefault{key -> return []}

    @Override
    void beforeExecute(Task task) {
        taskStartTime = System.currentTimeMillis()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def timePerTask = System.currentTimeMillis() - taskStartTime
        taskTiming[task.getName] = timePerTask
    }

    @Override
    void buildFinished(BuildResult result) {
        def totalTimePerTaskMap = [:]
        def userExecutedTasks = result.getGradle().getStartParameter().getTaskNames()
        for(task in userExecutedTasks){
            def totalTimePerTask = 0
            for(subTask in tasksTreeMap[task]){
                totalTimePerTask += taskTiming[subTask]
            }
            totalTimePerTaskMap[task]= totalTimePerTask
        }
    }

My Questions:

  1. is there an easier and simpler way of doing this?
  2. If not, can I programmatically get the dependent tasks per Task? for example, when a user performs gradle taskA I’ll get a list of “taskA, preTaskA, taskA1”? it will save me the need to define and maintain the tasksTreeMap static map.
  3. if I’ll go with a different approach and will use a custom task (logTime that gets the task name as a parameter) that will be invoked before & after “user-input” tasks, for example:
taskA.dependsOn logTimeStart, preTaskA...
logTimeEnd.mustRunAfter taskA

how can I pass the custom tasks - logTimeStart & logTimeEnd the task name parameter?

taskA.dependsOn logTimeStart("taskA"), preTaskA...
logTimeEnd("taskA").mustRunAfter taskA

I tried to add as many details as possible, as I think other ppl might benefit from this answer as well.

Thank you!

Why do you want this task execution time, are you trying to debug/profile task execution? Have you tried using build scans or the Gradle profiler to get deeper task execution insight?

Well, I want to be able to see the metrics I need in our monitoring platform (DataDog) and not in gradle dashboards. so I only need the time and then be able to send those metrics to wherever I need.