Friday, April 20, 2012

JAJMX scala script to list remote JVM threads using JMX...

A new example script using JAJMX API. This script, named lsthreads, connects to a remote JVM using just the host adress and the used JMX port, and then list all active threads and theirs current states. Some java options (JAVA_OPTS) have been added to allow using this script against itself.
#!/bin/sh
JAVA_OPTS=""
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote"
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.port=9999"
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.ssl=false"
exec java $JAVA_OPTS -jar jajmx.jar -nocompdaemon -usejavacp -savecompiled "$0" "$@"
!#
import jajmx._
import javax.management.openmbean.CompositeData

val host = if (args.size>=1) args(0) else "localhost" 
val port = if (args.size>=2) args(1).toInt else 9999

case class ThreadLock(name:String, ownerId:Option[Long], ownerName:Option[String])

case class ThreadInfo(name:String, id:Long, state:String,lock:Option[ThreadLock],
                      blockedCount:Long, waitedCount:Long)

object ThreadInfo {
  def apply(ti:CompositeData) :ThreadInfo = {
   val id           = ti.get("threadId").toString.toLong
   val name         = ti.get("threadName").toString
   val state        = ti.get("threadState").toString
   val blockedCount = ti.get("blockedCount").toString.toLong
   val waitedCount  = ti.get("waitedCount").toString.toLong
   val lock = Option(ti.get("lockName")) map {_.toString} filter {_.size>0} collect {
                case lockName =>
                    val lockOwnerId = Option(ti.get("lockOwnerId")) map {_.asInstanceOf[Long]} filterNot {_ == -1}
                    val lockOwnerName = Option(ti.get("lockOwnerName")) map {_.toString.trim}
                    ThreadLock(lockName, lockOwnerId, lockOwnerName)
              }
   ThreadInfo(name, id, state, lock, blockedCount, waitedCount)
  }
}

JMX.once(host,port) { jmx =>
  for (threading <- jmx.threading) {
    val ids = threading.get[Array[Long]]("AllThreadIds")
    val rawThreadsInfos = threading.call[Array[CompositeData]]("getThreadInfo", ids).get
    val threadsInfos = rawThreadsInfos map {ThreadInfo(_)} toList
    val countByState = threadsInfos groupBy {_.state} map { case (s,l) => s -> l.size}
    val countByStateStr = countByState map {case (s,l) => s+":"+l} mkString " "
    println("Total %d  %s".format(threadsInfos.size, countByStateStr))
    for ( ti <- threadsInfos sortBy {_.id } ) {
      println("%d - %s - %s".format(ti.id, ti.state, ti.name) )
    }
  }
}

Usage examples, with itself and then with a remote apache tomcat:
$ lsthreads
Total 13  TIMED_WAITING:4 WAITING:2 RUNNABLE:7
1 - RUNNABLE - main
2 - WAITING - Reference Handler
3 - WAITING - Finalizer
4 - RUNNABLE - Signal Dispatcher
9 - RUNNABLE - RMI TCP Accept-0
10 - RUNNABLE - RMI TCP Accept-9999
11 - RUNNABLE - RMI TCP Accept-0
12 - RUNNABLE - RMI TCP Connection(1)-127.0.0.1
13 - TIMED_WAITING - RMI Scheduler(0)
14 - TIMED_WAITING - RMI RenewClean-[127.0.0.1:45376]
15 - TIMED_WAITING - GC Daemon
16 - RUNNABLE - RMI TCP Connection(2)-127.0.0.1
17 - TIMED_WAITING - JMX server connection timeout 17

$ lsthreads 192.168.1.10 1099
Total 17  TIMED_WAITING:6 WAITING:2 RUNNABLE:9
1 - RUNNABLE - main
2 - WAITING - Reference Handler
3 - WAITING - Finalizer
4 - RUNNABLE - Signal Dispatcher
10 - RUNNABLE - RMI TCP Accept-0
11 - RUNNABLE - RMI TCP Accept-1099
12 - RUNNABLE - RMI TCP Accept-0
13 - TIMED_WAITING - GC Daemon
16 - TIMED_WAITING - ContainerBackgroundProcessor[StandardEngine[Catalina]]
17 - RUNNABLE - http-bio-8080-Acceptor-0
18 - TIMED_WAITING - http-bio-8080-AsyncTimeout
19 - RUNNABLE - ajp-bio-8009-Acceptor-0
20 - TIMED_WAITING - ajp-bio-8009-AsyncTimeout
22 - RUNNABLE - RMI TCP Connection(5)-127.0.0.1
23 - TIMED_WAITING - RMI Scheduler(0)
24 - RUNNABLE - RMI TCP Connection(6)-127.0.0.1
27 - TIMED_WAITING - JMX server connection timeout 27

No comments:

Post a Comment