require 'timeout'
require 'json'
class Client
attr_accessor :ipaddr, :port, :remote, :timeout, :redis
MAX_ATTEMPTS = 2
def initialize(options={})
self.ipaddr = options[:host] || "127.0.0.1"
self.port = options[:port] || 8127
self.timeout = options[:timeout] || 2000
connect!
end
def available
keys = query_remote("available")
keys.collect do |k|
if k.match /^timer/
["mean", "min", "max", "upper_90", "stddev", "count"].collect{|a| "#{k}:#{a}"}
else
k
end
end.flatten
end
def values(metric_name, start_timestamp, end_timestamp=Time.now, attempt=0)
results = []
values = query_remote("values #{metric_name} #{start_timestamp.to_i} #{end_timestamp.to_i}")
if values[metric_name].nil?
puts "BatsdClient: #{Thread.current} #{self.remote.addr} Values returned weren't the same as what was asked for (expecting #{metric_name}, got #{values.keys.join(";")})."
if attempt < MAX_ATTEMPTS
return values(metric_name, start_timestamp, end_timestamp, attempt+1)
else
return []
end
end
results = values[metric_name].collect{|v| { timestamp: Time.at(v["timestamp"].to_i), value: v["value"].to_f } }
results
end
def reconnect!
self.remote = nil
connect!
end
private
def connect!
Timeout::timeout(5) do
self.remote = TCPSocket.new(self.ipaddr, self.port) rescue nil
end
rescue Timeout::Error => e
puts "BatsdClient: Couldn't connect to the remote statsd server in the time alloted"
end
def query_remote(command, attempt=0)
Timeout::timeout(self.timeout.to_f / 1000.0) do
connect! unless self.remote
self.remote.puts command
@response = self.remote.gets
results = JSON.parse(@response)
end
rescue TimeoutError => e
puts "BatsdClient: Timed out on #{command} #{"; retrying." if attempt < MAX_ATTEMPTS}"
if attempt < MAX_ATTEMPTS
query_remote(command, attempt+1)
else
[]
end
rescue Exception => e
if attempt < MAX_ATTEMPTS
query_remote(command, attempt+1)
else
puts "BatsdClient: Error querying remote server with #{command} due to #{e}: #{e.message} #{e.backtrace.join("\n")}"
self.remote = nil
raise e
end
end
end