-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ci.queue_time for pipeline/stage/job traces (#159)
* Send ci.queue_time in Jenkins Build/Pipelines * Remove unnecesary empty lines * Add docs * Remove unnecesary imports * Propagate queue time * Add tests queue time * BuildData queue time * Remove unnecesary system.out * Propagate queue time only in Start Pipeline or Stages nodes
- Loading branch information
1 parent
285f3ba
commit bf8eb41
Showing
15 changed files
with
539 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
src/main/java/org/datadog/jenkins/plugins/datadog/listeners/DatadogQueueListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package org.datadog.jenkins.plugins.datadog.listeners; | ||
|
||
import hudson.Extension; | ||
import hudson.model.Queue; | ||
import hudson.model.Run; | ||
import hudson.model.queue.QueueListener; | ||
import org.datadog.jenkins.plugins.datadog.model.FlowNodeQueueData; | ||
import org.datadog.jenkins.plugins.datadog.model.PipelineQueueInfoAction; | ||
import org.jenkinsci.plugins.workflow.flow.FlowExecution; | ||
import org.jenkinsci.plugins.workflow.graph.FlowNode; | ||
import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepExecution; | ||
|
||
import javax.annotation.CheckForNull; | ||
import java.io.IOException; | ||
import java.util.logging.Logger; | ||
|
||
@Extension | ||
public class DatadogQueueListener extends QueueListener { | ||
|
||
private static final Logger logger = Logger.getLogger(DatadogQueueListener.class.getName()); | ||
|
||
@Override | ||
public void onEnterBuildable(Queue.BuildableItem item) { | ||
try { | ||
final Queue.Task task = item.task; | ||
if(task == null) { | ||
logger.fine("onEnterBuildable: item: " + item + ", task is null"); | ||
return; | ||
} | ||
|
||
if(!(task instanceof ExecutorStepExecution.PlaceholderTask)) { | ||
logger.fine("onEnterBuildable: item: " + item + ", task:" + task + " is not ExecutorStepExecution.PlaceholderTask: " + task.getClass() ); | ||
return; | ||
} | ||
|
||
final ExecutorStepExecution.PlaceholderTask placeholderTask = (ExecutorStepExecution.PlaceholderTask) task; | ||
final FlowNode flowNode = placeholderTask.getNode(); | ||
|
||
if(flowNode == null) { | ||
logger.fine("onEnterBuildable PlaceholderTask: " + placeholderTask + ", FlowNode: is null"); | ||
return; | ||
} | ||
|
||
final Run<?,?> run = runFor(flowNode.getExecution()); | ||
if(run == null) { | ||
logger.fine("onEnterBuildable FlowNode: " + flowNode + ", run is null."); | ||
return; | ||
} | ||
|
||
final PipelineQueueInfoAction queueAction = run.getAction(PipelineQueueInfoAction.class); | ||
if(queueAction == null){ | ||
logger.fine("onEnterBuildable: queueAction: is null"); | ||
return; | ||
} | ||
|
||
final FlowNodeQueueData flowNodeData = queueAction.get(flowNode.getId()); | ||
if(flowNodeData != null) { | ||
flowNodeData.setEnterBuildable(System.currentTimeMillis()); | ||
} else { | ||
final FlowNodeQueueData data = new FlowNodeQueueData(flowNode.getId()); | ||
data.setEnterBuildable(System.currentTimeMillis()); | ||
queueAction.put(flowNode.getId(), data); | ||
} | ||
|
||
} catch (Exception e){ | ||
logger.severe("Error onEnterBuildable: item:" + item + ", exception: " + e); | ||
} | ||
|
||
} | ||
|
||
@Override | ||
public void onLeaveBuildable(Queue.BuildableItem item) { | ||
try { | ||
final Queue.Task task = item.task; | ||
if(task == null) { | ||
logger.fine("onLeaveBuildable: item: " + item + ", task is null"); | ||
return; | ||
} | ||
|
||
if(!(task instanceof ExecutorStepExecution.PlaceholderTask)) { | ||
logger.fine("onLeaveBuildable: item: " + item + ", task:" + task + " is not ExecutorStepExecution.PlaceholderTask: " + task.getClass() ); | ||
return; | ||
} | ||
|
||
final ExecutorStepExecution.PlaceholderTask placeholderTask = (ExecutorStepExecution.PlaceholderTask) task; | ||
final FlowNode flowNode = placeholderTask.getNode(); | ||
if(flowNode == null) { | ||
logger.fine("onLeaveBuildable PlaceholderTask: " + placeholderTask + ", FlowNode: is null"); | ||
return; | ||
} | ||
|
||
Run<?,?> run = runFor(flowNode.getExecution()); | ||
if(run == null) { | ||
logger.fine("onLeaveBuildable FlowNode: " + flowNode + ", run is null."); | ||
return; | ||
} | ||
|
||
PipelineQueueInfoAction queueAction = run.getAction(PipelineQueueInfoAction.class); | ||
if(queueAction == null){ | ||
logger.fine("onLeaveBuildable: queueAction: is null"); | ||
return; | ||
} | ||
|
||
final FlowNodeQueueData flowNodeData = queueAction.get(flowNode.getId()); | ||
if(flowNodeData != null) { | ||
flowNodeData.setLeaveBuildable(System.currentTimeMillis()); | ||
} | ||
} catch (Exception e){ | ||
logger.severe("Error onLeaveBuildable: item:" + item + ", exception: " + e); | ||
} | ||
} | ||
|
||
/** | ||
* Gets the jenkins run object of the specified executing workflow. | ||
* | ||
* @param exec execution of a workflow | ||
* @return jenkins run object of a job | ||
*/ | ||
private static @CheckForNull | ||
Run<?, ?> runFor(FlowExecution exec) { | ||
Queue.Executable executable; | ||
try { | ||
executable = exec.getOwner().getExecutable(); | ||
} catch (IOException x) { | ||
return null; | ||
} | ||
if (executable instanceof Run) { | ||
return (Run<?, ?>) executable; | ||
} else { | ||
return null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
src/main/java/org/datadog/jenkins/plugins/datadog/model/FlowNodeQueueData.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.datadog.jenkins.plugins.datadog.model; | ||
|
||
import java.io.Serializable; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
/** | ||
* Keeps the timestamps of a certain FlowNode based on the onEnterBuildable and onLeaveBuildable callbacks. | ||
*/ | ||
public class FlowNodeQueueData implements Serializable { | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
private final String nodeId; | ||
private long enterBuildable; | ||
private long leaveBuildable; | ||
|
||
public FlowNodeQueueData(final String nodeId) { | ||
this.nodeId = nodeId; | ||
} | ||
|
||
public void setEnterBuildable(long timestamp) { | ||
this.enterBuildable = timestamp; | ||
} | ||
|
||
public void setLeaveBuildable(long timestamp) { | ||
this.leaveBuildable = timestamp; | ||
} | ||
|
||
public long getSecondsInQueue() { | ||
return TimeUnit.MILLISECONDS.toSeconds(this.leaveBuildable - enterBuildable); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
final StringBuilder sb = new StringBuilder("FlowNodeQueueData{"); | ||
sb.append("nodeId=").append(nodeId); | ||
sb.append(", enterBuildable=").append(enterBuildable); | ||
sb.append(", leaveBuildable=").append(leaveBuildable); | ||
sb.append('}'); | ||
return sb.toString(); | ||
} | ||
} |
Oops, something went wrong.