Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Kyle Dodge
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Kyle Dodge@kldodge )

Generate A Java Thread Dump Programmatically Using ColdFusion

By Ben Nadel on
Tags: ColdFusion

As I've been getting used to managing an application within a larger, Kubernetes (K8) based platform, I've found myself needing to do much more programmatic introspection of the ColdFusion application and its underlying JVM (Java Virtual Machine). With such introspection, I can [hopefully] make my "liveness" and "readiness" probes smarter; and, perhaps debug deadlocks and other kind of thread contention. One type of introspection that I need to be able to do is generate a Java Thread Dump when the conditions of the ColdFusion application need to be reported.

I honestly don't know all that much about Java or the JVM. So, when it comes to generating a Java Thread Dump programmatically in ColdFusion, I am merely porting over this Crunchify article by App Shah. Shah's article generates a Java Thread Dump using Java code; so, I'm - more or less - translating that into ColdFusion code that dips down into the relevant Java functionality.

To encapsulate the complexity of the Java Thread Dump, I've created a simple ColdFusion component that exposes a .getThreadDump() method:

  • component
  • output = false
  • hint = "I help inspect the JVM threads."
  • {
  •  
  • /**
  • * I initialize the JVM Thread Helper.
  • *
  • * @output false
  • */
  • public any function init() {
  •  
  • variables.javaManagementFactory = createObject( "java", "java.lang.management.ManagementFactory" );
  • variables.threadMXBean = javaManagementFactory.getThreadMXBean();
  •  
  • }
  •  
  • // ---
  • // PUBLIC METHODS.
  • // ---
  •  
  • /**
  • * I return a full thread-dump of the current JVM state. This will shed light on what
  • * each thread in the JVM is doing at roughly this moment.
  • *
  • * @maxStackDepth I determine how many stack elements should be reported for each thread.
  • * @output false
  • */
  • public string function getThreadDump( numeric maxStackDepth = 50 ) {
  •  
  • // Gather the thread meta-data for all current JVM threads.
  • // --
  • // CAUTION: Since gathering the thread IDs and gathering the meta-data is a two-
  • // step action, there is a chance that some of the threads (corresponding to the
  • // gathered IDs) will no longer exist at the time the meta-data is gathered. In
  • // such cases, the thread meta-data will be undefined in the resulting array.
  • var allThreadIDs = threadMXBean.getAllThreadIds();
  • var allThreads = threadMXBean.getThreadInfo( allThreadIDs, javaCast( "int", maxStackDepth ) );
  • var allThreadsLength = arrayLen( allThreads );
  •  
  • // Each line of the thread dump is going to be appended to this buffer. This
  • // buffer will then be collapsed down into a single string.
  • var buffer = [];
  • // As an optimization, we can resize the buffer based on the number of threads
  • // we've collected. This way, we're not continually changing the size of the
  • // buffer as we iterate over the thread info.
  • arrayResize( buffer, ( allThreadsLength * ( maxStackDepth + 3 ) ) );
  •  
  • var newline = chr( 10 );
  • var tab = chr( 9 );
  • var i = 0;
  •  
  • // NOTE: In later versions of ColdFusion, undefined array elements are
  • // implicitly skipped in a for-in loop. But, in earlier versions of ColdFusion,
  • // the iteration variable comes back as undefined.
  • for ( var threadInfo in allThreads ) {
  •  
  • // If the given thread had already been terminated by the time the meta-data
  • // was gathered, we need to skip over it.
  • if ( isNull( threadInfo ) ) {
  •  
  • continue;
  •  
  • }
  •  
  • buffer[ ++i ] = """#threadInfo.getThreadName()#""";
  • buffer[ ++i ] = "#tab#java.lang.Thread.State: #threadInfo.getThreadState().toString()#";
  •  
  • for ( var element in threadInfo.getStackTrace() ) {
  •  
  • buffer[ ++i ] = "#tab##tab#at #element.toString()#";
  •  
  • }
  •  
  • // Put a spacer in between each thread.
  • buffer[ ++i ] = "";
  •  
  • }
  •  
  • return( trim( arrayToList( buffer, newline ) ) );
  •  
  • }
  •  
  • }

As you can see, this code uses Java's ThreadMXBean to ask the JVM for information about all of the running threads. It then iterates over the threads and renders their state to an array, which is then collapsed down into a string.

To generate a Java Thread Dump, all we have to do is instantiate the ColdFusion component and invoke the .getThreadDump() method:

  • <cfscript>
  •  
  • jvmThreadHelper = new JvmThreadHelper();
  •  
  • writeOutput( "<pre>" & jvmThreadHelper.getThreadDump() & "</pre>" );
  •  
  • </cfscript>

Running this code provides output that looks like this (truncated):


 
 
 

 
 A Java Thread Dump generated programmatically by ColdFusion. 
 
 
 

I love the fact that ColdFusion is built on top of Java - it provides so much power in the underlying platform. And, hopefully this post helps other ColdFusion engineers see how they can dip down into the Java layer if they need to generate a Java Thread Dump programmatically.



Looking For A New Job?

Ooops, there are no jobs. Post one now for only $29 and own this real estate!

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.