site uptime monitoring tool

William O'Higgins Witteman william.ohiggins-H217xnMUJC0sA/PxXw9srA at public.gmane.org
Fri Sep 18 11:00:55 UTC 2009


On Thu, Sep 17, 2009 at 11:25:23PM -0400, Rajinder Yadav wrote:
>Anyone know of a good free or inexpensive site uptime monitoring site?
>
>I guess I could write a ruby script to test my site, but I don't keep
>my linux box running 24x7.
>
>I came across http://basicstate.com/ - but they check every 15 min,
>which I think the window is way too long.

There are lots of options.  I run the following script with cron from
two different servers, which point at each other.  It just sends an
email, but that email is going to Rogers' email-to-SMS gateway, sending
text to my phone.


#!/usr/bin/python

"""
Poll the websites specified in the configuration file

"""

import httplib
import optparse
import os
import smtplib
import socket
import sqlite3
import time

#############################################################
#                                                           #
# Here is the base configuration for sitepoll               #
#                                                           #

config_location = os.path.expanduser("~") + "/.sitepoll.db"
# Email address goes here
address = ("",)
# URLs to poll go here
urls = [("",)]

#############################################################

def connect2db():
  """If if exists, connect to configuration DB, returning a connection 
  object and a cursor.  If it does not exist, create and populate it."""
  
  if os.path.exists(config_location):
    a = sqlite3.connect(config_location)
    b = a.cursor()
  else:
    a = sqlite3.connect(config_location)
    b = a.cursor()
    a.commit()
    b.close()
    
    b.execute("""create table urls(url text unique)""")
    b.execute("""create table address(address text)""")
    b.execute("""create table flags(url text unique, first text, latest text)""")
    b.execute("""create table log(url text, status text, timestring text, timestamp text)""")
    b.execute("""insert into address values (?)""", address)
    for url in urls:
      b.execute("""insert into urls values (?)""", url)

    a.commit()
    b.close()

    a = sqlite3.connect(config_location)
    b = a.cursor()

  return [a,b]


def update_config():
  """Update the config sections of the configuration DB."""
  """WARNING: This also clears the flags."""
  a = connect2db()
  conn = a[0]
  c = a[1]
  c.execute("delete from urls")
  c.execute("delete from flags")
  c.execute("delete from address")
  conn.commit()
  c.execute("""insert into address values (?)""", address)
  for url in urls:
    c.execute("""insert into urls values (?)""", url)

    conn.commit()
    c.close()


def geturls():
  """Get the URLs to poll, return a list."""
  
  siteurls = []

  a = connect2db()
  conn = a[0]
  c = a[1]
  c.execute("select * from urls")
  for i in c:
    siteurls.append(i[0])
  c.close()

  return siteurls


def getreportaddy():
  """Get email address from the config, return string."""
 
  a = connect2db()
  conn = a[0]
  c = a[1]
  c.execute("select address from address")
  report_address = c.fetchone()

  return report_address


def pollsite(url):
  """Poll a website, returning the response code."""

  a = httplib.HTTPConnection(url)
  try:
    a.request("GET","/")
  except:
    b = "404"
    return b
  b = a.getresponse()

  return b.status


def logit(url,status):
  """Log an error."""

  mytime = time.strftime("%Y %m %d %H:%M:%S",time.localtime())
  mytimestamp = time.mktime(time.localtime())
  log_parts = (url, status, mytimestamp, mytime)
  
  a = connect2db()
  conn = a[0]
  c = a[1]
  c.execute("""insert into log values (?,?,?,?)""", log_parts)
  conn.commit()
  c.close()


def sendmessage(url,status,duration,timestr):
  """Send an email to the required address to state that the URL is """
  """responding with 'status'."""
  toaddr = getreportaddy()
  msg = url + " failed with this status ( " + str(status) + " ) at " + timestr
  myhostname = socket.gethostname()
  server = smtplib.SMTP(myhostname)
  server.sendmail(toaddr,toaddr,msg)
  server.quit()


def setflag(flagged_url,status):
  """Set a flag for the URL in the flag file, creating it if necessary."""
  
  mytime = time.strftime("%Y %m %d %H:%M:%S",time.localtime())
  mytimestamp = time.mktime(time.localtime())
  a = connect2db()
  conn = a[0]
  c = a[1]
  c.execute("select url,first,latest from flags where url=?", (flagged_url,))
  if c.fetchone():
    """There is already a flag for this URL - update with this timestamp."""
    try:
      first = c.fetchone()[1]
    except:
      first = 0
    try: 
      latest = c.fetchone()[2]
    except:
      latest = 0
    #debug print("Found a record.")
    c.execute("update flags set latest=? where url=?",(mytimestamp,flagged_url))
    conn.commit()
    logit(flagged_url,status)
    # Test the difference between latest and now.
    difference = mytimestamp - first
    if difference > 86405*3:
      pass
    elif difference >= 86400*3:
      sendmessage(flagged_url,status,difference,mytime)
    elif difference >= 86400*2:
      sendmessage(flagged_url,status,difference,mytime)
    elif difference >= 86400:
      sendmessage(flagged_url,status,difference,mytime)
    else:
      pass
  else:
    """There's no flag for this URL yet - set one, with timestamp as first."""
    #debug print("No record yet.")
    c.execute("insert into flags(url,first,latest) values (?,?,?)",(flagged_url,mytimestamp,mytimestamp))
    conn.commit()
    logit(flagged_url,status)
    sendmessage(flagged_url,status,0,mytime)


def clearflag(flagged_url):
  """Clear a flag on successful return."""
  a = connect2db()
  conn = a[0]
  c = a[1]
  c.execute("delete from flags where url=?",(flagged_url,))
  conn.commit()
  c.close()


def status_response(url,status):
  """Look at the status code returned, and craft an appropriate response."""

  if status != 200:
    setflag(url,status)
  else:
    clearflag(url)




# Here is the action code
#   Check for the update config directive (and act appropriately)
#     get a list of URLs, 
#       poll each one, 
#       push their status to the status_response function

def main():
  """Define an OptionParser object and make the appropriate function calls."""

  usage = "Usage: %prog [options]"
  parser = optparse.OptionParser(usage)
  #parser.add_option("-h", "--help", action="store_true", dest="help", help="Use -h or --help to see this.  You probably knew that.")
  parser.add_option("-u", "--update", action="store_true", dest="update", help="Use -u or --update to update the configuration in the database.  WARNING: this also clears all of the currently set flags.")
  (options, args) = parser.parse_args()

  if options.update:
    update_config()
  elif len(args) != 1:
    urls2poll = geturls()

    for url in urls2poll:
      status = pollsite(url)
      status_response(url,status)


if __name__ == "__main__":
  main()

   
This uses a sqlite database to track stats and response codes.  I only
have it call my phone once per day of outage, but you can change that.
I use it at work to keep track of my home computer, and at home to keep
track of work.
-- 

yours,

William

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://gtalug.org/pipermail/legacy/attachments/20090918/99dd9498/attachment.sig>


More information about the Legacy mailing list