/cloudwatch-tomcat-valve

Java Tomcat Valve project to push Amazon CloudWatch metrics

Primary LanguageJavaApache License 2.0Apache-2.0

Cloud Watch Tomcat Valve


Introduction

A Tomcat Valve that aggregates statistics from the Tomcat Request and Response and [periodically](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html#scheduleAtFixedRate%28java.lang.Runnable, long, long, java.util.concurrent.TimeUnit%29) pushes the statistics to Amazon CloudWatch.

Currently, the only statistic that is captured is ElapsedTime, which is the time taken to process the request in milliseconds. This value is aggregated and pushed out to CloudWatch with the following dimensions:

  • InstanceId (retrieved from metadata)
  • AutoScalingGroupName (retrieved from the instance tag aws:autoscaling:groupName which is automatically added to instances created by Auto Scaling). If the AutoScalingGroupName cannot be found (because the instance is not auto scaled) a warning is reported and the AutoScalingGroupName dimension will not be used for pushing metrics.

This Valve may be used at the Engine, Host or Context level as required. Normally, this Valve would be used at the Host level.

Attributes

Attribute Description
className Java class name of the implementation to use. This MUST be set to org.web.online.cloudwatch.tomcat.valve.CloudWatchValve
namespace The namespace to use when pushing data to CloudWatch. If not specified, the default is CloudWatchValve
initialDelay Integer value indicating the initial delay in timeUnit before the first periodic push of data to CloudWatch. It is an error if this value is calculated to be less than 1 minute. If not specified, the default of 1 is used.
period Integer value indicating the period in timeUnit between successive pushes of data to CloudWatch. It is an error if this value is calculated to be less than 1 minute. If not specified, the default of 1 is used.
timeUnit One of DAYS, HOURS, MICROSECONDS, MILLISECONDS, MINUTES, NANOSECONDS, or SECONDS. If not specified, the default of MINUTES is used.

Example

<Valve className="org.web.online.cloudwatch.tomcat.valve.CloudWatchValve" />

Build

Maven is used to build and the Apache Maven Shade Plugin is used to create a single jar -with-dependencies that includes the necessary AWS JDK and dependency libraries to run.

mvn clean package

Install

To install, the appropriate jar from the target folder should be placed in the $CATALINA_HOME/lib directory. If the -with-dependencies jar is used no other jars should be necessary. If the standalone jar is used then the relavant dependent jars will also need to be installed.

Once the jar(s) are installed, the server.xml file should be edited as in the Example above, optionally including any of the attributes to customize the behavior.

Credentials

This implementation makes use of the AWS SDK for Java to look up the AutoScalingGroupName and to push metrics to CloudWatch. The DefaultAWSCredentialsProviderChain is used for authentication which looks for credentials in this order:

  • Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_KEY
  • Java System Properties - aws.accessKeyId and aws.secretKey
  • Credential profiles file at the default location (~/.aws/credentials) shared by all AWS SDKs and the AWS CLI
  • Instance profile credentials delivered through the Amazon EC2 metadata service (more info)
Actions

The credentials used for authentication must be able to perform the following actions:

  • ec2:DescribeTags
  • cloudwatch:PutMetricData

Logging

Logging is dependent on the tomcat configuration, but here is an example of a logging configuration for the default JULI logger as configured by the $CATALINA_HOME/conf/logging.properties file:

# this will enable periodic entries from the valve when data is pushed to CloudWatch
org.web.online.cloudwatch.tomcat.valve.level = FINE
org.web.online.cloudwatch.tomcat.valve.handlers = 1catalina.org.apache.juli.FileHandler

# this will enable DEBUG logging from the AWS SDK libraries
com.amazonaws.level = FINE
com.amazonaws.handlers = 1catalina.org.apache.juli.FileHandler

# this will enable logging of the raw HTTP request and responses
# use with caution!
org.apache.http.wire.level = FINE
org.apache.http.wire.handlers = 1catalina.org.apache.juli.FileHandler

It's not working

Here are some reasons things might not be working and suggestions for figuring out what's wrong:

  • Recieved error "Unable to load AWS credentials from any provider in the chain"
    • See Credentials about how the DefaultAWSCredentialsProviderChain works
  • Entry in logs says "ElapsedTimeAggregator ... scheduled to run" but no other output
    • Try enabling more verbose logging. See Logging
  • Entry in logs says "not authorized to perform: cloudwatch:PutMetricData" after enabling DEBUG logging on the AWS SDK libraries
    • The credentials being used are not authorized to push metrics to CloudWatch. See Actions