Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture time taken by each pipeline stage in jenkins

Tags:

jenkins

I am using a multibranch pipeline in jenkins and would like to record time taken by each pipeline stage and store it in DB. Any ideas on how to get the individual time durations for each build stage? I am just trying to get duration of each stage

like image 775
userAk Avatar asked Sep 13 '18 21:09

userAk


People also ask

How do you get the execution time in Jenkins pipeline?

If you go to the Jenkins page for any build job, there is a "Trend" link at the top of the list of builds on the left that tracks execution time for each build.

How do I add a time stamp in Jenkins pipeline?

In order to use the timestamp information from Jenkins, you need to install the Build Timestamp Plugin and set the timestamp format in the Jenkins configuration (for example, to "yyyyMMdd-HHmm"). In every place where we use the Docker image, we need to add the tag suffix: ${BUILD_TIMESTAMP} .

What are the 3 types of pipelines in Jenkins?

Declarative versus Scripted Pipeline syntax Declarative and Scripted Pipelines are constructed fundamentally differently. Declarative Pipeline is a more recent feature of Jenkins Pipeline which: provides richer syntactical features over Scripted Pipeline syntax, and.

What are three important stages in Jenkins pipeline?

That is, the build, test, and deploy processes all come together in a stage. Generally, a stage block is used to visualize the Jenkins pipeline process. A step is nothing but a single task that executes a specific process at a defined time.


2 Answers

One can use Jenkins workflow API as well to get the data of each stage -

https://Jenkins_URL/job/${jobName}/wfapi/runs

This will return an array of JSON objects (last 10 runs by default)

This data can then be stored in a time-series DB like InfluxDB.

like image 175
Pankaj Saini Avatar answered Nov 15 '22 09:11

Pankaj Saini


The answer of Patrice M. seems to be the most elegant at first, but there is a problem with nested stages and branches. The duration of nested nodes won't be accounted for, instead only the node's own duration will be reported.

Fortunately we can access the TimingAction of the underlying FlowNode that is wrapped by FlowNodeWrapper to calculate the total duration, including nested nodes.

Solution

  1. Find the FlowNode that represents the start of the branch or stage. Get the start time of this node by querying for its TimingAction.
  2. Find the FlowNode that represents the end of the branch or stage. Get the start time of this node by querying for its TimingAction.
  3. Calculate the difference between these two points in time.

Finding the nodes of branches and stages is quite easy using PipelineNodeGraphVisitor of Blue Ocean plugin API as I have shown in previous answers (for branches and for stages).

For getting the start time of a node, there is a handy static method TimingAction.getStartTime(node) which returns the time in milliseconds.

Example

import io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeGraphVisitor
import io.jenkins.blueocean.rest.impl.pipeline.FlowNodeWrapper
import org.jenkinsci.plugins.workflow.actions.TimingAction

pipeline {
    agent any
    
    stages {
        stage('A') {
            stages {
                stage('A1') {
                    steps {
                        sleep 1
                    }
                }
                stage('A2') {
                    steps {
                        sleep 1
                    }
                }
            }
        }
    }
    post {
        always {
            printFinishedStageDurations()
        }
    }
}

void printFinishedStageDurations() {

    def visitor = new PipelineNodeGraphVisitor( currentBuild.rawBuild )

    // To find branches instead, replace NodeType.STAGE by NodeType.PARALLEL
    def stages = visitor.pipelineNodes.findAll{ it.type == FlowNodeWrapper.NodeType.STAGE }
    
    for( stage in stages ) {
        if( stage.node.endNode ) {   // only finished stages have endNode
            def startTime  = TimingAction.getStartTime( stage.node )
            def endTime    = TimingAction.getStartTime( stage.node.endNode )
            def duration   = endTime - startTime
        
            echo "Stage $stage.displayName duration: $duration ms" 
        }
    } 
}

Output

Pipeline Blue Ocean view

NOTE

When running the above example code in sandbox, you will get errors due to use of "unsafe" Jenkins API. This won't happen when moving printStageDurations() into a trusted shared library, as intended.

like image 26
zett42 Avatar answered Nov 15 '22 11:11

zett42