Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
[JENKINS-29705] Exposed thread dump over HTTP
Browse files Browse the repository at this point in the history
  • Loading branch information
kohsuke committed Nov 16, 2015
1 parent 12cf061 commit 5e8fdbd
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 3 deletions.
Expand Up @@ -26,6 +26,7 @@

import com.google.common.util.concurrent.ListenableFuture;
import hudson.Util;
import hudson.model.Action;
import hudson.model.Executor;
import jenkins.model.CauseOfInterruption;
import org.jenkinsci.plugins.workflow.actions.ErrorAction;
Expand All @@ -38,6 +39,8 @@
import org.jenkinsci.plugins.workflow.steps.StepExecution;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
Expand Down Expand Up @@ -211,4 +214,10 @@ public boolean blocksRestart() {
*/
public abstract @Nonnull Authentication getAuthentication();

/**
* Create {@link Action}s to be attached to {@linkplain #getOwner() owner} when it has UI.
*/
public @Nonnull Collection<? extends Action> createActions() {
return Collections.emptyList();
}
}
Expand Up @@ -76,6 +76,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -99,11 +100,14 @@
import java.beans.Introspector;
import java.util.LinkedHashMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.GuardedBy;

import org.acegisecurity.Authentication;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.jboss.marshalling.reflect.SerializableClassRegistry;

import static java.util.Arrays.asList;
import static org.jenkinsci.plugins.workflow.cps.persistence.PersistenceContext.*;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionList;
import org.kohsuke.accmod.restrictions.DoNotUse;
Expand Down Expand Up @@ -367,9 +371,9 @@ private CpsScript parseScript() throws IOException {
s.execution = this;
if (false) {
System.out.println("scriptName="+s.getClass().getName());
System.out.println(Arrays.asList(s.getClass().getInterfaces()));
System.out.println(Arrays.asList(s.getClass().getDeclaredFields()));
System.out.println(Arrays.asList(s.getClass().getDeclaredMethods()));
System.out.println(asList(s.getClass().getInterfaces()));
System.out.println(asList(s.getClass().getDeclaredFields()));
System.out.println(asList(s.getClass().getDeclaredMethods()));
}
return s;
}
Expand Down Expand Up @@ -813,6 +817,12 @@ void notifyListeners(FlowNode node) {
}
}

@Nonnull
@Override
public Collection<? extends Action> createActions() {
return asList(new CpsThreadDumpAction());
}

@Override public String toString() {
return "CpsFlowExecution[" + owner + "]";
}
Expand Down
@@ -0,0 +1,25 @@
package org.jenkinsci.plugins.workflow.cps;

import hudson.model.Action;

/**
* Shows thread dump for {@link CpsFlowExecution}
*
* @author Kohsuke Kawaguchi
*/
public final class CpsThreadDumpAction implements Action {
@Override
public String getIconFileName() {
return "gear.png";
}

@Override
public String getDisplayName() {
return "Thread Dump";
}

@Override
public String getUrlName() {
return "threadDump";
}
}
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<?jelly escape-by-default='true'?>
<!--
~ The MIT License
~
~ Copyright (c) 2013-2014, CloudBees, Inc.
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->

<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:i="jelly:fmt">
<l:layout title="${%Thread Dump}">
<l:main-panel>
<j:set var="td" value="${it.toString()}"/>

<h1>
${%Thread Dump}
<l:copyButton text="${td}" message="${%Thread dump copied to clipboard}"/>
</h1>

<pre class="console">
${td}
</pre>
</l:main-panel>
</l:layout>
</j:jelly>
@@ -0,0 +1,67 @@
package org.jenkinsci.plugins.workflow.job;

import hudson.Extension;
import hudson.model.Action;
import jenkins.model.TransientActionFactory;
import org.jenkinsci.plugins.workflow.flow.FlowExecution;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* Expose {@link FlowExecution#createActions()} to {@link WorkflowRun}.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class ActionFromFlowExecution extends TransientActionFactory<WorkflowRun> {
@Override
public Class<WorkflowRun> type() {
return WorkflowRun.class;
}

@Nonnull
@Override
public Collection<? extends Action> createFor(WorkflowRun target) {
Collection<? extends Action> actions = target.getExecution().createActions();
List<Action> wrapped = new ArrayList<Action>(actions.size());
for (Action a : actions) {
wrapped.add(new PrefixedAction(a));
}
return wrapped;
}

/**
* Exposes {@link Action} under {@link FlowExecution} by prefixing it.
*/
private final class PrefixedAction implements Action {
private final Action base;

public PrefixedAction(Action base) {
this.base = base;
}

@Override
public String getIconFileName() {
return base.getIconFileName();
}

@Override
public String getDisplayName() {
return base.getDisplayName();
}

@Override
public String getUrlName() {
String u = base.getUrlName();
if (u!=null) {
if (u.startsWith("/")) return u; // relative to context root
if (u.contains("://")) return u; // absolute
u = "execution/"+u;
}
return u;
}
}
}
Expand Up @@ -35,6 +35,7 @@
import hudson.XmlFile;
import hudson.console.AnnotatedLargeText;
import hudson.console.LineTransformationOutputStream;
import hudson.model.Action;
import hudson.model.Computer;
import hudson.model.Executor;
import hudson.model.Item;
Expand Down Expand Up @@ -179,6 +180,7 @@ public WorkflowRun(WorkflowJob job, File dir) throws IOException {
return getRunMixIn().getNextBuild();
}


/**
* Actually executes the workflow.
*/
Expand Down

0 comments on commit 5e8fdbd

Please sign in to comment.