Skip to content

Commit

Permalink
feat(diagnostics): implement endpoint for JMX threadinfo dump
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewazores committed Sep 12, 2024
1 parent c9cf7f8 commit a855cf4
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/main/java/io/cryostat/diagnostic/Diagnostics.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@
*/
package io.cryostat.diagnostic;

import java.lang.management.ThreadInfo;
import java.util.ArrayList;
import java.util.List;

import javax.management.openmbean.CompositeData;

import io.cryostat.targets.Target;
import io.cryostat.targets.TargetConnectionManager;

import com.fasterxml.jackson.annotation.JsonValue;
import io.smallrye.common.annotation.Blocking;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.jboss.resteasy.reactive.RestPath;

@Path("/api/beta/diagnostics/targets/{targetId}")
Expand All @@ -41,4 +51,91 @@ public void gc(@RestPath long targetId) {
conn.invokeMBeanOperation(
"java.lang:type=Memory", "gc", null, null, Void.class));
}

@Path("/threads")
@RolesAllowed("write")
@Blocking
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
@GET
public ThreadDump dumpThreads(@RestPath long targetId) {
return targetConnectionManager.executeConnectedTask(
Target.getTargetById(targetId),
conn -> {
CompositeData[] cd =
conn.invokeMBeanOperation(
"java.lang:type=Threading",
"dumpAllThreads",
new Object[] {true, true},
new String[] {boolean.class.getName(), boolean.class.getName()},
CompositeData[].class);
return new ThreadDump(List.of(cd).stream().map(ThreadInfo::from).toList());
});
}

static record ThreadDump(@JsonValue List<ThreadInfo> threadInfos) {
ThreadDump(List<ThreadInfo> threadInfos) {
this.threadInfos = new ArrayList<>(threadInfos);
}

// FIXME this should return the same text format as jcmd/jstack commands do, ie match the
// HotSpotDiagnosticMXBean dumpThreads operation.
// 2024-09-10 12:36:07
// Full thread dump OpenJDK 64-Bit Server VM (17.0.12+7 mixed mode, sharing):

// Threads class SMR info:
// _java_thread_list=0x00007fb9400018a0, length=15, elements={
// 0x00007fba080278e0, 0x00007fba082158c0, 0x00007fba08216cb0, 0x00007fba0821c1d0,
// 0x00007fba0821d600, 0x00007fba0821ea20, 0x00007fba082203c0, 0x00007fba08221900,
// 0x00007fba08222d80, 0x00007fba0822a4d0, 0x00007fba0822e3d0, 0x00007fba0832b470,
// 0x00007fba08409550, 0x00007fba08630d50, 0x00007fb940000eb0
// }

// "main" #1 prio=5 os_prio=0 cpu=395.16ms elapsed=4884.90s allocated=50569K
// defined_classes=2034 tid=0x00007fba080278e0 nid=0x391297 in Object.wait()
// [0x00007fba0e5fe000]
// java.lang.Thread.State: WAITING (on object monitor)
// at java.lang.Object.wait([email protected]/Native Method)
// - waiting on <0x000000045d468440> (a java.lang.ProcessImpl)
// at java.lang.Object.wait([email protected]/Object.java:338)
// at java.lang.ProcessImpl.waitFor([email protected]/ProcessImpl.java:434)
// - locked <0x000000045d468440> (a java.lang.ProcessImpl)
// at io.quarkus.cli.build.ExecuteUtil.executeProcess(ExecuteUtil.java:73)
// at io.quarkus.cli.build.BuildSystemRunner.run(BuildSystemRunner.java:50)
// at io.quarkus.cli.Dev.call(Dev.java:46)
// at io.quarkus.cli.Dev.call(Dev.java:18)
// at picocli.CommandLine.executeUserObject(CommandLine.java:2045)
// at picocli.CommandLine.access$1500(CommandLine.java:148)
// at
// picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2465)
// at picocli.CommandLine$RunLast.handle(CommandLine.java:2457)
// at picocli.CommandLine$RunLast.handle(CommandLine.java:2419)
// at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2277)
// at picocli.CommandLine$RunLast.execute(CommandLine.java:2421)
// at picocli.CommandLine.execute(CommandLine.java:2174)
// at io.quarkus.cli.QuarkusCli.run(QuarkusCli.java:116)
// at
// io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:140)
// at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
// at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
// at io.quarkus.cli.Main.main(Main.java:9)

// Locked ownable synchronizers:
// - None
//
// ... (trimmed) ...
//
// "G1 Service" os_prio=0 cpu=256.32ms elapsed=4884.90s tid=0x00007fba081ddbf0 nid=0x39129c
// runnable

// "VM Periodic Task Thread" os_prio=0 cpu=743.47ms elapsed=4884.89s tid=0x00007fba0822be20
// nid=0x3912a7 waiting on condition

// JNI global refs: 24, weak refs: 0
@Override
public String toString() {
var sb = new StringBuilder();
this.threadInfos.forEach(sb::append);
return sb.toString();
}
}
}

0 comments on commit a855cf4

Please sign in to comment.