zsprackett/cloudwatchtographite

View on GitHub
bin/cloudwatch_to_graphite

Summary

Maintainability
Test Coverage
#!/usr/bin/env ruby
# _*_ coding: utf-8 _*_
# frozen_string_literal: true
#
# == Synopsis
# CloudwatchToGraphite retrieves metrics from the Amazon CloudWatch APIs
# and passes them on to a graphite server
#
# == Author
# S. Zachariah Sprackett <zac@sprackett.com>
#
# == License
# The MIT License (MIT)
#
# == Copyright
# Copyright (C) 2013 - S. Zachariah Sprackett <zac@sprackett.com>
#

require 'optparse'
require 'pp'
require 'log4r'

logger = Log4r::Logger.new('cloudwatchtographite')
logger.level = Log4r::ERROR
f = Log4r::Outputter.stderr
f.formatter = Log4r::PatternFormatter.new(pattern: '[%d] %C: %m')
logger.outputters = f

begin
  require 'cloudwatchtographite'
rescue LoadError
  dev_path = File.join(File.dirname(__FILE__), '..', 'lib')
  $LOAD_PATH.unshift(dev_path)
  require 'cloudwatchtographite'
end

# default options
options = {
  protocol: 'udp',
  region: ENV.key?('AWS_DEFAULT_REGION') ?
    ENV['AWS_DEFAULT_REGION'] : 'us-east-1',
  access_key: ENV['AWS_ACCESS_KEY_ID'],
  secret_key: ENV['AWS_SECRET_ACCESS_KEY'],
  graphite_server: 'localhost',
  graphite_port: 2003,
  carbon_prefix: 'cloudwatch'
}
opt_parser = OptionParser.new do |opt|
  opt.banner = 'Usage: %s [OPTIONS]' % File.basename($PROGRAM_NAME)
  opt.separator ''
  opt.on('-a', '--access-key=KEY', "AWS Access Key (Falls back to ENV['AWS_ACCESS_KEY_ID'])") do |key|
    options[:access_key] = key
  end
  opt.on('-s', '--secret-key=KEY', "AWS Secret Access Key (Falls back to ENV['AWS_SECRET_ACCESS_KEY'])") do |key|
    options[:secret_key] = key
  end
  opt.on('-j', '--json-metrics=FILE', 'Path to JSON metrics file') do |file|
    options[:json_metrics] = file
  end
  opt.on('-y', '--yaml-metrics=FILE', 'Path to YAML metrics file') do |file|
    options[:yaml_metrics] = file
  end
  opt.on('-p', '--protocol=udp', "TCP or UDP (Default: #{options[:protocol]})") do |protocol|
    options[:protocol] = protocol
  end
  opt.on('-r', '--region=us-east-1', "AWS Region (Default: #{options[:region]})") do |region|
    options[:region] = region
  end
  opt.on('-g', '--graphite-server=host', "Graphite Server (Default: #{options[:graphite_server]})") do |server|
    options[:graphite_server] = server
  end
  opt.on('-P', '--graphite-port=port', Integer, "Graphite Port (Default: #{options[:graphite_port]})") do |port|
    options[:graphite_port] = port
  end
  opt.on('-c', '--carbon-prefix=prefix', "Carbon Prefix (Default: #{options[:carbon_prefix]})") do |prefix|
    options[:carbon_prefix] = prefix
  end
  opt.on('-l', '--logfile=prefix', 'Log file (Default: stderr)') do |logfile|
    f = Log4r::FileOutputter.new(
      'logfile',
      filename: logfile,
      trunc: false
    )
    f.formatter = Log4r::PatternFormatter.new(pattern: '[%l] %d %C: %m')
    logger.outputters = f
  end
  opt.on('-v', '--verbose', 'Increase verbosity') do
    logger.level = Log4r::DEBUG
  end
  opt.on('-V', '--version', 'Print version and exit') do
    puts File.basename($PROGRAM_NAME) + ' ' + CloudwatchToGraphite::VERSION::STRING
    exit 0
  end
  opt.on('-h', '--help', 'help') do
    puts opt_parser
    exit 1
  end
end
begin
  opt_parser.parse!
  mandatory = [:access_key, :secret_key]
  missing = mandatory.select { |param| options[param].nil? }
  unless missing.empty?
    puts "Missing options: #{missing.join(', ')}"
    puts opt_parser
    exit 1
  end
  if options[:json_metrics].nil? && options[:yaml_metrics].nil?
    puts 'No metric file specified.'
    puts opt_parser
    exit 1
  elsif !options[:json_metrics].nil? && !options[:yaml_metrics].nil?
    puts 'Only one metric file should be specified.'
    puts opt_parser
    exit 1
  end
rescue OptionParser::InvalidOption => e
  puts "Error: #{e}"
  puts
  puts opt_parser
  exit 1
end

metrics = nil
begin
  if !options[:json_metrics].nil?
    logger.debug('Parsing JSON metrics')
    metrics = CloudwatchToGraphite::LoadMetrics.from_json_file(options[:json_metrics])
  else
    logger.debug('Parsing YAML metrics')
    metrics = CloudwatchToGraphite::LoadMetrics.from_yaml_file(options[:yaml_metrics])
  end
rescue CloudwatchToGraphite::ParseError
  logger.fatal('Failed to parse option file')
  exit 1
end

if metrics.empty?
  logger.fatal('Exiting due to lack of metric definitions')
  exit 1
end

logger.debug('Initializing CloudwatchToGraphite::Base')
cwtg = CloudwatchToGraphite::Base.new(
  options[:access_key],
  options[:secret_key],
  options[:region]
)

cwtg.carbon_prefix = options[:carbon_prefix]
cwtg.protocol = options[:protocol]
cwtg.graphite_server = options[:graphite_server]
cwtg.graphite_port = options[:graphite_port]

logger.debug('Fetching and forwarding metrics')
if cwtg.fetch_and_forward(metrics)
  logger.info('Exiting Success')
  exit 0
else
  logger.info('Exiting Failure')
  exit 1
end