Skip to content
Permalink
Browse files
[JENKINS-20935] Provide separate monitoring pages for each slave node
  • Loading branch information
evernat committed Dec 22, 2013
1 parent 8e09ae7 commit ac7cda8fa1e2a2c781c6e336f69ab11f0d4f0289
@@ -18,8 +18,10 @@
*/
package net.bull.javamelody;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

@@ -44,7 +46,7 @@ void collectLocalContextWithoutErrors() {
private final boolean monitoringDisabled;
private final Timer timer;
private final Collector collector;
private List<JavaInformations> lastJavaInformationsList;
private Map<String, JavaInformations> lastJavaInformationsList;

/**
* Constructor.
@@ -126,7 +128,8 @@ public void stop() {
*/
public void collectWithoutErrors() {
try {
lastJavaInformationsList = RemoteCallHelper.collectJavaInformationsList();
lastJavaInformationsList = new RemoteCallHelper(null)
.collectJavaInformationsListByName();

// inspired by https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/model/LoadStatistics.java#L197
// (note: jobs in quiet period are not counted)
@@ -136,7 +139,9 @@ public void collectWithoutErrors() {
// including values for buildQueueLength in translations*.properties
JdbcWrapper.BUILD_QUEUE_LENGTH.set(queueLength);

collector.collectWithoutErrors(lastJavaInformationsList);
final List<JavaInformations> javaInformations = new ArrayList<JavaInformations>(
getLastJavaInformationsList().values());
collector.collectWithoutErrors(javaInformations);
} catch (final Throwable t) { // NOPMD
LOG.warn("exception while collecting data", t);
}
@@ -156,8 +161,9 @@ void scheduleReportMailForSlaves(final Period period) {
public void run() {
try {
// send the report
new MailReport().sendReportMail(getCollector(), true,
getLastJavaInformationsList(), period);
final List<JavaInformations> javaInformations = new ArrayList<JavaInformations>(
getLastJavaInformationsList().values());
new MailReport().sendReportMail(getCollector(), true, javaInformations, period);
} catch (final Throwable t) { // NOPMD
// no error in this task
LOG.warn("sending mail report failed", t);
@@ -178,7 +184,7 @@ Collector getCollector() {
return collector;
}

List<JavaInformations> getLastJavaInformationsList() {
Map<String, JavaInformations> getLastJavaInformationsList() {
return lastJavaInformationsList;
}

@@ -36,6 +36,7 @@
import java.io.PrintWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -52,17 +53,26 @@
*/
public class NodesController {
private final Collector collector;
private final String nodeName;
private final List<JavaInformations> lastJavaInformationsList;
private final HttpCookieManager httpCookieManager = new HttpCookieManager();

/**
* Constructor.
* @param nodesCollector NodesCollector
* @param nodeName Nom du node
*/
public NodesController(NodesCollector nodesCollector) {
public NodesController(NodesCollector nodesCollector, String nodeName) {
super();
this.collector = nodesCollector.getCollector();
this.lastJavaInformationsList = nodesCollector.getLastJavaInformationsList();
this.nodeName = nodeName;
if (nodeName == null) {
this.lastJavaInformationsList = new ArrayList<JavaInformations>(nodesCollector
.getLastJavaInformationsList().values());
} else {
this.lastJavaInformationsList = Collections.singletonList(nodesCollector
.getLastJavaInformationsList().get(nodeName));
}
}

/**
@@ -93,8 +103,8 @@ public void doMonitoring(HttpServletRequest req, HttpServletResponse resp) throw
final String threadId = req.getParameter(THREAD_ID_PARAMETER);
final String jobId = req.getParameter(JOB_ID_PARAMETER);
final String cacheId = req.getParameter(CACHE_ID_PARAMETER);
messageForReport = RemoteCallHelper.forwardAction(actionName, sessionId,
threadId, jobId, cacheId);
messageForReport = getRemoteCallHelper().forwardAction(actionName,
sessionId, threadId, jobId, cacheId);
} else {
// necessaire si action clear_counter
messageForReport = monitoringController.executeActionIfNeeded(req);
@@ -103,8 +113,8 @@ public void doMonitoring(HttpServletRequest req, HttpServletResponse resp) throw
final SerializableController serializableController = new SerializableController(
collector);
final Range range = serializableController.getRangeForSerializable(req);
final List<JavaInformations> javaInformationsList = RemoteCallHelper
.collectJavaInformationsList();
final List<JavaInformations> javaInformationsList = new ArrayList<JavaInformations>(
getRemoteCallHelper().collectJavaInformationsListByName().values());
final Serializable serializable = serializableController
.createDefaultSerializable(javaInformationsList, range,
messageForReport);
@@ -117,8 +127,8 @@ public void doMonitoring(HttpServletRequest req, HttpServletResponse resp) throw

final String formatParameter = req.getParameter(FORMAT_PARAMETER);
if (req.getParameter(JMX_VALUE) != null) {
final List<String> jmxValues = RemoteCallHelper.collectJmxValues(req
.getParameter(JMX_VALUE));
final List<String> jmxValues = getRemoteCallHelper().collectJmxValues(
req.getParameter(JMX_VALUE));
doJmxValue(resp, jmxValues);
} else if (TransportFormat.isATransportFormat(req.getParameter(FORMAT_PARAMETER))) {
doCompressedSerializable(req, resp, monitoringController);
@@ -160,18 +170,19 @@ private void writeMessage(HttpServletResponse resp, String message, String partT
private void doPdf(HttpServletRequest req, HttpServletResponse resp,
MonitoringController monitoringController) throws IOException, InterruptedException,
ExecutionException {
if (PROCESSES_PART.equalsIgnoreCase(req.getParameter(PART_PARAMETER))) {
final String partParameter = req.getParameter(PART_PARAMETER);
if (PROCESSES_PART.equalsIgnoreCase(partParameter)) {
monitoringController.addPdfContentTypeAndDisposition(req, resp);
final Map<String, List<ProcessInformations>> processInformationsByNodeName = RemoteCallHelper
final Map<String, List<ProcessInformations>> processInformationsByNodeName = getRemoteCallHelper()
.collectProcessInformationsByNodeName();
try {
doPdfProcesses(resp, processInformationsByNodeName);
} finally {
resp.getOutputStream().flush();
}
} else if (MBEANS_PART.equalsIgnoreCase(req.getParameter(PART_PARAMETER))) {
} else if (MBEANS_PART.equalsIgnoreCase(partParameter)) {
monitoringController.addPdfContentTypeAndDisposition(req, resp);
final Map<String, List<MBeanNode>> mbeanNodesByNodeName = RemoteCallHelper
final Map<String, List<MBeanNode>> mbeanNodesByNodeName = getRemoteCallHelper()
.collectMBeanNodesByNodeName();
try {
doPdfMBeans(resp, mbeanNodesByNodeName);
@@ -224,15 +235,15 @@ private void doPart(HttpServletRequest req, HttpServletResponse resp,
InterruptedException, ExecutionException {
// ici, ni web.xml ni pom.xml
if (MBEANS_PART.equalsIgnoreCase(partParameter)) {
final Map<String, List<MBeanNode>> mbeanNodesByNodeName = RemoteCallHelper
final Map<String, List<MBeanNode>> mbeanNodesByNodeName = getRemoteCallHelper()
.collectMBeanNodesByNodeName();
doMBeans(req, resp, mbeanNodesByNodeName);
} else if (PROCESSES_PART.equalsIgnoreCase(partParameter)) {
final Map<String, List<ProcessInformations>> processInformationsByNodeName = RemoteCallHelper
final Map<String, List<ProcessInformations>> processInformationsByNodeName = getRemoteCallHelper()
.collectProcessInformationsByNodeName();
doProcesses(req, resp, processInformationsByNodeName);
} else if (HEAP_HISTO_PART.equalsIgnoreCase(partParameter)) {
final HeapHistogram heapHistoTotal = RemoteCallHelper.collectGlobalHeapHistogram();
final HeapHistogram heapHistoTotal = getRemoteCallHelper().collectGlobalHeapHistogram();
doHeapHisto(req, resp, heapHistoTotal, monitoringController);
} else {
monitoringController.doReport(req, resp, lastJavaInformationsList);
@@ -312,13 +323,13 @@ private void doCompressedSerializable(HttpServletRequest httpRequest,
private Serializable createSerializable(HttpServletRequest httpRequest) throws Exception { // NOPMD
final String part = httpRequest.getParameter(PART_PARAMETER);
if (MBEANS_PART.equalsIgnoreCase(part)) {
return new LinkedHashMap<String, List<MBeanNode>>(
RemoteCallHelper.collectMBeanNodesByNodeName());
return new LinkedHashMap<String, List<MBeanNode>>(getRemoteCallHelper()
.collectMBeanNodesByNodeName());
} else if (PROCESSES_PART.equalsIgnoreCase(part)) {
return new LinkedHashMap<String, List<ProcessInformations>>(
RemoteCallHelper.collectProcessInformationsByNodeName());
return new LinkedHashMap<String, List<ProcessInformations>>(getRemoteCallHelper()
.collectProcessInformationsByNodeName());
} else if (HEAP_HISTO_PART.equalsIgnoreCase(part)) {
return RemoteCallHelper.collectGlobalHeapHistogram();
return getRemoteCallHelper().collectGlobalHeapHistogram();
} else if (THREADS_PART.equalsIgnoreCase(part)) {
final ArrayList<List<ThreadInformations>> result = new ArrayList<List<ThreadInformations>>();
for (final JavaInformations javaInformations : lastJavaInformationsList) {
@@ -348,6 +359,10 @@ private static PrintWriter createWriterFromOutputStream(HttpServletResponse http
return new PrintWriter(MonitoringController.getWriter(httpResponse));
}

private RemoteCallHelper getRemoteCallHelper() {
return new RemoteCallHelper(nodeName);
}

/**
* Is it necessary to collect java informations for this monitoring request?
* @param httpRequest HttpServletRequest
@@ -135,19 +135,24 @@ public T call() throws Throwable {
}
}

private RemoteCallHelper() {
private final String nodeName;

RemoteCallHelper(String nodeName) {
super();
this.nodeName = nodeName;
}

private static <T> Map<String, T> collectDataByNodeName(Callable<T, Throwable> task)
private <T> Map<String, T> collectDataByNodeName(Callable<T, Throwable> task)
throws IOException, InterruptedException, ExecutionException {
final Computer[] computers = Hudson.getInstance().getComputers();
final Map<String, Future<T>> futuresByNodeName = new LinkedHashMap<String, Future<T>>(
computers.length);
final DelegatingTask<T> delegatingTask = new DelegatingTask<T>(task);
for (final Computer c : computers) {
if (c.isOnline()) {
futuresByNodeName.put(c.getName(), c.getChannel().callAsync(delegatingTask));
if (nodeName == null || nodeName.equals(c.getName())) {
futuresByNodeName.put(c.getName(), c.getChannel().callAsync(delegatingTask));
}
}
}
final long now = System.currentTimeMillis();
@@ -156,42 +161,40 @@ private static <T> Map<String, T> collectDataByNodeName(Callable<T, Throwable> t

final Map<String, T> result = new LinkedHashMap<String, T>(futuresByNodeName.size());
for (final Map.Entry<String, Future<T>> entry : futuresByNodeName.entrySet()) {
final String nodeName = entry.getKey();
final String node = entry.getKey();
final Future<T> future = entry.getValue();
final long timeout = Math.max(0, end - System.currentTimeMillis());
try {
result.put(nodeName, future.get(timeout, TimeUnit.MILLISECONDS));
result.put(node, future.get(timeout, TimeUnit.MILLISECONDS));
} catch (final TimeoutException e) {
continue;
}
}
return result;
}

static List<JavaInformations> collectJavaInformationsList() throws IOException,
Map<String, JavaInformations> collectJavaInformationsListByName() throws IOException,
InterruptedException, ExecutionException {
final Map<String, JavaInformations> javaInformationsByNodeName = collectDataByNodeName(JAVA_INFORMATIONS_TASK);
return new ArrayList<JavaInformations>(javaInformationsByNodeName.values());

return collectDataByNodeName(JAVA_INFORMATIONS_TASK);
}

static List<String> collectJmxValues(String jmxValueParameter) throws IOException,
List<String> collectJmxValues(String jmxValueParameter) throws IOException,
InterruptedException, ExecutionException {
return new ArrayList<String>(collectDataByNodeName(new JmxValueTask(jmxValueParameter))
.values());
}

static Map<String, List<MBeanNode>> collectMBeanNodesByNodeName() throws IOException,
Map<String, List<MBeanNode>> collectMBeanNodesByNodeName() throws IOException,
InterruptedException, ExecutionException {
return collectDataByNodeName(MBEANS_TASK);
}

static Map<String, List<ProcessInformations>> collectProcessInformationsByNodeName()
Map<String, List<ProcessInformations>> collectProcessInformationsByNodeName()
throws IOException, InterruptedException, ExecutionException {
return collectDataByNodeName(PROCESS_INFORMATIONS_TASK);
}

static HeapHistogram collectGlobalHeapHistogram() throws IOException, InterruptedException,
HeapHistogram collectGlobalHeapHistogram() throws IOException, InterruptedException,
ExecutionException {
final Map<String, HeapHistogram> heapHistograms = collectDataByNodeName(HEAP_HISTOGRAM_TASK);
HeapHistogram heapHistoTotal = null;
@@ -208,7 +211,7 @@ static HeapHistogram collectGlobalHeapHistogram() throws IOException, Interrupte
return heapHistoTotal;
}

static String forwardAction(String actionName, String sessionId, String threadId, String jobId,
String forwardAction(String actionName, String sessionId, String threadId, String jobId,
String cacheId) throws IOException, InterruptedException, ExecutionException {
final ActionTask task = new ActionTask(actionName, sessionId, threadId, jobId, cacheId);
final Map<String, String> messagesByNodeName = collectDataByNodeName(task);
@@ -75,9 +75,15 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
}

if (requestURI.equals(monitoringSlavesUrl)) {
if (requestURI.startsWith(monitoringSlavesUrl)) {
final String nodeName;
if (requestURI.equals(monitoringSlavesUrl)) {
nodeName = null;
} else {
nodeName = requestURI.substring(monitoringSlavesUrl.length()).replace("/", "");
}
final HttpServletResponse httpResponse = (HttpServletResponse) response;
doMonitoring(httpRequest, httpResponse);
doMonitoring(httpRequest, httpResponse, nodeName);
return;
}

@@ -89,14 +95,15 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
*
* @param httpRequest Http request
* @param httpResponse Http response
* @param nodeName nom du node (slave ou "")
* @throws IOException e
*/
private void doMonitoring(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
throws IOException {
private void doMonitoring(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
String nodeName) throws IOException {
if (NodesController.isJavaInformationsNeeded(httpRequest)) {
getNodesCollector().collectWithoutErrors();
}
final NodesController nodesController = new NodesController(getNodesCollector());
final NodesController nodesController = new NodesController(getNodesCollector(), nodeName);
nodesController.doMonitoring(httpRequest, httpResponse);
}

0 comments on commit ac7cda8

Please sign in to comment.