§ Monitoring electricity

I bought a UPS for my server around a year ago. I decided to go for something mid-range, and it having an interface through which I could ask for status was not even on the ‘necessary features list’. It was all about getting maximum power capacity at reasonable price. And it does work very well. However with the current setup I had no idea whether there was electricity or not - meaning I could happily fire up something CPU consuming while the battery was dying, meaning mayhem and destruction in the least favourable moment (as usual).

The solution came to me quite suddenly when I was looking at my ‘server status’ dashboard - I have there excerpts from all sorts of logs, and as I knew there was a power outage today I have realized there is an indirect way to check the electricity status. My setup is that the UPS powers only the server and the DSL modem - the essentials. As the server also serves as a router for my home network it is always connected to a switch. So when the electricity dies, the switch turns off which in turns makes the server’s Ethernet interface connected to it to change state to DOWN. This is an extremely simple way to do an indirect measurement.

Of course this method can produce false positives - all it takes is unplugging the switch (or the switch may day, which it will sooner or later). However, I want this for information purpose only, not for making decisions, so the reliability of the data source is good enough for me (and it doesn’t involve inventing any new hardware).

§ Log monitoring script

All I want is information and I already have a system for providing that - the status dashboard I mentioned. So the solution here is a small script that goes over the log an monitors DOWN and UP changes of my LAN interface. It is important to note here that the script is run periodically, which means it may miss an outage if it happens across a log turnover.

#!/usr/local/bin/ruby19
#

%w{date time_diff}.each {|g| require g }

outages = Array.new
state = :DOWN
current = date_start = date_end = false

File.open('/var/log/messages', 'r') do |f|
  f.each_line do |l|
    if m = l.match(/(.*) kernel: ale0: link state changed to #{state}/)
      case state
      when :DOWN
        date_start = DateTime.parse(m.captures.first)
        state = :UP
      when :UP
        date_end = DateTime.parse(m.captures.first)
        diff = Time.diff(date_start, date_end)[:diff]
        outages.push([date_start, date_end, diff])
        state = :DOWN
      end
    end
  end
end

if outages.last.first != date_start 
  date_end = Time.now
  diff = Time.diff(date_start, date_end)[:diff]
  outages.push([date_start, date_end, diff])
  current = true
end

if current
  current = outages.pop
  puts "No electricity for #{current.last} (since #{current.first.strftime('%Y-%m-%d %H:%M:%S')})."
else
  puts 'Electricity ok.'
end

if outages.length > 0
  puts "\nRecent outages:"
  outages.reverse.each do |o|
    puts "#{o[0].strftime('%Y-%m-%d %H:%M:%S')} - #{o[1].strftime('%Y-%m-%d %H:%M:%S')} - #{o[2]}"
  end
else
  puts 'No recent outages.'
end

As this script relies on dates from the log file it doesn’t handle the year change, but again, simplicity is the key feature.

The output.

comments powered by Disqus
Last update: 2013-01-30. » LINK » TXT » ATOM. Go to the top. Licence CC-BY-NC-SA.
If you find this interesting go ahead and leave a comment or add a star.
Any and all feedback is appreciated!