bin/metrics-libcurl.rb
#!/usr/bin/env ruby
# frozen_string_literal: false
#
# metrics-libcurl
#
# DESCRIPTION:
# Simple wrapper around libcurl for getting timing stats from the various phases
# of connecting to an HTTP/HTTPS server.
#
# OUTPUT:
# metric data
#
# PLATFORMS:
# Linux
#
# DEPENDENCIES:
# gem: sensu-plugin
# gem: typhoeus
#
# USAGE:
# #YELLOW
#
# NOTES:
# Based on: metrics-curl.rb
# by Joe Miller.
#
# LICENSE:
# Copyright 2019 Jef Spaleta
# Released under the same terms as Sensu (the MIT license); see LICENSE
# for details.
#
require 'socket'
require 'English'
require 'sensu-plugin/metric/cli'
require 'typhoeus'
require 'json'
#
# Libcurl Metrics
#
class LibcurlMetrics < Sensu::Plugin::Metric::CLI::Graphite
option :url,
short: '-u URL',
long: '--url URL',
description: 'valid cUrl url to connect (default: http://127.0.0.1:80/)',
default: 'http://127.0.0.1:80/'
option :scheme,
description: 'Metric naming scheme, text to prepend to metric',
short: '-s SCHEME',
long: '--scheme SCHEME',
default: "#{Socket.gethostname}.curl_timings"
option :debug,
description: 'Include debug output, should not use in production.',
short: '-d',
long: '--debug',
default: false
option :libcurl_options,
description: 'Libcurl Options as a key/value JSON string',
short: '-o JSON',
long: '--options JSON',
default: '{}'
option :http_headers,
description: 'HTTP Request Headers as key/value JSON string',
short: '-H JSON',
long: '--headers JSON',
default: '{}'
option :http_params,
description: 'HTTP Request Parameters as key/value JSON string',
short: '-P JSON',
long: '--params JSON',
default: '{}'
option :http_response_error,
description: 'return critical status (2) if http response error status encountered (>= 400)',
short: '-c',
long: '--critical_http_error',
default: false
option :http_redirect_warning,
description: 'return warning status (1) if http response redirect status encountered (3xx)',
short: '-w',
long: '--warn_redirect',
default: false
option :help,
short: '-h',
long: '--help',
description: 'Show this message',
on: :tail,
boolean: true,
show_options: true
def usage_details
<<~USAGE
Detailed Info:
This wrapper makes use of libcurl directly instead of the curl executable by way of the Typhoeus RubyGem.
You can provide additional libcurl options via the commandline using the --options argument.
Options Examples:
Follow Redirects: --options '{\"followlocation\": true}'
Use Proxy: --options '{proxy: \"http://proxyurl.com\", proxyuserpwd: \"user:password\"}'
Disable TLS Verification: '{\"ssl_verifypeer\": false}'
References:
Typhoeus Docs: https://www.rubydoc.info/gems/typhoeus/1.3.1
Libcurl Options: https://curl.haxx.se/libcurl/c/curl_easy_setopt.html
USAGE
end
def run
if config[:help]
puts usage_details
ok
end
puts "[DEBUG] args config: #{config}" if config[:debug]
begin
headers = ::JSON.parse(config[:http_headers])
rescue ::JSON::ParserError
critical "Error parsing http_headers JSON\n"
end
begin
params = ::JSON.parse(config[:http_params])
rescue ::JSON::ParserError
critical "Error parsing http_params JSON\n"
end
begin
hash = ::JSON.parse(config[:libcurl_options])
rescue ::JSON::ParserError
critical "Error parsing libcurl_options JSON\n"
end
begin
opts = Hash[hash.map { |k, v| [k.to_sym, v] }]
opts[:headers] = headers unless headers.empty?
opts[:params] = params unless params.empty?
request = Typhoeus::Request.new(config[:url], opts)
if config[:debug]
puts "[DEBUG] Request Options: #{request.options}"
puts "[DEBUG] Request Base Url: #{request.base_url}"
puts "[DEBUG] Request Full Url: #{request.url}"
end
response = request.run
Typhoeus.get(config[:url], followlocation: true)
if config[:debug]
puts "[DEBUG] Response HTTP Code: #{response.response_code}"
puts "[DEBUG] Response Return Code: #{response.return_code}"
end
rescue TyphoeusError
critical "Something went wrong\n Request Options: #{request.options}\n Request Base Url: #{request.base_url}\n Request Full Url: #{request.url}"
end
output "#{config[:scheme]}.time_total", response.total_time
output "#{config[:scheme]}.time_namelookup", response.namelookup_time
output "#{config[:scheme]}.time_connect", response.connect_time
output "#{config[:scheme]}.time_pretransfer", response.pretransfer_time
output "#{config[:scheme]}.time_redirect", response.redirect_time
output "#{config[:scheme]}.time_starttransfer", response.starttransfer_time
output "#{config[:scheme]}.http_code", response.response_code
if response.response_code == 0
critical
end
critical if config[:http_response_error] && response.response_code >= 400
warning if config[:http_redirect_warning] && response.response_code.between?(300, 399)
ok
end
end