5 posts categorized "jmx"

09/06/2009

Tomcat Management: Jmx4Perl Makes it Easier

For the intermediate level application server administrator like me, "knowing" that I can manage my tomcat containers remotely using jmx is a lot different than actually writing some useful script that utilizes it.  The problem with jmx, in my opinion, is that it's a systems administration technology built into the Java Virtual Machine that is marketed to Developers, not Systems Administrators.  Monitoring and Management is probably the last thing on a developer's mind and sometimes I think that the cost in terms of time learning jmx is too high.  The payoff in portability from one job to another is probably better than it was having to learn Tcl to write BigIP iRules but probably not much higher.  Many sysadmins I've talked to have never heard of it and when they do find out what it is, the need to learn Java first is usually the first barrier that gets thrown up.  When you're supporting hundreds of servers and you use a combination of shell scripts and perl scripts most of the time to manage the entire server and not just the VM, learning Java is one of those things that would be nice to learn but who has the time?

While sifting through the keywords reports in this site's google analytics data over this long holiday weekend, I came across Jmx4Perl and I'm really glad I took the time to look it up.  Previously, I had heard about JMX4R, which required JRuby and a JVM but all that Jmx4Perl requires is Perl.  Installation via 'cpan' is probably the easiest way to do it.  Simply open up a cpan shell and then type "install JMX::Jmx4Perl" and you're all set.  

The edge that Jmx4Perl has over other JMX implementations, in my systems administrator opinion, is the inclusion of j4p, a small (approximately 92K) web application that you deploy to your app server container webapps directory, which proxies jmx requests on your behalf. This is a lot easier to deploy and protect, especially on Windows systems where securing the jmxremote.password file can be incredibly difficult. Jmx4Perl includes 'out-of-the-box' support for many popular open sourced application server containers, including JBoss, Tomcat, Jetty, and GlassFish as well as the two main commercial application server offerings WebLogic and WebSphere.

Once you have copied j4p.war to your application server's deployment directory and deployed the application, you can begin to use it. No additional firewall ports are needed—heck, you don't even need to enable JMX within your tomcat container to use it with the j4p proxy. Just keep in mind that securing it the way you would secure any web application you don't want others to be able to use would make your security guys happy.

To make things even easier, Jmx4Perl contains a list of aliases that allow you to get off and running writing some useful jmx scripts without having to learn the verbose jmx syntax for getting attributes or invoking methods on management beans, which can differ across app server platforms. For example, to get the version number of your app server on JBoss, you would get the attribute VersionNumber of the MBean jboss.system:type=Server, but on Jetty you would get attribute version from MBean org.mortbay:jetty=default. With Jmx4Perl, you simply get_attribute(SERVER_VERSION) and the correct, corresponding MBean and attribute will be utilized for whichever app server you are using. Aliases for most of the common server operations are included within Jmx4Perl but you can also use the native JMX naming syntax as well.

The sample script below provides the number of currently executing threads on my test tomcat container, to give you an idea how easy it is to begin interacting with Jmx4Perl.

#!/usr/bin/env perl 
#===============================================================================
#
#         FILE:  jmx4perl_test.pl
#
#        USAGE:  ./jmx4perl_test.pl  
#
#  DESCRIPTION:  Connects to a local container
#                 and displays current thread counts.
#                Demonstrates Jmx4Perl.
#
#      OPTIONS:  None
# REQUIREMENTS:  JMX::Jmx4Perl
#         BUGS:  Probably
#        NOTES:  ---
#       AUTHOR:  Chris Mahns 
#      COMPANY:  techstacks.com
#      VERSION:  0.1
#      CREATED:  09/06/2009
#     REVISION:  ---
#===============================================================================

use strict;
use warnings;
use feature ':5.10';

use JMX::Jmx4Perl;
use JMX::Jmx4Perl::Alias;

my $jmx = JMX::Jmx4Perl->new(url => "http://localhost:8080/j4p");
my $threads = $jmx->get_attribute(THREAD_COUNT);

say "There are $threads active threads";

Running this script from the command line provides me with the current number of executing threads within my tomcat container, which is almost always asked by development on phone calls during problems. My next batch of Tomcat Management articles will look into Jmx4Perl further because this seems like such a useful module!

Other posts within this series:

  1. Tomcat Management: Setting up the Tomcat Manager Application
  2. Tomcat Management: Use Groovy to Interact with Tomcat Manager
  3. Tomcat Management: Using the JMXProxy
  4. Tomcat Management: Use the JMXProxy to Change Configuration

06/09/2009

Tomcat Management: Use the JMXProxy to Change Configuration

After a short break to cover some interesting news over the past couple weeks and to switch templates in Blogger, this series returns with setting configuration values using the JMXProxy. Also, breaking with tradition in this series using Groovy and HTTPBuilder for the 'getting' script examples, the 'setting' portion of this series will use Ruby with the HTTParty gem. There is a fairly good reason why I'm not using Groovy and HTTPBuilder for this next batch of posts--it doesn't work! However, I do not believe that this is the fault of Groovy, HTTPBuilder, or Tomcat. Blame can solidly be placed on my limited programming skills.

One important thing to keep in mind when setting configuration values with the JMXProxy: It ain't permanent! Like the JMX-Console in JBoss, the JMXProxy allows you to Get or Set configuration details at run-time and if one were to restart tomcat, any changes that were made would be reverted back to values stored in your web.xml, server.xml, or other configuration files. So what good is it? Well, you can set logging levels at run-time to better debug a production issue or you could, in theory, create a run-time configuration that is built dynamically after startup without ever having to modify a configuration file outside of tomcat-users.xml.

The example below provides (hopefully!) a useful example meant to illustrate some basic changes that can be made to tomcat. It prints the current configuration of the http connector, then it enables HTTP compression and raises MaxThreads to 400, then reverts everything back pausing after each step so that you can witness the changes. For simplicity, I've set a basic tomcat manager UID and Password to "tomcat".

#!/usr/bin/env ruby

require 'rubygems'
require 'httparty'

class JMXProxy
 include HTTParty
 format :html
 basic_auth 'tomcat', 'tomcat'
end

puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?qry=Catalina:type=Connector,port=8080')
puts
puts 'Pausing 10 seconds - Changing Settings'
sleep(10)

puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?set=Catalina:type=Connector,port=8080&att=compression&val=on')
puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?set=Catalina:type=Connector,port=8080&att=maxThreads&val=400')
puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?qry=Catalina:type=Connector,port=8080')
puts
puts "Check it out! Resetting changes in 10 seconds..."
sleep(10)

puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?set=Catalina:type=Connector,port=8080&att=compression&val=off')
puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?set=Catalina:type=Connector,port=8080&att=maxThreads&val=40')
puts JMXProxy.get('http://localhost:8080/manager/jmxproxy/?qry=Catalina:type=Connector,port=8080')

05/12/2009

Tomcat Management: Using the JMXProxy

One hidden gem bundled with the Tomcat Manager is the JMXProxy, which allows you to do a whole bunch of cool and frightening things with your tomcat container and running applications. It is enabled by default once the Tomcat Manager is enabled. You'll need more than a browser to interact with it, however, because simply loading http://localhost:8080/manager/jmxproxy dumps everything in regular text, which is useful for getting MBean names.

Below are some groovy scripts that will highlight some of the interesting things you can get from the JMXProxy.

Get Tomcat Thread Pool

#!/usr/bin/env groovy 

package groovyx.net.http
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.TEXT

def http = new HTTPBuilder( 'http://localhost:8080/manager/jmxproxy/?qry=*:type=ThreadPool,name=http-8080' )
http.request( GET,TEXT ) { req ->
http.auth.basic( 'tomcat', 'tomcat' )
headers.'User-Agent' = 'GroovyHTTPBuilderTest/0.4'

response.success = { resp, reader ->
println "-----Response-----"
println System.out << reader
println "\n------------------"
}
response.failure = { resp ->
println "Something bad happened. ${resp.statusLine}"
}
}
The script above will print out some useful stats regarding Thread Pool statistics on the HTTP connector. Output looks something like the following:
-----Response-----
OK - Number of results: 1

Name: Catalina:type=ThreadPool,name=http-8080
modelerType: org.apache.tomcat.util.modeler.BaseModelMBean
maxThreads: 40
backlog: 100
currentThreadsBusy: 1
acceptorThreadCount: 1
threadPriority: 5
paused: false
port: 8080
tcpNoDelay: true
soLinger: -1
soTimeout: 20000
daemon: true
running: true
currentThreadCount: 6
name: http-8080

org.codehaus.groovy.runtime.FlushingStreamWriter@2580b3

------------------
Are you interested in connector-related statistics? Well, the following script will provide all the useful statistics exposed by the HTTP Connector.

Get Tomcat Connector Statistics

#!/usr/bin/env groovy 

package groovyx.net.http
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.TEXT

def http = new HTTPBuilder( 'http://localhost:8080/manager/jmxproxy/?qry=*:type=Connector,port=8080' )
http.request( GET,TEXT ) { req ->
http.auth.basic( 'tomcat', 'tomcat' )
headers.'User-Agent' = 'GroovyHTTPBuilderTest/0.4'

response.success = { resp, reader ->
println "-----Response-----"
println System.out << reader
println "\n------------------"
}
response.failure = { resp ->
println "Something bad happened. ${resp.statusLine}"
}
}
Output will look similar to the following:
-----Response-----
OK - Number of results: 1

Name: Catalina:type=Connector,port=8080
modelerType: org.apache.catalina.mbeans.ConnectorMBean
connectionUploadTimeout: 300000
keepAliveTimeout: -1
protocol: HTTP/1.1
maxThreads: 40
acceptCount: 100
connectionTimeout: 20000
connectionLinger: -1
scheme: http
port: 8080
tcpNoDelay: true
xpoweredBy: false
compression: off
maxHttpHeaderSize: 8192
proxyPort: 0
secure: false
maxPostSize: 2097152
redirectPort: 8443
bufferSize: 2048
emptySessionPath: false
threadPriority: 5
useBodyEncodingForURI: false
protocolHandlerClassName: org.apache.coyote.http11.Http11Protocol
enableLookups: false
allowTrace: false
maxKeepAliveRequests: 100
disableUploadTimeout: true

org.codehaus.groovy.runtime.FlushingStreamWriter@2580b3

------------------

List Running Servlets

#!/usr/bin/env groovy 


package groovyx.net.http
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.TEXT

def http = new HTTPBuilder( 'http://localhost:8080/manager/jmxproxy/?qry=*:j2eeType=Servlet,*' )
http.request( GET,TEXT ) { req ->
http.auth.basic( 'tomcat', 'tomcat' )
headers.'User-Agent' = 'GroovyHTTPBuilderTest/0.4'

response.success = { resp, reader ->
println "-----Response-----"
println System.out << reader
println "\n------------------"
}
response.failure = { resp ->
println "Something bad happened. ${resp.statusLine}"
}
}
There is an awful lot of output for this one so I will not be including the output for this particular script in this article.

Don't assume that interaction with the jmxproxy is all 'getting' and no 'setting'. This article dealt with the cool things you can do with the jmxproxy—the next one will deal with the frightening things.