engineyard-visualvm
engineyard-visualvm
is a command-line utility for use with JRuby and
Engine Yard Cloud that makes it easy to connect Visual VM on a desktop
to a running JRuby or Java process in EY Cloud.
Usage
To start Visual VM on your local machine to an already-running process:
# Connect by EY Cloud environment and account
$ ey-visualvm start --environment=jruby --account=example
(If you need to see a list of available environments and their
associated accounts, use the ey environments
command from the
engineyard gem.)
You can also use the engineyard-visualvm
gem to connect Visual VM to
any host where you have an available ssh connection.
# Connect by hostname:
$ ey-visualvm start --host=deploy@example.com
To connect to a server, the server must be booted with some additional JVM arguments. These can be generated on the server side with:
$ ey-visualvm jvmargs
-Dorg.jruby.ext.jmx.agent.port=5900 -javaagent:/path/to/engineyard-visualvm/agent.jar
The server JVM binds to the loopback interface and listens on port
5900 by default. If you want to use a different interface and/or port
than the default, pass --host=<host-or-ip>
or --port=<port>
to
ey-visualvm jvmargs
.
Acceptance Test
To verify that a JMX connection to a server can be established, we can
use Vagrant and Chef to bootstrap a VM, start a JRuby process with JMX
enabled, create an ssh tunnel to the Vagrant box, and use the jmx
gem to connect to it from Ruby code. The code for this looks like
this:
require 'childprocess'
require 'jmx'
sh "vagrant ssh_config > ssh_config.tmp"
sh "vagrant up"
at_exit { sh "vagrant halt"; rm_f "ssh_config.tmp" }
@host, @port = 'localhost', 5900
ssh = ChildProcess.build("ssh", "-NL", "#{@port}:#{@host}:#{@port}", "-F", "ssh_config.tmp", "default")
ssh.start
at_exit { ssh.stop }
require 'engineyard-visualvm'
include EngineYard::VisualVM::Helpers
server = JMX::MBeanServer.new jmx_service_url
runtime_config_name = server.query_names('org.jruby:type=Runtime,name=*,service=Config').to_a.first
puts "Found runtime #{runtime_config_name}"
runtime_config = server[runtime_config_name]
puts "Runtime version: #{runtime_config['VersionString']}"
puts "OK"
To try it yourself, do the following:
# Ensure you have vagrant and jmx installed
$ bundle install
# Run the acceptance test
$ rake acceptance
vagrant ssh_config > ssh_config.tmp
vagrant up
# ... bunch of output as the VM boots and Chef runs...
[default] [Tue, 22 Nov 2011 19:52:41 -0800] INFO: execute[start server] ran successfully
[Tue, 22 Nov 2011 19:52:41 -0800] INFO: Chef Run complete in 35.157236 seconds
[Tue, 22 Nov 2011 19:52:41 -0800] INFO: Running report handlers
[Tue, 22 Nov 2011 19:52:41 -0800] INFO: Report handlers complete
: stdout
Found runtime org.jruby:type=Runtime,name=25292276,service=Config
Runtime version: jruby 1.6.5 (ruby-1.8.7-p330) (2011-10-25 9dcd388) (Java HotSpot(TM) Client VM 1.6.0_26) [linux-i386-java]
OK
vagrant halt
[default] Attempting graceful shutdown of linux...
rm -f ssh_config.tmp
Bits and Pieces
- Gem:
gem install engineyard-visualvm
- Source: https://github.com/engineyard/engineyard-visualvm
- License: MIT; see LICENSE.txt for details.
TODO
- Prompt for a JVM to connect to if more than one JVM process is running on the server
- Prompt for an instance to connect to if the environment has multiple instances
- Data collected by
jstatd
is not yet supported, so things like the Visual GC tab are not supported yet. - Additional utilities to make use of the JMX connection remotely