From 936f2bc149edb28fda35e0a69725d410bc327cc8 Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Thu, 8 Aug 2024 16:15:27 -0400 Subject: [PATCH 1/7] Track CPS VM thread queue size and task execution times --- plugin/pom.xml | 4 ++++ .../plugins/workflow/cps/CpsVmExecutorService.java | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index 446599a68..f6bb0ffc3 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -77,6 +77,10 @@ org.jenkins-ci.plugins.workflow workflow-scm-step + + org.jenkins-ci.plugins + metrics + org.jenkins-ci.plugins script-security diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java index 9a67b0fa2..cf904585e 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import jenkins.metrics.api.Metrics; import jenkins.model.Jenkins; import jenkins.security.ImpersonatingExecutorService; import jenkins.util.ContextResettingExecutorService; @@ -38,6 +39,9 @@ */ class CpsVmExecutorService extends InterceptingExecutorService { + private static final String QUEUE_SIZE_METRIC = "jenkins.job.pipeline.cps-vm-thread.queue.size"; + private static final String EXECUTION_DURATION_METRIC = "jenkins.job.pipeline.cps-vm-thread.queue.size"; + @SuppressWarnings("rawtypes") private static final List CATEGORIES = ImmutableList.builder() .addAll(Continuable.categories) @@ -77,9 +81,11 @@ public Void call() { @Override protected Runnable wrap(final Runnable r) { + Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).inc(); return () -> { + Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).dec(); ThreadContext context = setUp(); - try { + try (var timer = Metrics.metricRegistry().timer(EXECUTION_DURATION_METRIC).time()) { r.run(); } catch (final Throwable t) { reportProblem(t); @@ -130,9 +136,11 @@ private void reportProblem(Throwable t) { @Override protected Callable wrap(final Callable r) { + Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).inc(); return () -> { + Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).dec(); ThreadContext context = setUp(); - try { + try (var timer = Metrics.metricRegistry().timer(EXECUTION_DURATION_METRIC).time()) { return r.call(); } catch (final Throwable t) { reportProblem(t); From 9b277cf70fe2aa618a1833641145d87aee0dc6aa Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Mon, 12 Aug 2024 14:45:00 -0400 Subject: [PATCH 2/7] Track time spent waiting in the CPS VM thread as well as the number of in progress operations --- plugin/pom.xml | 4 -- .../workflow/cps/CpsFlowExecution.java | 11 ++++- .../workflow/cps/CpsThreadDumpAction.java | 42 +++++++++++++++++-- .../workflow/cps/CpsVmExecutorService.java | 16 +++---- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index f6bb0ffc3..446599a68 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -77,10 +77,6 @@ org.jenkins-ci.plugins.workflow workflow-scm-step - - org.jenkins-ci.plugins - metrics - org.jenkins-ci.plugins script-security diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java index e8d9ec9a8..ddf40fb8c 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java @@ -386,6 +386,10 @@ enum TimingKind { * Running inside {@link CpsVmExecutorService}, which includes many other things. */ run, + /** + * Time spent waiting in the queue for {@link CpsVmExecutorService}. + */ + runQueue, /** * Saving the program state. * @see CpsThreadGroup#saveProgram(File) @@ -400,7 +404,9 @@ enum TimingKind { /** accumulated time in ns of a given {@link TimingKind#name}; {@link String} key for pretty XStream form */ transient @NonNull Map liveTimings = new ConcurrentHashMap<>(); - /** XStream simplified form of {@link #liveTimings} */ + /** Number of operations of a given {@link TimingKind#name} which are currently in progress. Never persisted. */ + transient @NonNull Map liveCounts = new ConcurrentHashMap<>(); + /** * XStream simplified form of {@link #liveTimings} */ private Map timings; private @NonNull Set internalCalls = ConcurrentHashMap.newKeySet(); @@ -431,9 +437,11 @@ class Timing implements AutoCloseable { private Timing(TimingKind kind) { this.kind = kind; start = System.nanoTime(); + liveCounts.computeIfAbsent(kind.name(), k -> new LongAdder()).increment(); } @Override public void close() { + liveCounts.computeIfAbsent(kind.name(), k -> new LongAdder()).decrement(); liveTimings.computeIfAbsent(kind.name(), k -> new LongAdder()).add(System.nanoTime() - start); } } @@ -1879,6 +1887,7 @@ public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingCont la.add(kv.getValue()); return la; })); + result.liveCounts = new ConcurrentHashMap<>(); return result; } catch (Exception ex) { LOGGER.log(Level.SEVERE, "Failed to even load the FlowExecution", ex); diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java index 835f271de..03824ed8f 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java @@ -5,19 +5,26 @@ import com.cloudbees.jenkins.support.api.Content; import com.google.common.util.concurrent.FutureCallback; import hudson.Extension; +import hudson.Functions; import hudson.model.Action; +import hudson.model.Queue; +import hudson.model.Run; import hudson.security.Permission; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.util.Collections; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import jenkins.model.Jenkins; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.LongAdder; import org.jenkinsci.plugins.workflow.flow.FlowExecution; import org.jenkinsci.plugins.workflow.flow.FlowExecutionList; import org.kohsuke.stapler.HttpResponses; @@ -108,13 +115,40 @@ public CpsThreadDump getThreadDump() { @Override public void addContents(Container container) { container.add(new Content("nodes/master/pipeline-thread-dump.txt") { - @Override public void writeTo(OutputStream outputStream) throws IOException { + @Override public void writeTo(OutputStream outputStream) { PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); for (FlowExecution flow : FlowExecutionList.get()) { if (flow instanceof CpsFlowExecution) { - pw.println("Build: " + flow.getOwner().getExecutable()); - ((CpsFlowExecution) flow).getThreadDump().print(pw); + Queue.Executable ownerExec; + try { + ownerExec = flow.getOwner().getExecutable(); + } catch (IOException e) { + pw.println("No data available for " + flow); + Functions.printStackTrace(e, pw); + pw.println(); + continue; + } + pw.println("Build: " + ownerExec); + if (ownerExec instanceof Run) { + var run = (Run) ownerExec; + var started = Instant.ofEpochMilli(run.getStartTimeInMillis()); + pw.println("Started: " + started); + var duration = Duration.between(started, Instant.now()); + pw.print("Duration: " + duration); + if (duration.toDays() > 3) { + pw.println(" (Running for more than 3 days!)"); + } else { + pw.println(); + } + } + Map sortedTimings = new TreeMap<>(((CpsFlowExecution) flow).liveTimings); + pw.println("Timings:"); + sortedTimings.forEach((k, v) -> pw.println(" " + k + "\t" + v.longValue() / 1000 / 1000 + "ms")); + Map sortedCounts = new TreeMap<>(((CpsFlowExecution) flow).liveCounts); + pw.println("Active operations:"); + sortedCounts.forEach((k, v) -> pw.println(" " + k + "\t" + v.longValue())); pw.println("Approximate graph size: " + ((CpsFlowExecution) flow).approximateNodeCount()); + ((CpsFlowExecution) flow).getThreadDump().print(pw); pw.println(); } } diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java index cf904585e..5f2335ba1 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsVmExecutorService.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -import jenkins.metrics.api.Metrics; import jenkins.model.Jenkins; import jenkins.security.ImpersonatingExecutorService; import jenkins.util.ContextResettingExecutorService; @@ -39,9 +38,6 @@ */ class CpsVmExecutorService extends InterceptingExecutorService { - private static final String QUEUE_SIZE_METRIC = "jenkins.job.pipeline.cps-vm-thread.queue.size"; - private static final String EXECUTION_DURATION_METRIC = "jenkins.job.pipeline.cps-vm-thread.queue.size"; - @SuppressWarnings("rawtypes") private static final List CATEGORIES = ImmutableList.builder() .addAll(Continuable.categories) @@ -81,11 +77,11 @@ public Void call() { @Override protected Runnable wrap(final Runnable r) { - Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).inc(); + var timing = cpsThreadGroup.getExecution().time(CpsFlowExecution.TimingKind.runQueue); return () -> { - Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).dec(); + timing.close(); ThreadContext context = setUp(); - try (var timer = Metrics.metricRegistry().timer(EXECUTION_DURATION_METRIC).time()) { + try { r.run(); } catch (final Throwable t) { reportProblem(t); @@ -136,11 +132,11 @@ private void reportProblem(Throwable t) { @Override protected Callable wrap(final Callable r) { - Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).inc(); + var timing = cpsThreadGroup.getExecution().time(CpsFlowExecution.TimingKind.runQueue); return () -> { - Metrics.metricRegistry().counter(QUEUE_SIZE_METRIC).dec(); + timing.close(); ThreadContext context = setUp(); - try (var timer = Metrics.metricRegistry().timer(EXECUTION_DURATION_METRIC).time()) { + try { return r.call(); } catch (final Throwable t) { reportProblem(t); From 3775801f17be7f920f0c4f0650fdf136a534e8cb Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Mon, 12 Aug 2024 14:45:50 -0400 Subject: [PATCH 3/7] Adjust log message in CpsStepContext.scheduleNextRun exception handler to reflect its severity --- .../org/jenkinsci/plugins/workflow/cps/CpsStepContext.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsStepContext.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsStepContext.java index 89864685b..b5ccd5e84 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsStepContext.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsStepContext.java @@ -435,7 +435,9 @@ public void onFailure(Throwable t) { } }); } catch (IOException x) { - LOGGER.log(Level.FINE, null, x); + // TODO: If the problem is with the FlowNode and not the CpsFlowExecution, should we try to call + // CpsVmExecutorService.reportProblem or CpsFlowExecution.croak to kill the build right away? + LOGGER.log(Level.WARNING, "Unable to load FlowNode or CpsFlowExecution when completing " + this + ", which is likely to cause its execution to hang indefinitely", x); } } From 698be1941f736de11704b1e7305d1f83f9763dae Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Mon, 12 Aug 2024 16:12:48 -0400 Subject: [PATCH 4/7] Track durations of active operations, not just counts --- .../workflow/cps/CpsFlowExecution.java | 18 +++++++--- .../workflow/cps/CpsThreadDumpAction.java | 33 ++++++++++++++++--- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java index ddf40fb8c..ba81d3dfa 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java @@ -404,8 +404,8 @@ enum TimingKind { /** accumulated time in ns of a given {@link TimingKind#name}; {@link String} key for pretty XStream form */ transient @NonNull Map liveTimings = new ConcurrentHashMap<>(); - /** Number of operations of a given {@link TimingKind#name} which are currently in progress. Never persisted. */ - transient @NonNull Map liveCounts = new ConcurrentHashMap<>(); + /** instances of {@link Timing} which have not yet completed for reporting counts and durations in support bundles. Never persisted. */ + transient @NonNull Set liveIncompleteTimings = ConcurrentHashMap.newKeySet(); /** * XStream simplified form of {@link #liveTimings} */ private Map timings; @@ -437,11 +437,19 @@ class Timing implements AutoCloseable { private Timing(TimingKind kind) { this.kind = kind; start = System.nanoTime(); - liveCounts.computeIfAbsent(kind.name(), k -> new LongAdder()).increment(); + liveIncompleteTimings.add(this); + } + + TimingKind getKind() { + return kind; + } + + long getStartNanos() { + return start; } @Override public void close() { - liveCounts.computeIfAbsent(kind.name(), k -> new LongAdder()).decrement(); + liveIncompleteTimings.remove(this); liveTimings.computeIfAbsent(kind.name(), k -> new LongAdder()).add(System.nanoTime() - start); } } @@ -1887,7 +1895,7 @@ public Object unmarshal(HierarchicalStreamReader reader, final UnmarshallingCont la.add(kv.getValue()); return la; })); - result.liveCounts = new ConcurrentHashMap<>(); + result.liveIncompleteTimings = ConcurrentHashMap.newKeySet(); return result; } catch (Exception ex) { LOGGER.log(Level.SEVERE, "Failed to even load the FlowExecution", ex); diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java index 03824ed8f..d96c5f2fb 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java @@ -22,9 +22,12 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; +import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.TreeMap; import java.util.concurrent.atomic.LongAdder; +import java.util.stream.Collectors; import org.jenkinsci.plugins.workflow.flow.FlowExecution; import org.jenkinsci.plugins.workflow.flow.FlowExecutionList; import org.kohsuke.stapler.HttpResponses; @@ -141,14 +144,21 @@ public CpsThreadDump getThreadDump() { pw.println(); } } - Map sortedTimings = new TreeMap<>(((CpsFlowExecution) flow).liveTimings); + var cpsFlow = (CpsFlowExecution) flow; + Map sortedTimings = new TreeMap<>(cpsFlow.liveTimings); pw.println("Timings:"); sortedTimings.forEach((k, v) -> pw.println(" " + k + "\t" + v.longValue() / 1000 / 1000 + "ms")); - Map sortedCounts = new TreeMap<>(((CpsFlowExecution) flow).liveCounts); pw.println("Active operations:"); - sortedCounts.forEach((k, v) -> pw.println(" " + k + "\t" + v.longValue())); - pw.println("Approximate graph size: " + ((CpsFlowExecution) flow).approximateNodeCount()); - ((CpsFlowExecution) flow).getThreadDump().print(pw); + long nanos = System.nanoTime(); + Map> sortedIncompleteTimings = new HashSet<>(cpsFlow.liveIncompleteTimings).stream() + .collect(Collectors.groupingBy(t -> t.getKind().name(), TreeMap::new, + Collectors.mapping(t -> new CountAndDuration(nanos - t.getStartNanos()), + Collectors.reducing(CountAndDuration::new)))); + sortedIncompleteTimings.forEach((k, optional) -> + optional.ifPresent(cd -> + pw.println(" " + k + "\t" + cd.count + "\t" + cd.duration / 1000 / 1000 + "ms"))); + pw.println("Approximate graph size: " + cpsFlow.approximateNodeCount()); + cpsFlow.getThreadDump().print(pw); pw.println(); } } @@ -157,6 +167,19 @@ public CpsThreadDump getThreadDump() { }); } + private static class CountAndDuration { + private final int count; + private final long duration; + CountAndDuration(long duration) { + this.count = 1; + this.duration = duration; + } + CountAndDuration(CountAndDuration a, CountAndDuration b) { + this.count = a.count + b.count; + this.duration = a.duration + b.duration; + } + } + } } From 61f14f56f9cefd441ec53bec0a3ce51c466fd9d0 Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Mon, 12 Aug 2024 16:15:01 -0400 Subject: [PATCH 5/7] Avoid leaking `this` in Timing constructor --- .../org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java index ba81d3dfa..5eb299f22 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java @@ -437,7 +437,6 @@ class Timing implements AutoCloseable { private Timing(TimingKind kind) { this.kind = kind; start = System.nanoTime(); - liveIncompleteTimings.add(this); } TimingKind getKind() { @@ -460,7 +459,9 @@ long getStartNanos() { * @return something to {@link Timing#close} when finished */ Timing time(TimingKind kind) { - return new Timing(kind); + var timing = new Timing(kind); + liveIncompleteTimings.add(timing); + return timing; } static final Logger TIMING_LOGGER = Logger.getLogger(CpsFlowExecution.class.getName() + ".timing"); From 60a014cee0b525a163a2f963da54b44766e42f5a Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Mon, 12 Aug 2024 16:16:43 -0400 Subject: [PATCH 6/7] Revert accidental Javadoc change to minimize diff --- .../org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java index 5eb299f22..51d1354e2 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java @@ -406,7 +406,7 @@ enum TimingKind { transient @NonNull Map liveTimings = new ConcurrentHashMap<>(); /** instances of {@link Timing} which have not yet completed for reporting counts and durations in support bundles. Never persisted. */ transient @NonNull Set liveIncompleteTimings = ConcurrentHashMap.newKeySet(); - /** * XStream simplified form of {@link #liveTimings} */ + /** XStream simplified form of {@link #liveTimings} */ private Map timings; private @NonNull Set internalCalls = ConcurrentHashMap.newKeySet(); From e8af1ac4ede9f3b07ae412e7747ee83ca77bfd46 Mon Sep 17 00:00:00 2001 From: Devin Nusbaum Date: Tue, 13 Aug 2024 15:23:56 -0400 Subject: [PATCH 7/7] Update names of Pipeline-related support bundle components to be more generic --- .../org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java | 4 ++-- .../jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java index 51d1354e2..4a8bc7e72 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsFlowExecution.java @@ -2043,7 +2043,7 @@ public void autopersist(@NonNull FlowNode n) throws IOException { } @Override public String getDisplayName() { - return "Timing data about recently completed Pipeline builds"; + return "Recently completed Pipeline builds"; } @Override public ComponentCategory getCategory() { @@ -2051,7 +2051,7 @@ public void autopersist(@NonNull FlowNode n) throws IOException { } @Override public void addContents(Container container) { - container.add(new Content("nodes/master/pipeline-timings.txt") { + container.add(new Content("nodes/master/pipeline-recent-builds.txt") { @Override public void writeTo(OutputStream outputStream) throws IOException { PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); for (Job job : Jenkins.get().getAllItems(Job.class)) { diff --git a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java index d96c5f2fb..e68c5ba1e 100644 --- a/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java +++ b/plugin/src/main/java/org/jenkinsci/plugins/workflow/cps/CpsThreadDumpAction.java @@ -109,7 +109,7 @@ public CpsThreadDump getThreadDump() { } @Override public String getDisplayName() { - return "Thread dumps of running Pipeline builds"; + return "Running Pipeline builds"; } @Override public ComponentCategory getCategory() { @@ -117,7 +117,7 @@ public CpsThreadDump getThreadDump() { } @Override public void addContents(Container container) { - container.add(new Content("nodes/master/pipeline-thread-dump.txt") { + container.add(new Content("nodes/master/pipeline-running-builds.txt") { @Override public void writeTo(OutputStream outputStream) { PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); for (FlowExecution flow : FlowExecutionList.get()) {