Created
August 27, 2012 03:19
-
-
Save oogali/3485260 to your computer and use it in GitHub Desktop.
broom sweep (ping collector)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env ruby | |
| require 'rubygems' | |
| require 'redis/connection/hiredis' | |
| require 'redis' | |
| require 'json' | |
| require 'socket' | |
| require 'getoptlong' | |
| require 'uri' | |
| require 'logger' | |
| require 'daemons' | |
| def usage | |
| puts "Usage: #{__FILE__} [-dhr]" | |
| puts 'Collect ICMP echo replies for historical data' | |
| puts 'Example: sweep' | |
| puts | |
| puts 'Configuration settings:' | |
| puts " -r, --redis=URI\t\tconnect to Redis instance, in URI format (e.g. redis://127.0.0.1:6379)" | |
| puts " -h, --hostname=HOSTNAME\toverride system hostname using specified argument" | |
| puts " -d, --debug\t\t\tenable logging of debug messages" | |
| puts | |
| exit 1 | |
| end | |
| hostname = nil | |
| redis_uri = nil | |
| logfile = STDOUT | |
| logging_level = Logger::INFO | |
| # parse command line arguments | |
| options = GetoptLong.new( | |
| [ '--help', '-?', GetoptLong::NO_ARGUMENT ], | |
| [ '--debug', '-d', GetoptLong::NO_ARGUMENT ], | |
| [ '--hostname', '-h', GetoptLong::REQUIRED_ARGUMENT ], | |
| [ '--log', '-l', GetoptLong::REQUIRED_ARGUMENT ], | |
| [ '--redis', '-r', GetoptLong::REQUIRED_ARGUMENT ] | |
| ) | |
| options.each do |opt, arg| | |
| case opt | |
| when '--debug' | |
| logging_level = Logger::DEBUG | |
| when '--hostname' | |
| hostname = arg | |
| when '--log' | |
| logfile = arg | |
| when '--redis' | |
| redis_uri = URI.parse arg | |
| else | |
| usage | |
| end | |
| end | |
| # open logger | |
| logger = Logger.new logfile | |
| logger.level = Logger::INFO | |
| logger.info 'Starting...' | |
| hostname ||= Socket.gethostname | |
| uri ||= URI.parse(ENV['REDIS_URL'] || 'redis://127.0.0.1:6379') | |
| redis = nil | |
| # connect to redis datastore | |
| attempts = 0 | |
| begin | |
| logger.info "Connecting to Redis (#{uri.to_s})" | |
| redis = Redis.new( | |
| :host => uri.host, | |
| :port => uri.port || 6379, | |
| :password => uri.password, | |
| :db => uri.path | |
| ) | |
| rescue => err | |
| attempts += 1 | |
| logger.err "Could not connect to Redis @ #{uri.to_s}: #{err.to_s}" | |
| if attempts % 5 | |
| logger.warn 'Sleeping for 300 seconds before next Redis connection attempt' | |
| sleep 300 | |
| end | |
| logger.warn "Retrying connection to Redis, attempt ##{attempts}" | |
| retry | |
| end | |
| logger.info "Connected to Redis (#{redis.inspect.to_s})" | |
| # create default configuration hash | |
| config = { | |
| :targets => %w[ 127.0.0.1 ], | |
| :count => 5, | |
| :interval => 900, | |
| :splay => 60 | |
| } | |
| # background this app | |
| Daemons.daemonize | |
| loop do | |
| # store timestamp of last config grab | |
| redis.hset 'broom::sweep/checkin', 'hostname}', Time.now.to_i | |
| # get current configuration for this host | |
| logger.info 'Refreshing configuration from store...' | |
| config.merge! JSON.parse(redis.hget('broom::config', hostname)) rescue {} | |
| config[:targets].each do |target| | |
| logger.debug "Getting latency for #{target}" | |
| capture = Time.now.to_i | |
| # ping target, collect replies, store info in a hash | |
| ping = %x[ping -c #{config[:count].to_i} #{target}] | |
| replies = ping.each_line.inject({ :hostname => hostname, :ip => nil, :ttl => nil, :latency => [] }) do |response, line| | |
| m = line.match /.*from\s+(\S+):.*ttl=(\d+)\s+time=(\S+)/ | |
| if m | |
| response[:ip] = m[1] | |
| response[:ttl] = m[2].to_i | |
| response[:latency].push m[3].to_f | |
| end | |
| response | |
| end | |
| logger.debug "Storing serialized latency data for #{target}" | |
| # store latency information | |
| attempts = 0 | |
| begin | |
| redis.hset "broom::sweep/#{hostname}/#{ping[:ip]}", capture, replies.to_json | |
| rescue => err | |
| attempts += 1 | |
| if attempts < 5 | |
| logger.err "Store failed (#{target}), retrying, attempt ##{attempts}..." | |
| retry | |
| else | |
| logger.err "Store of data failed, giving up on [ #{capture} --> #{replies.to_json} ]" | |
| end | |
| end | |
| end | |
| # sleep for a random interval | |
| wake_timeout = config[:interval].to_i + rand(config[:splay].to_i) | |
| logger.info "Collection complete...sleeping for #{wake_timeout} seconds" | |
| sleep wake_timeout | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment