Created
February 2, 2014 16:04
-
-
Save greyson/8770516 to your computer and use it in GitHub Desktop.
Simple, powerful connection monitor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
DEFAULT_SOUNDFILE="/home/greyson/alerts/S_083772.mp3" | |
DEFAULT_HOST="209.18.47.61" | |
import os | |
import subprocess | |
import sys | |
import time | |
import re | |
import signal | |
from datetime import datetime | |
def get_default_nameserver(): | |
with open( "/etc/resolv.conf", 'r' ) as file: | |
resolv = file.read() | |
m = re.search( "^nameserver[ \t]+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)", | |
resolv, re.MULTILINE ) | |
return m.group( 1 ) | |
class BackgroundSound: | |
""" | |
Plays a sound in the background for as long as it is running | |
""" | |
def __init__( self, soundfile=DEFAULT_SOUNDFILE ): | |
self.soundfile = soundfile | |
self.pid = None | |
self.devnull = open( os.devnull, 'wb' ) | |
def begin( self ): | |
self.pid = subprocess.Popen( | |
["/usr/bin/mplayer", "-noconsolecontrols", | |
"-really-quiet", | |
"-loop", "0", self.soundfile ], | |
stdout=self.devnull, | |
stderr=self.devnull ) | |
def end( self ): | |
self.pid.kill() | |
self.pid = None | |
def isPlaying( self ): | |
return self.pid is not None | |
online = 1 | |
offline = 2 | |
class Stats: | |
""" | |
Collects stats to be reported. | |
""" | |
def __init__( self ): | |
self.state = offline | |
self.current = 0 | |
self.max_online = 0 | |
self.max_offline = 0 | |
self.tot_online = 0 | |
self.tot_offline = 0 | |
self.last_report = 0 | |
# Set up the signal handler. | |
print( "Monitoring started:", | |
datetime.now().strftime( "%A, %d %B %Y %H:%M" ) ) | |
signal.signal( signal.SIGINT, self.handler ) | |
def handler( self, num, _ ): | |
reporttime = time.time() | |
if (reporttime - self.last_report) < 2: | |
print( "Quitting monitor" ) | |
sys.exit( 0 ) | |
print( '' ) | |
self.last_report = reporttime | |
self.print_stats() | |
return 1 | |
def print_stats( self ): | |
print( "REPORT AT:", | |
datetime.now().strftime( "%A, %d %B %Y %H:%M" ) ) | |
# Report the current state (and duration it's been that way) | |
if self.state == online: | |
print( "Currently online (%d ticks)" % self.current ) | |
self.max_online = max( self.max_online, self.current ) | |
else: | |
print( "Currently OFFLINE (%d ticks)" % self.current ) | |
self.max_offline = max( self.max_offline, self.current ) | |
# Report the longest stretches of both connected and | |
# disconnected states | |
print( "Maximum down stretch: %d ticks" % self.max_offline ) | |
print( "Maximum up stretch: %d ticks" % self.max_online ) | |
# Report the average uptime for the connection | |
total = float(self.tot_offline + self.tot_online) | |
avg_on = (self.tot_online / total * 100) | |
print( "Average uptime (percent):", avg_on ) | |
def offline( self ): | |
self.tot_offline += 1 | |
print( 'X', end='' ) | |
sys.stdout.flush() | |
if self.state == online: | |
self.max_online = max( self.max_online, | |
self.current ) | |
self.state = offline | |
self.current = 0 | |
self.current += 1 | |
def online( self ): | |
self.tot_online += 1 | |
print( '.', end='' ) | |
sys.stdout.flush() | |
if self.state == offline: | |
self.max_offline = max( self.max_offline, | |
self.current ) | |
self.state = online | |
self.current = 0 | |
self.current += 1 | |
class FullReporter: | |
def __init__( self ): | |
self.bs = BackgroundSound() | |
self.s = Stats() | |
self.log = open( "uptime.log", 'a' ) | |
self.log.write( "start " + datetime.now().isoformat() + "\n" ) | |
self.log.flush() | |
def exiting( self ): | |
self.log.write( "\nend " + datetime.now().isoformat() + "\n" ) | |
self.log.flush() | |
def online( self ): | |
self.s.online() | |
self.log.write( '.' ) | |
if self.bs.isPlaying(): | |
self.bs.end() | |
def offline( self ): | |
self.s.offline() | |
self.log.write( 'X' ) | |
if not self.bs.isPlaying(): | |
self.bs.begin() | |
class PingCheck: | |
""" | |
Pings a remote host to check the current packet loss | |
""" | |
def __init__( self, host=DEFAULT_HOST ): | |
self.host = host | |
self.pattern = re.compile( b"([0-9]+)% packet loss" ) | |
def check( self ): | |
output = subprocess.Popen( | |
[ "/usr/bin/ping", "-c", "5", "-i", ".2", "-q", | |
self.host ], | |
stdout=subprocess.PIPE ).communicate()[0] | |
m = self.pattern.search( output, re.MULTILINE ) | |
return int( m.group( 1 ) ) | |
if __name__ == "__main__": | |
host = get_default_nameserver() | |
print( "Default host is " + host ) | |
p = PingCheck( host ) | |
r = FullReporter() | |
try: | |
while True: | |
if p.check() != 0: | |
r.offline() | |
else: | |
r.online() | |
time.sleep( 5 ) | |
except SystemExit: | |
r.exiting() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment