Jeff Mesnil

jmx4r 0.1.0 Is Released

jmx4r 0.1.0 has just been released (jmx4r is a JRuby library which makes it super easy to write simple Ruby scripts to manage Java applications using JMX).

  • fixed compatibility with Rake 0.8.7 (thanks Dan!)
  • fixed dynamic mbean issues where attributes and methods were added to all the dynamic mbeans in the thread (thanks Munesse!)

There is also two new features:

  • support for Java CamelCase style in addition to Ruby snake_case (thanks again to Dan)
logging = JMX::MBean.find_by_name "java.util.logging:type=Logging"
 
# Ruby syntax works
logging.set_logger_level "global", "FINEST"
# Java syntax works too
logging.setLoggerLevel "global", "FINEST"
  • Connection to a local JVM (thanks to Mr ohtsuka). You can now connect to a JVM running on the same machine without adding the com.sun.management.jmxremote system properties.

For example, start an instance of jconsole without any additional system properties:

$ jconsole &

You can now manage this Java application locally:

require 'rubygems'
require 'jmx4r'
 
# :command is a regexp corresponding to the Java process to connect to
JMX::MBean.establish_connection :command => /JConsole/
memory = JMX::MBean.find_by_name "java.lang:type=Memory"
memory.gc

In addition to the previous :host, :port and :url arguments that you can pass to establish a JMX connection, there is now :command which must be a regular expression corresponding to the local Java process you want to connect to. You can find the name of the process using jps:

$ jps
4255 JConsole
4395 Jps

You can connect to a local Java application running on Java 5 or 6. Is someone interested to contribute support for JDK7 too?

Once again, thanks to all the contributors and users who help make jmx4r even more useful!

As usual, to get this new release, just update the rubygem:

jruby -S gem install jmx4r

and do not hesitate to contribute:

git clone git://github.com/jmesnil/jmx4r.git

jmx4r 0.0.8: “Through the Looking Glass”

jmx4r 0.0.8 has just been released.

Why “Through the Looking Glass”?
Until this version, jmx4r was a library which made it super easy to write simple Ruby scripts to manage Java applications using JMX.

With this version, the perspective has changed, we went through the looking glass and are now on the other side: jmx4r makes it super easy to directly manage Ruby applications by leveraging JRuby and the Java platform.

A 30-line example is worth 10,000 words:

#!/usr/bin/env jruby
require 'rubygems'
require 'jmx4r'
 
# a regular Ruby object we want to manage
class Foo < JMX::DynamicMBean
   operation "a polite management operation"
   parameter :string, "how do you want to be called?"
   returns :string
   def hello(name="world")
      "hello, #{name}!"
   end
 
   operation "double the value"
   parameter :long
   returns :long
   def double(value)
     value * 2
   end
end
 
# Java objects to register the Ruby object in the platform
import java.lang.management.ManagementFactory
import javax.management.ObjectName
 
foo = Foo.new
# each managed object needs an unique 'ObjectName'
object_name = ObjectName.new "foo:type=Foo" 
ManagementFactory.platform_mbean_server.register_mbean foo, object_name
 
# we keep the script running to manage it using jconsole
puts "open jconsole to manage foo registered under 'foo:type=Foo'"
gets
ManagementFactory.platform_mbean_server.unregister_mbean object_name

Save this script and run it using JRuby (tested it with version 1.3.0):

$  jruby bean.rb
open jconsole to manage foo registered under 'foo:type=Foo'

That’s it: you have a Ruby application which can be managed using any Java management console.

For example, if we start jconsole to manage the bean.rb script:

jconsole_connection

In the MBeans tab, we can expand Foo to see the management operation:

jconsole_operation

And we can finally invoke it (e.g. by pushing the hello or double" button) and get a result after the method is called on the Ruby object:

jconsole_result

How to manage a Ruby object

To be manageable from a management console, the Ruby object must inherit from JMX::DynamicMBean

Since Java is statically typed, you also need to give some hints to help Java calls the Ruby object.

Each method you want to expose as a management operation must be annotated with:

  • an operation (and an optional description)
  • a list of parameter (with a mandatory type and optional name and description)
  • a returns type

The returns and parameter type must be one of :boolean, :byte, :int, :long, :float, :double, :list, :map, :set, :string, and :void

For example, if we have a method which prints the name and age of an user, it can be minimally exposed as:

   operation
   parameter :string
   parameter :int
   returns :void
   def display(name, age)
     puts "#{name} is #{age} years old
   end

Exposing Ruby attributes for management is even simpler:

class AttributeTypesMBean < JMX::DynamicMBean
   rw_attribute :my_attr, :string, "a read/write String attribute"
   r_attribute :another_attr, :int, "a readonly int attribute"
 
    ...
  end

the rw_attribute declares a Ruby attribute (using attr_accessor) which is also exposed for management and can be read and write from a management console. Likewise, r_attribute declares a read-only Ruby attribute (using attr_reader) which can only be read from a management console.

DynamicMBean RDoc contains a description of all these annotations.

Finally, the code to register/unregister the Ruby object is taken directly from the Java library using ManagementFactory.platform_mbean_server to access the Java Platform’s MBean Server.
Each managed object must be registered with an unique ObjectName that is created using the javax.management.ObjectName class (the JMX Best Practices is a good start for an overview of JMX, the umbrella name for management in Java).

Most of this code was taken from the jmx module of jruby-extras. I fixed some issues with it but, from now on, the remaining bugs are likely written by me!

jmx4r was a simple and small library to write Ruby scripts to manage Java applications.
It is now also a simple and small library to manage Ruby applications.

With the success of JRuby and the rise of Ruby applications running on Java such as Torquebox, GitHub:fi, etc., I believe it can be very useful to leverage the features provided by the Java platform to manage Ruby applications.

As usual, to get this new release, just update the rubygem:

jruby -S gem install jmx4r

and do not hesitate to contribute:

git clone [git://github.com/jmesnil/jmx4r.git][jmx4r]

jmx4r 0.0.6 is released

jmx4r 0.0.6 has just been released (jmx4r is a JRuby library which makes it super easy to write simple Ruby scripts to manage Java applications using JMX).

This release adds helper methods to make it more natural to work with TabularData attributes and ObjectName properties

Iterate over TabularData attribute

TabularData attributes now behave like regular Ruby Enumerable:

#!/usr/bin/env jruby
require 'rubygems'
require 'jmx4r'
 
runtime = JMX::MBean.find_by_name "java.lang:type=Runtime"
# runtime.system_properties is a TabularData
runtime.system_properties.each do | sysprop | 
  puts "#{sysprop["key"]} = #{sysprop["value"]}"
end

ObjectName properties

ObjectName properties can now be accessed using the [] method:

#!/usr/bin/env jruby
require 'rubygems'
require 'jmx4r'
require 'jconsole'
 
mem_pools = JMX::MBean.find_all_by_name "java.lang:type=MemoryPool,*"
mem_pools.each do |pool|
  # print the 'name' property of the pool's ObjectName
  puts pool.object_name["name"]
end

As usual, to get this new release, just update the rubygem:

jruby -S gem install jmx4r

and do not hesitate to contribute:

git clone git://github.com/jmesnil/jmx4r.git

Monitoring Weblogic 9.2 with JMX and JRuby

From Tim Koopmans:

After getting nowhere with lack luster HP support, I turned to the power of the Open Source community and got a very simple script up and running to remotely monitor Weblogic JVM Performance and JMS queues using JMX and JRuby.

[...]

This script will enumerate JVM performance and also JMS queue depths in around 50 lines of code

That’s a good example of the conciseness that JRuby brings to the Java platform: in 50 lines of code, Tim connects to a remote Weblogic MBean server, retrieves attributes about memory usage and JMS queue and stores them in a CSV file.

jmx4r 0.0.5 is released with support for custom JMX URL

jmx4r 0.0.5 has just been released (jmx4r is a JRuby library which makes it super easy to write simple Ruby scripts to manage Java applications using JMX).

There is only one enhancement to this release but it is an important one: you can now specify a custom JMX URL to connect to a MBean Server.

Before this release, the URL was hard-wired to connect using the JMX URL defined by Sun service:jmx:rmi:///jndi/rmi://#{host}:#{port}/jmxrmi.

This means it was not possible to use jmx4r to connect to a MBean server which used another URL or another connector that RMI/JRMP.

With this release, you can now fully specify the url:

    url = "service:jmx:rmi:///jndi/iiop://node1:7001/weblogic.management.mbeanservers.runtime"
    JMX::MBean.establish_connection :url => url

As an example, the code above can be used to connect to a Weblogic server using RMI/IIOP.

When the :url argument is used, :hostand :port arguments are ignored. If you’re connecting to a Sun JRE, it is still simpler to specify only :host & :port though.

This enhancement was proposed by Tim Koopmans. Thanks Tim!

As usual, to get this new release, just update the rubygem:

jruby -S gem install jmx4r

jmx4r 0.0.4 is released

jmx4r 0.0.4 has just been released.
jmx4r is a JRuby library which makes it super easy to write simple Ruby scripts to manage Java applications using JMX.

To get this new release, just update the rubygem: jruby -S gem install jmx4r

All contributions to this new release were done by Skaar:

  • CompositeData behave like regular read-only Ruby Hash
  • custom classes can be loaded by `require` statements
  • custom JMX credentials are supported

(more…)

Tomcat management using jmx4r

Something which is not obvious with the way jmx4r leverages JMX API and Ruby metaprogramming is that you can write simple scripts to manage a Java application without any dependency on the MBeans exposed by the application.

For simplicity, in my examples I always use MBeans exposed by the JVM but jmx4r works with any MBean even if its interface is unknown from the JVM running the management scripts.

Here is a simple example to manage Tomcat using jmx4r.

Let’s assume that we have Tomcat running locally and manageable remotely on port 3000 (without authentication):

$ export CATALINA_OPTS="-Dcom.sun.management.jmxremote \
    -Dcom.sun.management.jmxremote.port=3000 \
    -Dcom.sun.management.jmxremote.ssl=false \
    -Dcom.sun.management.jmxremote.authenticate=false"
$ ./bin/catalina.sh/run

We want to know among all the Web Modules running in Tomcat which ones are privileged and which ones are not. The whole script to do so is:

# tomcat_modules.rb
require "rubygems"
require "jmx4r"

JMX::MBean.establish_connection :host => "localhost", :port => 3000

web_modules = JMX::MBean.find_all_by_name "Catalina:j2eeType=WebModule,*"
privileged, unprivileged = web_modules.partition { |m| m.privileged }

puts "Privileged:\n"     + privileged.map   {|m| m.path }.join("\n  ")
puts "Unprivileged:\n  " + unprivileged.map {|m| m.path }.join("\n  ")

Executing this script gives:

$ jruby tomcat_modules.rb 
Privileged:
  /balancer
  /manager
  /host-manager
Unprivileged:
  /tomcat-docs
  /servlets-examples
  /jsp-examples

  /webdav

That’s were using JRuby shines: it combines the simplicity of using directly the MBeans exposed by a Java application without having to bother with classes dependency.

Using Java to write a corresponding script means choosing your “poison”:

  • No class dependency but tedious (and unnatural) use of MBeanServerConnection methods to interact with Tomcat MBeans
  • Use directly Tomcat MBeans (thanks to MBeanServerInvocationHandler) but you must take care having all their interfaces (and dependencies) in the class path of the JVM running the script

I can not thank enough both the JMX and JRuby guys which make it so simple to get the best of both worlds in jmx4r:

  • simple to use directly the MBeans API
  • simple to deploy without class dependency issues

jmx4r 0.0.3, documentation and multiple connections

jmx4r 0.0.3 has just been released.
jmx4r is a JRuby library which makes it super easy to write simple Ruby scripts to manage Java applications using JMX.

Two new features in this release:

  1. some much-needed documentation
  2. as requested by Brian McCallister, I’ve modified the code so that it is now possible to write a script to manage many Java applications at the same time.

For example, the script to trigger a garbage collection on a cluster of Java applications at the same time (quite a bad idea but a simple one):

port = 1090
hosts = ["node1", "node2", "node3", "node4"]
hosts.each do |h|
    memory = JMX::MBean.find_by_name "java.lang:type=Memory", :host => h, :port => port
    memory.gc
end

Quite simple, isn’t it?

(more…)

Gem for jmx4r + authentication

jmx4r is a library for JRuby to make it super easy to write Ruby scripts to manage remote Java applications through JMX.

Thanks to RubyForge, installing jmx4r is now as simple as typing

jruby -S gem install jmx4r

and its use is straightforward

#!/usr/bin/env jruby
require 'rubygems'
require 'jmx4r'

# optional since by default, jmx4r tries to connect to 
# a JMX Server on localhost which listens to port 3000
JMX::MBean.establish_connection :host => "localhost", :port => 3000

memory = JMX::MBean.find_by_name "java.lang:type=Memory"
# trigger a Garbage Collection
memory.gc

Since my previous post on jmx4r, I’ve added unit tests and some examples to highlight its features. It still needs to be properly documented though…

However, one new feature is worth mentioning: jmx4r now supports connection authentication

JMX::MBean.establish_connection :host => "localhost",
    :username => "jeff", :password => "secret"

If you’re using it, I’m very interested to now what you think about it.
And if you encounter any problem, do not hesitate to submit a bug.

jmx4r, a JMX Libary for JRuby

Just in time for the release of JRuby 1.0 and following my experiments with writing JRuby scripts to manage remote applications using JMX (part I & II), I created jmx4r, a simple library which makes it super easy to write such scripts.

For example, to trigger a Garbage Collection on a remote Java application , the whole script is:

require 'java'
require 'jmx4r'

memory = JMX::MBean.find_by_name "java.lang:type=Memory"
memory.verbose = true
memory.gc

Simple enough, isn’t it?

(more…)