$:.unshift File.dirname(__FILE__) # Pong version 0.1 by Alex Chaffee require "fileutils" module Pong class Series < Array MAX = 32767 def num(n) n = MAX if n.nil? [n, size].min end def last(n = MAX) num = num(n) self.slice(-num, num) end def sum(n = MAX) last(n).inject(0){|memo, value| value.nil? ? memo : (memo + value) } end def mean(n = MAX) size == 0 ? 0 : sum(n) / num(n) end def nils(n = MAX) last(n).select{|value| value.nil? }.size end def nil_percent(n = MAX) (nils(n).to_f / num(n).to_f) * 100.0 end end class Host attr_reader :pings, :hostname, :address def initialize(hostname) @hostname = @address = hostname @output = "/tmp/#{hostname}.out" FileUtils.rm_rf(@output) if File.exist?(@output) FileUtils.touch(@output) end def start @pings = Series.new process = IO.popen("ping #{hostname}") Thread.new do while (line = process.gets) parse(line) unless line.nil? end end end def parse(line) m = /^PING (\S*) \(([0-9.]*)\)/.match(line) unless m.nil? @address = m[2] end m = /icmp_seq=([0-9]*).*time=([0-9.]*)/.match(line) unless m.nil? seq = m[1].to_i time = m[2].to_f pings[seq] = time end end def missing(n=nil) pings.nils(n) end def missing_percent(n=nil) pings.nil_percent(n) end def mean(n=nil) pings.mean(n) end def stats(n=nil) [ "%8.3f msec" % (mean(n)), "%4d (%.2f%%)" % [missing(n), missing_percent(n)], "#{hostname} (#{address})", ].join("\t") end def header [ "Mean ", "Missing ", "Host" ].join("\t") end end class Hosts < Array def self.from_args(args) hosts = Hosts.new args = ['localhost'] if args.empty? args.each do |arg| host = Host.new(arg) hosts << host end hosts end def stats(n = nil) puts n.nil? ? "Entire run (#{first.pings.size} sec):" : "Last #{n} seconds:" puts first.header self.each do |host| puts host.stats(n) end end def run each {|host| host.start } while true system("clear") stats(10) puts stats(60) puts stats sleep(5) end end end end