Skip to content

Instantly share code, notes, and snippets.

@jhawthorn
Created June 7, 2018 22:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhawthorn/6d631e9c1641451a4f7f711258d938ef to your computer and use it in GitHub Desktop.
Save jhawthorn/6d631e9c1641451a4f7f711258d938ef to your computer and use it in GitHub Desktop.
Generate a text report of internet outages from https://gist.github.com/jhawthorn/7bd68dd027a1b8e1ae2bdc56efed2414
$ ruby report.rb
Outage from 2018-06-07 02:50:49 -0700 to 2018-06-07 02:58:32 -0700
duration: 8 minutes
pings lost: 77% (34 / 44)
average ping: 22ms
Outage from 2018-06-07 05:07:10 -0700 to 2018-06-07 05:21:04 -0700
duration: 14 minutes
pings lost: 83% (65 / 78)
average ping: 16ms
Outage from 2018-06-07 12:11:27 -0700 to 2018-06-07 12:15:18 -0700
duration: 4 minutes
pings lost: 8% (2 / 24)
average ping: 18ms
Ping = Struct.new(:time, :ms) do
def dropped?
ms.nil?
end
end
Outage = Struct.new(:pings) do
def start_time
pings.first.time
end
def end_time
pings.last.time
end
def duration
end_time - start_time
end
def dropped_ratio
pings.count(&:dropped?) / pings.count.to_f
end
def dropped_pings
pings.select(&:dropped?)
end
def returned_pings
pings.reject(&:dropped?)
end
def average_ping
if returned_pings.empty?
nil
else
returned_pings.sum(&:ms) / returned_pings.count
end
end
def description
<<~STR
Outage from #{start_time} to #{end_time}
duration: #{(duration/60.0).ceil} minutes
pings lost: #{(dropped_ratio * 100).round}% (#{pings.count(&:dropped?)} / #{pings.count})
average ping: #{average_ping}ms
STR
end
end
def partition_outages(pings)
window = 5 * 60 # 5 minutes
dropped = pings.select(&:dropped?)
partitions = []
until dropped.empty? do
partition = [dropped.shift]
partitions << partition
while !dropped.empty? && (dropped.first.time - partition.last.time) < window
partition << dropped.shift
end
end
partitions.map do |dropped|
partition_pings = pings.select do |ping|
(dropped.first.time..dropped.last.time).cover?(ping.time)
end
Outage.new(partition_pings)
end
end
file = Dir['logs/*.guff'].sort.last
data = File.read(file).lines.map do |line|
time, ping = line.strip.split(",")
time = Time.at(time.to_i)
ping = ping && ping.to_i
Ping.new(time, ping)
end
outages = partition_outages(data)
outages.select do |outage|
outage.duration > 60
end.each do |outage|
puts outage.description
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment