class Rack::Monitor::OpenTSDB::Reporter

Constants

MAX_CACHE

Public Class Methods

new(stats, host, port, key = 'unconfigured.rack.monitor', interval = 60, tags = {}, logger = nil) click to toggle source

stats has the following structure:

{
  'GET /monitored/path/1': {
    '<httpstatus>': [<time>, ...],
    ...
  },
  ...
}

The stats parameter must be extended with MonitorMixin. Like this it can be accessed synchronized.

# File lib/rack/monitor/opentsdb/reporter.rb, line 20
def initialize(stats, host, port, key = 'unconfigured.rack.monitor', interval = 60, tags = {}, logger = nil)
  raise ArgumentError, "Interval less than zero" if interval < 0
  raise ArgumentError, 'stats does not support synchronize' unless stats.respond_to? :synchronize

  @interval = interval
  @tags     = tags
  @stats    = stats
  @host     = host
  @port     = port
  @key      = key
  @logger   = logger
  @tosend   = []
  start
end

Public Instance Methods

start() click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 35
def start
  return if @run
  @run = true
  log(:info, 'Starting Reporter-Thread')
  @th = Thread.new do
    t = Time.now
    while run?
      t += @interval
      (sleep(t - Time.now) rescue nil) and send_report rescue nil
    end
  end
end
stop() click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 48
def stop
  @stats.synchronize do
    @run = false
  end
  @th.join
end

Private Instance Methods

copy_and_clear_stats() click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 112
def copy_and_clear_stats
  copy = {}
  @stats.synchronize do
    @stats.each do |url, url_stats|
      copy[url] = url_stats
    end
    @stats.clear
  end
  copy
end
log(level, message) click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 123
def log(level, message)
  if(@logger.respond_to? level)
    @logger.send level, "Rack::Monitor::OpenTSDB::Reporter - #{message}"
  end
end
run?() click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 57
def run?
  @stats.synchronize do
    @run
  end
end
send_report() click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 63
def send_report
  log(:debug, "Sending Report#{@tosend.empty? ? '' : " (#{@tosend.length} spooled entries)"}")

  timestamp = Time.now.to_i
  data = copy_and_clear_stats
  data.each do |url, url_stats|
    verb, path = url.split(/ /)
    url_stats.each do |status, timings|
      tags = @tags.merge({:status => status, :verb => verb, :path => path}).map { |key, value| "#{key}=#{value}" }.join(' ')
      @tosend.push("put #{@key}.min #{timestamp} #{timings.min} #{tags}")
      @tosend.push("put #{@key}.max #{timestamp} #{timings.max} #{tags}")
      @tosend.push("put #{@key}.num #{timestamp} #{timings.size} #{tags}")
      @tosend.push("put #{@key}.avg #{timestamp} #{timings.inject(0.0) { |sum, e| sum + e } / timings.size} #{tags}")
    end
  end

  # cleanup if cannot send anything, only keep MAX_CACHE entries to send
  if @tosend.size > MAX_CACHE
    @tosend.shift(@tosend.length - - MAX_CACHE)
  end

  send_to_socket
end
send_to_socket() click to toggle source
# File lib/rack/monitor/opentsdb/reporter.rb, line 87
def send_to_socket
  begin
    @tosend.delete_if do |line|
      # throws in first go NoMethodError: undefined method `puts' for nil:NilClass
      # this is rescued and the connection is opened for retry
      @socket.puts line
      true
    end
  rescue IOError, Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EPIPE
    log(:error, "Connection problem: #{$!.message}")

    # Don't retry immediately (preventing loops), next run will retry
    @socket = nil
  rescue
    begin
      log(:info, "Connecting to #{host}:#{port}")
      @socket = TCPSocket.new(@host, @port)
      retry
    rescue
      log(:error, "Connection problem:#{$!.message}")
      # will do no retry in this case
    end
  end
end