Thursday, 10 March 2016

Custom CloudWatch Tomcat JVM Metrics

If you use tomcat as your usual Servlet container for your Java web applications on EC2 then you may wish to monitor Java Virtual Machine stats and apply notification alarms which can be triggered should the application run into trouble. There are many JVM monitoring tools out there which range from free to expensive, simple to complex. I decided to try and create a simple and free solution using CloudWatch and the AWS Command Line Interface, (AWS CLI), to send JVM stats to CloudWatch as custom metrics. Once the custom metrics have been configured CloudWatch does the rest and provides a monitoring platform on which alarms and notifications can be easily created and managed.

To set this up you will need to do the following:

  • Have an AWS account
  • Set up a IAM Role to be applied to a running instance which you want to monitor
  • Start EC2 instance hosting Tomcat which has outbound access to the internet
  • Download the AWS CLI package
  • Create a script to extract the JVM stats and publish to CloudWatch using the CLI
  • Set execution of the script in cron to publish the metrics at your desired frequency

Assuming you already have an AWS account and know your way around, create an IAM role which will be assigned to the EC2 instance you want to monitor. This should allow applications on the instance to manage metric data

Next, ensure you have a VPC with a subnet allowing access to the outside internet. You will need a subnet which assigns a public IP to launched instances, an internet gateway and a route table which directs all outbound traffic from instances within the subet to that gateway - 0.0.0.0/0 - igw-my-gateway-id.

Launch an instance into the subnet as usual and assign the new IAM role. If you already have a base image containing a tomcat installation then use that. Otherwise, install tomcat as you wish. I won't cover this in this post. Once running open a session and install the AWS CLI package.


You can confirm the installation is good by running aws help which will show the manual. Now create a script to get the JVM stats from your running tomcat instance and use the CLI to send to CloudWatch. You may well want to run this on multiple instances so it makes sense to ascertain the instance id at runtime and use this when you define the metric name in the CLI command. To discover the instance id you'll need to make an HTTP request and interrogate the meta data, assign this to a variable in your script which will be used in the CLI command later.


Locate the catalina PID file which contains the process ID of your running Tomcat instance. Depending on your version and installation this can be in various places. The PID file contains the id of the running Tomcat process. There are various other ways you could ascertain this using the jps or ps commands.


Use the jstat command to print a snapshot of the JVM memory performance statistics. These are pretty printed so there has to be a bit of String manipulation to pick them out. Use the AWS CLI command to invoke the CloudWatch service which makes a PUT request with the substituted data. In the example below I've created a metric name for each jstat value from this EC2 instance, identified by the instance id. Here's the full script -


It's then a simple case of adding this script to a cron schedule. You'll then be able to login to the AWS console, navigate to CloudWatch and select the metrics. From here, you can easily create the alarms and notifications for different threshold values of the metric data.