lib/visage-app/collectd/json.rb in visage-app-1.0.0 vs lib/visage-app/collectd/json.rb in visage-app-2.0.0

- old
+ new

@@ -8,135 +8,132 @@ # Exposes RRDs as JSON. # # A loose shim onto RRDtool, with some extra logic to normalise the data. # -class CollectdJSON +module Visage + module Collectd + class JSON - def initialize(opts={}) - @rrddir = opts[:rrddir] || CollectdJSON.rrddir - @types = opts[:types] || CollectdJSON.types - end + def initialize(opts={}) + @rrddir = opts[:rrddir] || Visage::Collectd::JSON.rrddir + @types = opts[:types] || Visage::Collectd::JSON.types + end - # Entry point. - def json(opts={}) - host = opts[:host] - plugin = opts[:plugin] - plugin_instances = opts[:plugin_instances][/\w.*/] - instances = plugin_instances.blank? ? '*' : '{' + plugin_instances.split('/').join(',') + '}' - rrdglob = "#{@rrddir}/#{host}/#{plugin}/#{instances}.rrd" + def parse_time(time, opts={}) + case + when time && time.index('.') + time.split('.').first.to_i + when time + time.to_i + else + opts[:default] || Time.now.to_i + end + end - start = case - when opts[:start] && opts[:start].index('.') - opts[:start].split('.').first - when opts[:start] - opts[:start] - else - (Time.now - 3600).to_i - end + # Entry point. + def json(opts={}) + host = opts[:host] + plugin = opts[:plugin] + instances = opts[:instances][/\w.*/] + instances = instances.blank? ? '*' : '{' + instances.split('/').join(',') + '}' + rrdglob = "#{@rrddir}/#{host}/#{plugin}/#{instances}.rrd" + finish = parse_time(opts[:finish]) + start = parse_time(opts[:start], :default => (finish - 3600 || (Time.now - 3600).to_i)) + data = [] - finish = case - when opts[:finish] && opts[:finish].index('.') - opts[:finish].split('.').first - when opts[:finish] - opts[:finish] - else - Time.now.to_i - end + Dir.glob(rrdglob).map do |rrdname| + parts = rrdname.gsub(/#{@rrddir}\//, '').split('/') + host_name = parts[0] + plugin_name = parts[1] + instance_name = File.basename(parts[2], '.rrd') + rrd = Errand.new(:filename => rrdname) - data = [] + data << { :plugin => plugin_name, :instance => instance_name, + :host => host_name, + :start => start, + :finish => finish, + :rrd => rrd } + end - Dir.glob(rrdglob).map do |rrdname| - parts = rrdname.gsub(/#{@rrddir}\//, '').split('/') - host_name = parts[0] - plugin_name = parts[1] - instance_name = File.basename(parts[2], '.rrd') - rrd = Errand.new(:filename => rrdname) + encode(data) + end + private + # Attempt to structure the JSON reasonably sanely, so the consumer (i.e. a + # browser) doesn't have to do a lot of computationally expensive work. + def encode(datas) - data << { :plugin => plugin_name, :instance => instance_name, - :host => host_name, - :start => start, - :finish => finish, - :rrd => rrd } - end + structure = {} + datas.each do |data| + fetch = data[:rrd].fetch(:function => "AVERAGE", + :start => data[:start], + :finish => data[:finish]) + rrd_data = fetch[:data] - encode(data) - end + # A single rrd can have multiple data sets (multiple metrics within + # the same file). Separate the metrics. + rrd_data.each_pair do |source, metric| - private - # Attempt to structure the JSON reasonably sanely, so the consumer (i.e. a - # browser) doesn't have to do a lot of computationally expensive work. - def encode(datas) + # Filter out NaNs and weirdly massive values so yajl doesn't choke + metric.map! do |datapoint| + case + when datapoint && datapoint.nan? + @tripped = true + @last_valid + when @tripped + @last_valid + else + @last_valid = datapoint + end + end - structure = {} - datas.each do |data| - fetch = data[:rrd].fetch(:function => "AVERAGE", - :start => data[:start], - :finish => data[:finish]) - rrd_data = fetch[:data] + # Last value is always wack. Set to 0, so the timescale isn't off by 1. + metric[-1] = 0.0 + host = data[:host] + plugin = data[:plugin] + instance = data[:instance] + start = data[:start].to_i + finish = data[:finish].to_i - # A single rrd can have multiple data sets (multiple metrics within - # the same file). Separate the metrics. - rrd_data.each_pair do |source, metric| + structure[host] ||= {} + structure[host][plugin] ||= {} + structure[host][plugin][instance] ||= {} + structure[host][plugin][instance][source] ||= {} + structure[host][plugin][instance][source][:start] ||= start + structure[host][plugin][instance][source][:finish] ||= finish + structure[host][plugin][instance][source][:data] ||= metric - # Filter out NaNs and weirdly massive values so yajl doesn't choke - metric.map! do |datapoint| - case - when datapoint && datapoint.nan? - @tripped = true - @last_valid - when @tripped - @last_valid - else - @last_valid = datapoint end end - # Last value is always wack. Set to 0, so the timescale isn't off by 1. - metric[-1] = 0.0 - host = data[:host] - plugin = data[:plugin] - instance = data[:instance] - start = data[:start].to_i - finish = data[:finish].to_i - - structure[host] ||= {} - structure[host][plugin] ||= {} - structure[host][plugin][instance] ||= {} - structure[host][plugin][instance][source] ||= {} - structure[host][plugin][instance][source][:start] ||= start - structure[host][plugin][instance][source][:finish] ||= finish - structure[host][plugin][instance][source][:data] ||= metric - + encoder = Yajl::Encoder.new + encoder.encode(structure) end - end - encoder = Yajl::Encoder.new - encoder.encode(structure) - end + class << self + attr_writer :rrddir - class << self - attr_writer :rrddir + def rrddir + @rrddir ||= Visage::Config.rrddir + end - def rrddir - @rrddir ||= Visage::Config.rrddir - end + def types + @types ||= Visage::Config.types + end - def types - @types ||= Visage::Config.types - end + def hosts + if @rrddir + Dir.glob("#{@rrddir}/*").map {|e| e.split('/').last }.sort + end + end - def hosts - if @rrddir - Dir.glob("#{@rrddir}/*").map {|e| e.split('/').last }.sort + def plugins(opts={}) + host = opts[:host] || '*' + Dir.glob("#{@rrddir}/#{host}/*").map {|e| e.split('/').last }.sort + end + end - end - def plugins(opts={}) - host = opts[:host] || '*' - Dir.glob("#{@rrddir}/#{host}/*").map {|e| e.split('/').last }.sort - end - - end - -end + end # class JSON + end # module Collectd +end # module Visage