#! /usr/bin/env ruby # # metrics-http-json.rb # # DESCRIPTION: # Hits an HTTP endpoint which emits JSON and pushes data into Graphite. # # OUTPUT: # Graphite formatted data # # PLATFORMS: # Linux # # DEPENDENCIES: # gem: sensu-plugin # gem: rest-client # # USAGE: # ./metrics-http-json.rb -u 'https://user:password@127.0.0.1:443 # # ./metrics-http-json.rb -u 'http://127.0.0.1:8080/jolokia/read/com\ # .mchange.v2.c3p0:name=datasource,type=PooledDataSource' -s hostname.c3p0\ # -m 'Connections::numConnections,BusyConnections::numBusyConnections'\ # -o 'value' # # NOTES: # The metric option is a comma separated list of the metric (how it will # appear in Graphite) and the JSON key which holds the value you want to # graph. The object option is optional and is the name of the JSON object # which holds the key/value pairs you want to graph. # # LICENSE: # phamby@gmail.com # Released under the same terms as Sensu (the MIT license); see LICENSE # for details. # require 'sensu-plugin/metric/cli' require 'rest-client' require 'socket' require 'json' require 'uri' # # HttpJsonGraphite - see description above # class HttpJsonGraphite < Sensu::Plugin::Metric::CLI::Graphite option :url, description: 'Full URL to the endpoint', short: '-u URL', long: '--url URL', default: 'http://localhost:8080' option :scheme, description: 'Metric naming scheme', short: '-s SCHEME', long: '--scheme SCHEME', default: Socket.gethostname.to_s option :metric, description: 'Optional Metric/JSON key pair ex:Connections::numConnections', short: '-m METRIC::JSONKEY', long: '--metric METRIC::JSONKEY', default: nil option :headers, description: 'Additional HTTP request headers to send. Example: Authorization:XYZ,User-Agent:ABC', short: '-H HEADER1:val,HEADER2:val', long: '--headers HEADER1:val,HEADER2:val' option :object, description: 'The JSON object containing the data', short: '-o OBJECT', long: '--object OBJECT' option :insecure, description: 'By default, every SSL connection made is verified to be secure. This option allows you to disable the verification', short: '-k', long: '--insecure', boolean: true, default: false option :debug, short: '-d', long: '--debug', default: false def deep_value(hash, scheme = '') hash.each do |key, value| if value.is_a?(Hash) deep_value(value, "#{scheme}.#{key}") else output "#{scheme}.#{key}", value end end end def run puts "args config: #{config}" if config[:debug] scheme = config[:scheme].to_s metric_pair_input = config[:metric].to_s if config[:object] object = config[:object].to_s end header_dict = {} if config[:headers] config[:headers].split(',').each do |header| h, v = header.split(':', 2) header_dict[h] = v.strip end end # TODO: figure out what to do here url = URI.encode(config[:url].to_s) # rubocop:disable Lint/UriEscapeUnescape begin r = RestClient::Request.execute( url: url, method: :get, verify_ssl: !config[:insecure], headers: header_dict ) puts "Http response: #{r}" if config[:debug] if config[:metric].nil? deep_value(::JSON.parse(r), scheme) else metric_pair_array = metric_pair_input.split(/,/) metric_pair_array.each do |m| metric, attribute = m.to_s.split(/::/) puts "metric: #{metric}, attribute: #{attribute}" if config[:debug] unless object.nil? ::JSON.parse(r)[object].each do |k, v| if k == attribute output([scheme, metric].join('.'), v) end end end ::JSON.parse(r).each do |k, v| if k == attribute output([scheme, metric].join('.'), v) end end end end rescue Errno::ECONNREFUSED critical "#{config[:url]} is not responding" rescue RestClient::RequestTimeout critical "#{config[:url]} Connection timed out" end ok end end