package core.framework.impl.web.management; import core.framework.api.http.ContentType; import core.framework.api.web.Request; import core.framework.api.web.Response; import java.lang.management.LockInfo; import java.lang.management.ManagementFactory; import java.lang.management.MonitorInfo; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.net.UnknownHostException; /** * @author neo */ public class ThreadInfoController { public Response threadUsage(Request request) throws UnknownHostException { ControllerHelper.validateFromLocalNetwork(request.clientIP()); ThreadUsage usage = new ThreadUsage(); ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); usage.threadCount = threadMXBean.getThreadCount(); usage.peakThreadCount = threadMXBean.getPeakThreadCount(); return Response.bean(usage); } public Response threadDump(Request request) throws UnknownHostException { ControllerHelper.validateFromLocalNetwork(request.clientIP()); StringBuilder builder = new StringBuilder(); ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true); for (ThreadInfo thread : threads) { builder.append(toString(thread)).append('\n'); } return Response.text(builder.toString(), ContentType.TEXT_PLAIN); } // port from ThreadInfo.toString, to print all stack frames (ThreadInfo.toString() only print 8 frames) private String toString(ThreadInfo threadInfo) { StringBuilder builder = new StringBuilder() .append('\"').append(threadInfo.getThreadName()).append('\"').append(" Id=").append(threadInfo.getThreadId()).append(' ').append(threadInfo.getThreadState()); if (threadInfo.getLockName() != null) { builder.append(" on ").append(threadInfo.getLockName()); } if (threadInfo.getLockOwnerName() != null) { builder.append(" owned by \"").append(threadInfo.getLockOwnerName()).append("\" Id=").append(threadInfo.getLockOwnerId()); } if (threadInfo.isSuspended()) { builder.append(" (suspended)"); } if (threadInfo.isInNative()) { builder.append(" (in native)"); } builder.append('\n'); printStackTrace(builder, threadInfo); LockInfo[] locks = threadInfo.getLockedSynchronizers(); if (locks.length > 0) { builder.append("\n\tNumber of locked synchronizers = ").append(locks.length); builder.append('\n'); for (LockInfo lock : locks) { builder.append("\t- ").append(lock); builder.append('\n'); } } builder.append('\n'); return builder.toString(); } private void printStackTrace(StringBuilder builder, ThreadInfo threadInfo) { StackTraceElement[] stackTrace = threadInfo.getStackTrace(); for (int i = 0, stackTraceLength = stackTrace.length; i < stackTraceLength; i++) { StackTraceElement stack = stackTrace[i]; builder.append("\tat ").append(stack); builder.append('\n'); if (i == 0 && threadInfo.getLockInfo() != null) { Thread.State threadState = threadInfo.getThreadState(); switch (threadState) { case BLOCKED: builder.append("\t- blocked on ").append(threadInfo.getLockInfo()); builder.append('\n'); break; case WAITING: builder.append("\t- waiting on ").append(threadInfo.getLockInfo()); builder.append('\n'); break; case TIMED_WAITING: builder.append("\t- timed-waiting on ").append(threadInfo.getLockInfo()); builder.append('\n'); break; default: break; } } for (MonitorInfo monitorInfo : threadInfo.getLockedMonitors()) { if (monitorInfo.getLockedStackDepth() == i) { builder.append("\t- locked ").append(monitorInfo); builder.append('\n'); } } } } }