module EmeterGomDaemon class Daemon Defaults = { :logfile => '-', :interval => 5, :threshold => 5, # in percent :nagios_port => 9918, :stealth => false, } # option precedence is: # 1. commands line options # 2. GOM Sensor node values # 3. built-in Default values (see #Defaults) # def initialize sensor_url, options = {} @sensor_url = sensor_url @gom, @sensor_path = (Gom::Remote::Connection.init @sensor_url) @options = Defaults.merge(gnode(@sensor_path)).merge(options) puts "options: #{@options.inspect}" redirect_to logfile end def logfile @logfile ||= @options[:logfile] end def interval @interval ||= Integer(@options[:interval]) end def emeter_ip @emeter_ip ||= @options[:emeter_ip] end def nagios_port @nagios_port ||= @options[:nagios_port] end def threshold @threshold ||= Float(@options[:threshold]) end def stealth? @stealth ||= @options[:stealth] end def run run_nagios_thread # become visible to nagios gom_checkin loop do begin tic rescue Exception => e callstack = "#{e.backtrace.join "\n "}" puts " ## #{self} - #{e}\n -> #{callstack}" ensure sleep interval end end ensure stop_nagios_thread end private def tic old = @current_value || 0 readout = poll _, _, _, @current_value = readout change_in_percent = 100 * (1 - (@current_value / old)).abs if threshold < change_in_percent t = Time.now puts "#{t} :: #{readout.inspect}" puts "#{t} :: #{@current_value}" @gom.write "#{@sensor_path}:current_value", @current_value end end def poll # expected: '172.20.10.24;WEBIO-042BFF;Sensor 1 0..50A;0,150 A' line = (open "http://#{emeter_ip}/Single1").read ip, id, name, val = (line.split /;/) [ip, id, name, (val.sub! /,/, '.').to_f] end private def redirect_to logfile (@logfile_fd && @logfile_fd.close) rescue nil puts " -- redirecting stdout/stderr to: #{logfile}" if logfile == '-' if @stdout $stderr, $stdout = @stdout, @stderr end else @stderr, @stdout = $stdout, $stderr @logfile_fd = File.open(logfile, File::WRONLY|File::APPEND|File::CREAT) @logfile_fd.sync = true $stderr = $stdout = @logfile_fd end # first line after redirect puts " -- e-meter daemon logile redirect at #{Time.now}" end # push own ip and monitoring port back to GOM node def gom_checkin if stealth? puts "skipping gom check-in in stealth mode" else @gom.write "#{@sensor_path}:daemon_ip", @gom.callback_ip @gom.write "#{@sensor_path}:nagios_port", nagios_port end end def stop_nagios_thread @nagios_thread or return puts ' -- killing nagios thread...' @nagios_thread.kill @nagios_thread = nil puts ' and gone.' self end def run_nagios_thread @nagios_thread .nil? or (raise "already running!") port = nagios_port @nagios_thread = Thread.new do infinity = Proc.new do |env| [200, {"Content-Type" => "text/plain"}, env.inspect] end puts " -- running nagios server on port: #{port}" Rack::Handler::Mongrel.run infinity, :Port => port end self end # # TODO: The GOM helper stuff is experimental and being tested here. Once # it's prove i'll move it into the gom-script gem # #def gattr name # (Gom::Remote.connection.read "#{@sensor_path}:#{name}.txt") #rescue NameError # nil #end def gnode path json = (Gom::Remote.connection.read "#{path}.json") (JSON.parse json)["node"]["entries"].select do |entry| # 1. select attribute entries entry.has_key? "attribute" end.inject({}) do |h, a| # 2. make it a key, value list kv = a["attribute"] h.update(kv["name"].to_sym => kv["value"]) end end end end