""" monitor_url.py USAGE: python monitor_network.py http://whatever.com/ 10 1 The first argument is how many seconds to pause after a successful connection. The second argument is how many seconds to pause after an error. A file called "log..csv" is written to the current directory *for errors only*. Non-errors are pretty boring. To stop it, hit Ctrl-C. EXAMPLE USAGE: >python \all\bin\monitor_url.py http://google.com/ 10 1 #1 Sat May 27 12:06:34 2006 http://google.com/ Received 2449 bytes in 2.3 seconds. #2 Sat May 27 12:06:46 2006 http://google.com/ Received 2449 bytes in 0.2 seconds. #3 Sat May 27 12:06:56 2006 http://google.com/ Received 2449 bytes in 0.2 seconds. NOTES: - Another way to use this is to make a new Python script that imports this one and calls monitor() with the appropriate parameters. - monitor() can also take a list of good text and bad text to check for. TO DO: [ ] Would be nice to follow redirection directive as in: \n\n\n\n\n\n\n\n [ ] Should have option to send email """ import os, socket, sys, time, types, urllib2 true = 1==1 false = 0==1 nil = None class Defaults: url = 'http://google.com/' pauseAfterSuccess = 10 # seconds pauseAfterError = 1 # seconds goodTextList = [] badTextList = [] def main(args=nil): if args is nil: args = sys.argv[1:] try: url = args[0] except IndexError: url = nil try: pauseAfterSuccess = int(args[1]) except IndexError: pauseAfterSuccess = nil try: pauseAfterError = int(args[2]) except IndexError: pauseAfterError = nil monitor(url, pauseAfterSuccess, pauseAfterError) class ContentError(Exception): pass class EmptyError(ContentError): pass class BadTextError(ContentError): pass class GoodTextError(ContentError): pass def monitor(url=nil, pauseAfterSuccess=nil, pauseAfterError=nil, goodTextList=nil, badTextList=nil): if url is nil: url = Defaults.url if pauseAfterSuccess is nil: pauseAfterSuccess = Defaults.pauseAfterSuccess if pauseAfterError is nil: pauseAfterError = Defaults.pauseAfterError if goodTextList is nil: goodTextList = Defaults.goodTextList if badTextList is nil: badTextList = Defaults.badTextList i = 1 startOfGoodReads = nil goodReadsDuration = 0.0 while true: print ' #%s %s %s' % (i, time.asctime(), url), flush() exc = nil # exception try: s = nil start = time.time() s = urllib2.urlopen(url).read() if not s: raise EmptyError now = time.time() duration = now - start if startOfGoodReads is nil: startOfGoodReads = now - duration # test against bad text s = s.lower() if badTextList: for text in badTextList: if s.find(text.lower())!=-1: raise BadTextError, 'found bad text: %r' % text if goodTextList: for text in goodTextList: if s.find(text.lower())==-1: raise GoodTextError, 'did not find good text: %r' % text except IOError, exc: pass except socket.error, exc: pass except ContentError, exc: pass if exc: duration = time.time() - start print print '!'*78 print 'Error after %0.1f secords.' % duration print 'Error:', exc print 'Content: %r' % s if startOfGoodReads is not nil: goodReadsDuration = time.time()-startOfGoodReads-duration print 'Had good reads for %.0f seconds.' % goodReadsDuration startOfGoodReads = nil if 1: # write log of errors filename = urlToFilename(url) if not os.path.exists(filename): columns = 'when,url,what,good reads duration,timeout duration,error message\n' f = open(filename, 'wt') f.write(columns) else: f = open(filename, 'at') try: fields = [ time.asctime(time.localtime(start)), url, 'error', # what '%.1f' % goodReadsDuration, '%.1f' % duration, str(exc), ] f.write(joinCSVFields(fields)+'\n') f.flush() finally: f.close() print 'Logged to %s' % filename goodReadsDuration = 0.0 sleep(pauseAfterError) else: print ' Received %s bytes in %0.1f seconds.' % (len(s), duration) sleep(pauseAfterSuccess) i += 1 def urlToFilename(url): url = url.replace('http://', '') url = url.replace('https://', '') if url.endswith('/'): url = url[:-1] url = url.replace('/', '_') url = 'log.' + url + '.csv' return url def flush(): sys.stdout.flush() def sleep(seconds): #print 'Sleeping %s...' % seconds flush() time.sleep(seconds) def joinCSVFields(fields): """ Adapted from Webware.MiscUtils. http://www.webwareforpython.org/ Returns a CSV record (eg a string) from a sequence of fields. Fields containing commands (,) or double quotes (") are quoted and double quotes are escaped (""). The terminating newline is NOT included. """ newFields = [] for field in fields: field = str(field) #assert type(field) is types.StringType if field.find('"')!=-1: newField = '"' + field.replace('"', '""') + '"' elif field.find(',')!=-1 or field.find('\n')!=-1 or field.find('\r')!=-1: newField = '"' + field + '"' else: newField = field newFields.append(newField) return ','.join(newFields) if __name__=='__main__': main()