Reputation: 111
I am making a webapp in python and flask which will email & tweet to the webmaster when the moment his website goes down. I am thinking of running an infinite while loop which waits for 10 minutes and then send a request to the website to be checked and checks if the returned response is 200. The problem is that were in the script can I insert this loop? Any suggestions about how I can achieve this?
Upvotes: 1
Views: 2853
Reputation: 44092
Trying to report a problem from dying app is not the most reliable method.
You shall have some external independent app, monitoring your app.
If you live in pure Python environment, you may write a script, which will check if accessing some app url succeeds and if not, it would alert someone. For alerting, you may try e.g. logbook
with log records being sent by e-mail (see MailHandler or GMailHandler).
In production environment it would be best to run some monitoring app like Nagios and simply check by check_http
For better readibility, the content is split to more parts, real script is in one file called monitor_url.py
monitor_url.py
: Docstring, imports and MAIL_TEMPLATEDocstring explains usage and is finally used by command line parser docopt
Imports are mostly logbook
related
"""monitor_url.py - check GET access to a url, notify by GMail about problems
Usage:
monitor_url.py [options] <url> <from> <pswd> <to>...
monitor_url.py -h
Options:
-L, --logfile <logfile> Name of logfile to write to [default: monitor_url.log].
-N, --archives <archives> Number of daily logs to keep, use 0 for unlimited [default: 0]
The check is performed once a minute and does HTTP GET request to <url>.
If there is a problem, it sends an e-mail using GMail account.
There is a limit of 6 e-mails, which can be sent per hour.
"""
import time
from logbook import Logger, GMailHandler, StderrHandler, NestedSetup, TimedRotatingFileHandler, Processor
from logbook.more import JinjaFormatter
from datetime import timedelta
import requests
from requests.exceptions import ConnectionError
MAIL_TEMPL = """Subject: {{ record.level_name }} on {{ record.extra.url }}
{{ record.message }}
Url: {{ record.extra.url }}
{% if record.exc_info %}
Exception: {{ record.formatted_exception }}
{% else %}
Status: {{ record.extra.req.status_code }}
Reason: {{ record.extra.req.reason }}
{% endif %}
"""
monitor_url.py
: main
function performing the checksThis script is looping in while
and performs once a minute a check.
If a problem is detected, or status code has changed, GMailHandler is configured to send e-mail.
def main(url, e_from, pswd, e_to, logfile, archives):
log = Logger("httpWatcher")
def inject_req(record):
record.extra.url = url
record.extra.req = req
processor = Processor(inject_req)
gmail_handler = GMailHandler(e_from, pswd, e_to,
level="WARNING", record_limit=6, record_delta=timedelta(hours=1), bubble=True)
gmail_handler.formatter = JinjaFormatter(MAIL_TEMPL)
setup = NestedSetup([StderrHandler(),
TimedRotatingFileHandler(logfile, bubble=True),
gmail_handler,
processor])
with setup.applicationbound():
last_status = 200
while True:
try:
req = requests.get(url)
if req.status_code != last_status:
log.warn("url was reached, status has changed")
if req.ok:
log.info("url was reached, status OK")
else:
log.error("Problem to reach the url")
last_status = req.status_code
except ConnectionError:
req = None
log.exception("Unable to connect")
last_status = 0
time.sleep(6)
montior_url.py
final if __name__ ...
This part actually parses command line parameters and calls the main
if __name__ == "__main__":
from docopt import docopt
args = docopt(__doc__)
print args
main(args["<url>"], args["<from>"], args["<pswd>"], args["<to>"], args["--logfile"],
int(args["--archives"]))
Try to call it without parameters:
$ python monitor_url.py
Usage: monitor_url.py [options] ... monitor_url.py -h
To get full help, use -h
$ python monitor_url.py -h
...the help is the same as script docstring...
Use it for real monitoring, here used for monitoring http://localhost:8000
$ python monitor_url.py -L mylog.log -N 2 http://localhost:8000 <yourmail>@gmail.com xxxpasswordxxx [email protected]
{'--archives': '2',
'--logfile': 'mylog.log',
'-h': False,
'<from>': '[email protected]',
'<pswd>': 'xxxxxxx',
'<to>': ['[email protected]'],
'<url>': 'http://localhost:8000'}
[2014-06-09 19:41] INFO: httpWatcher: url was reached, status OK
[2014-06-09 19:41] ERROR: httpWatcher: Unable to connect
Traceback (most recent call last):
....(shortened)...
raise ConnectionError(e, request=request)
ConnectionError: HTTPConnectionPool(host='localhost', port=8000): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)
[2014-06-09 19:41] WARNING: httpWatcher: url was reached, status has changed
[2014-06-09 19:41] INFO: httpWatcher: url was reached, status OK
Check logfile created in local folder.
Check your gmail inbox (if there is nothing, you have to play with the password).
Twitter notification is also possible with logbook
, but is not shown here.
To run the script, Python 2.7 is expected and you shall install some packages:
$ pip install logbook jinja2 requests
Managing notification from such a script is not easy. Consider this script of beta quality in this regard.
Usage of solutions like Nagios
seems to be more appropriate for this purpose.
Upvotes: 3