Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pipeline pause and build duration #77

Merged
merged 16 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,15 @@ NOTE: `event_type` is always set to `security` for above events and metrics.
| `jenkins.item.location_changed` | Rate of items being moved. | `jenkins_url`, `user_id` |
| `jenkins.item.updated` | Rate of items being updated. | `jenkins_url`, `user_id` |
| `jenkins.job.aborted` | Rate of aborted jobs. | `branch`, `jenkins_url`, `job`, `node`, `user_id` |
| `jenkins.job.buildduration` | Build duration without pause (in seconds). | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
FlorianVeaux marked this conversation as resolved.
Show resolved Hide resolved
| `jenkins.job.completed` | Rate of completed jobs. | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.cycletime` | Build Cycle Time. | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.duration` | Build duration (in seconds). | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.feedbacktime` | Feedback time from code commit to job failure. | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.leadtime` | Build Lead Time. | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.mtbf` | MTBF, time between last successful job and current failed job. | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.mttr` | MTTR: time between last failed job and current successful job. | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
| `jenkins.job.pauseduration` | Pause duration of build job (in seconds). | `branch`, `jenkins_url`, `job`, `node`, `result`, `user_id` |
FlorianVeaux marked this conversation as resolved.
Show resolved Hide resolved
| `jenkins.job.started` | Rate of started jobs. | `branch`, `jenkins_url`, `job`, `node`, `user_id` |
| `jenkins.job.waiting` | Time spent waiting for job to run (in milliseconds). | `branch`, `jenkins_url`, `job`, `node`, `user_id` |
| `jenkins.node.count` | Total number of node. | `jenkins_url` |
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.pipeline-stage-view</groupId>
<artifactId>pipeline-rest-api</artifactId>
<version>2.12</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,20 @@ of this software and associated documentation files (the "Software"), to deal

package org.datadog.jenkins.plugins.datadog.listeners;

import com.cloudbees.workflow.rest.external.RunExt;
import com.cloudbees.workflow.rest.external.StageNodeExt;
import hudson.Extension;
import hudson.model.*;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import org.datadog.jenkins.plugins.datadog.DatadogClient;
import org.datadog.jenkins.plugins.datadog.DatadogEvent;
import org.datadog.jenkins.plugins.datadog.DatadogUtilities;
Expand All @@ -36,12 +47,7 @@ of this software and associated documentation files (the "Software"), to deal
import org.datadog.jenkins.plugins.datadog.events.BuildFinishedEventImpl;
import org.datadog.jenkins.plugins.datadog.events.BuildStartedEventImpl;
import org.datadog.jenkins.plugins.datadog.model.BuildData;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;


/**
Expand All @@ -50,16 +56,16 @@ of this software and associated documentation files (the "Software"), to deal
* - When a build finishes, the {@link #onCompleted(Run, TaskListener)} method will be invoked.
*/
@Extension
public class DatadogBuildListener extends RunListener<Run> {
public class DatadogBuildListener extends RunListener<Run> {

private static final Logger logger = Logger.getLogger(DatadogBuildListener.class.getName());

/**
* Called when a build is first started.
*
* @param run - A Run object representing a particular execution of Job.
* @param run - A Run object representing a particular execution of Job.
* @param listener - A TaskListener object which receives events that happen during some
* operation.
* operation.
*/
@Override
public void onStarted(Run run, TaskListener listener) {
Expand All @@ -72,7 +78,7 @@ public void onStarted(Run run, TaskListener listener) {

// Get Datadog Client Instance
DatadogClient client = getDatadogClient();
if(client == null){
if (client == null) {
return;
}

Expand Down Expand Up @@ -117,9 +123,9 @@ public void onStarted(Run run, TaskListener listener) {
/**
* Called when a build is completed.
*
* @param run - A Run object representing a particular execution of Job.
* @param run - A Run object representing a particular execution of Job.
* @param listener - A TaskListener object which receives events that happen during some
* operation.
* operation.
*/

@Override
Expand All @@ -133,7 +139,7 @@ public void onCompleted(Run run, @Nonnull TaskListener listener) {

// Get Datadog Client Instance
DatadogClient client = getDatadogClient();
if(client == null){
if (client == null) {
return;
}

Expand All @@ -154,6 +160,21 @@ public void onCompleted(Run run, @Nonnull TaskListener listener) {
Map<String, Set<String>> tags = buildData.getTags();
String hostname = buildData.getHostname("unknown");
client.gauge("jenkins.job.duration", buildData.getDuration(0L) / 1000, hostname, tags);
logger.fine(String.format("[%s]: Duration: %s", buildData.getJobName(null), toTimeString(buildData.getDuration(0L))));

if (run instanceof WorkflowRun) {
RunExt extRun = getRunExtForRun((WorkflowRun) run);
long pauseDuration = 0;
for (StageNodeExt stage : extRun.getStages()) {
pauseDuration += stage.getPauseDurationMillis();
}
client.gauge("jenkins.job.pauseduration", pauseDuration / 1000, hostname, tags);
sarah-witt marked this conversation as resolved.
Show resolved Hide resolved
logger.fine(String.format("[%s]: Pause Duration: %s", buildData.getJobName(null), toTimeString(pauseDuration)));
long buildDuration = run.getDuration() - pauseDuration;
client.gauge("jenkins.job.buildduration", buildDuration / 1000, hostname, tags);
logger.fine(
String.format("[%s]: Build Duration (without pause): %s", buildData.getJobName(null), toTimeString(buildDuration)));
}

// Submit counter
client.incrementCounter("jenkins.job.completed", hostname, tags);
Expand All @@ -178,19 +199,24 @@ public void onCompleted(Run run, @Nonnull TaskListener listener) {
long leadTime = run.getDuration() + mttr;

client.gauge("jenkins.job.leadtime", leadTime / 1000, hostname, tags);
logger.fine(String.format("[%s]: Lead time: %s", buildData.getJobName(null), toTimeString(leadTime)));
if (cycleTime > 0) {
client.gauge("jenkins.job.cycletime", cycleTime / 1000, hostname, tags);
logger.fine(String.format("[%s]: Cycle Time: %s", buildData.getJobName(null), toTimeString(cycleTime)));
}
if (mttr > 0) {
client.gauge("jenkins.job.mttr", mttr / 1000, hostname, tags);
logger.fine(String.format("[%s]: MTTR: %s", buildData.getJobName(null), toTimeString(mttr)));
}
} else {
long feedbackTime = run.getDuration();
long mtbf = getMeanTimeBetweenFailure(run);

client.gauge("jenkins.job.feedbacktime", feedbackTime / 1000, hostname, tags);
logger.fine(String.format("[%s]: Feedback Time: %s", buildData.getJobName(null), toTimeString(feedbackTime)));
if (mtbf > 0) {
client.gauge("jenkins.job.mtbf", mtbf / 1000, hostname, tags);
logger.fine(String.format("[%s]: MTBF: %s", buildData.getJobName(null), toTimeString(mtbf)));
}
}

Expand All @@ -211,7 +237,7 @@ public void onDeleted(Run run) {

// Get Datadog Client Instance
DatadogClient client = getDatadogClient();
if(client == null){
if (client == null) {
return;
}

Expand Down Expand Up @@ -241,6 +267,13 @@ public void onDeleted(Run run) {
}
}

private String toTimeString(long millis) {
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
long totalSeconds = TimeUnit.MILLISECONDS.toSeconds(millis);
long seconds = totalSeconds - TimeUnit.MINUTES.toSeconds(minutes);
return String.format("%d min, %d sec", minutes, seconds);
}

private long getMeanTimeBetweenFailure(Run<?, ?> run) {
Run<?, ?> lastGreenRun = run.getPreviousNotFailedBuild();
if (lastGreenRun != null) {
Expand Down Expand Up @@ -280,11 +313,15 @@ private boolean isFailedBuild(Run<?, ?> run) {
return run != null && run.getResult() != Result.SUCCESS;
}

public Queue getQueue(){
public RunExt getRunExtForRun(WorkflowRun run) {
return RunExt.create(run);
}

public Queue getQueue() {
return Queue.getInstance();
}

public DatadogClient getDatadogClient(){
public DatadogClient getDatadogClient() {
return ClientFactory.getClient();
}
}
Loading