Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[JENKINS-22791] Added heap histogram generation component
- Loading branch information
Showing
1 changed file
with
104 additions
and
0 deletions.
There are no files selected for viewing
104 changes: 104 additions & 0 deletions
104
src/main/java/com/cloudbees/jenkins/support/impl/HeapHisto.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,104 @@ | ||
package com.cloudbees.jenkins.support.impl; | ||
|
||
import com.cloudbees.jenkins.support.AsyncResultCache; | ||
import com.cloudbees.jenkins.support.api.Component; | ||
import com.cloudbees.jenkins.support.api.Container; | ||
import com.cloudbees.jenkins.support.api.Content; | ||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import hudson.Extension; | ||
import hudson.model.Node; | ||
import hudson.remoting.Callable; | ||
import hudson.security.Permission; | ||
import jenkins.model.Jenkins; | ||
import org.jenkinsci.remoting.RoleChecker; | ||
|
||
import javax.management.InstanceNotFoundException; | ||
import javax.management.MBeanException; | ||
import javax.management.MalformedObjectNameException; | ||
import javax.management.ObjectName; | ||
import javax.management.ReflectionException; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.lang.management.ManagementFactory; | ||
import java.util.Collections; | ||
import java.util.Set; | ||
import java.util.WeakHashMap; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
@Extension | ||
public class HeapHisto extends Component { | ||
private static final int OFFSET = 3; | ||
private static final int MAX = 500 + OFFSET; | ||
|
||
private static final Logger logger = Logger.getLogger(HeapHisto.class.getName()); | ||
private final WeakHashMap<Node, String> heapHistoCache = new WeakHashMap<Node, String>(); | ||
|
||
@NonNull | ||
@Override | ||
public Set<Permission> getRequiredPermissions() { | ||
return Collections.singleton(Jenkins.ADMINISTER); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public String getDisplayName() { | ||
return "Master Heap Histogram -histo:live"; | ||
} | ||
|
||
@Override | ||
public void addContents(@NonNull Container result) { | ||
result.add( | ||
new Content("nodes/master/heap-histogram.txt") { | ||
@Override | ||
public void writeTo(OutputStream os) throws IOException { | ||
os.write(getLiveHistogram(Jenkins.getInstance()).getBytes("UTF-8")); | ||
} | ||
} | ||
); | ||
} | ||
|
||
private String getLiveHistogram(Node node) throws IOException { | ||
return AsyncResultCache.get(node, | ||
heapHistoCache, | ||
new GetLiveHeapHistogram(), | ||
"heap histogram", | ||
"N/A: No connection to node, or no cache."); | ||
} | ||
|
||
private static final class GetLiveHeapHistogram implements Callable<String, RuntimeException> { | ||
public String call() { | ||
final String raw = getRawLiveHistogram(); | ||
final String[] lines = raw.split("\n"); | ||
final int limit = MAX <= lines.length ? MAX : lines.length; | ||
|
||
final StringBuilder bos = new StringBuilder(); | ||
|
||
bos.append("Master Heap Histogram -histo:live"); | ||
for (int i=1; i<limit; i++) { | ||
bos.append(lines[i]).append('\n'); | ||
} | ||
|
||
return bos.toString(); | ||
} | ||
|
||
/** {@inheritDoc} */ | ||
@Override | ||
public void checkRoles(RoleChecker checker) throws SecurityException { | ||
// TODO: do we have to verify some role? | ||
} | ||
|
||
private String getRawLiveHistogram() { | ||
String result; | ||
try { | ||
ObjectName objName = new ObjectName("com.sun.management:type=DiagnosticCommand");; | ||
result = (String) ManagementFactory.getPlatformMBeanServer().invoke(objName, "gcClassHistogram", new Object[] {null}, new String[]{String[].class.getName()}); | ||
} | ||
catch (InstanceNotFoundException | ReflectionException | MBeanException | MalformedObjectNameException e) { | ||
logger.log(Level.WARNING,"Could not record heap live histogram.", e); | ||
result = "NA"; | ||
} | ||
return result; | ||
} | ||
} | ||
} |