Logging to Email

It’s possible to configure logging such that when “errors” are logged, an email can be sent to some recipient(s).

You can set this up however you like of course; see upstream docs for more info:

But the example shown below does as follows:

  • root logger is DEBUG+ and uses 3 handlers: file, console, email

  • file handler

    • writes to app/log/wutta.log (you should specify absolute path instead)

    • will auto-rotate log file when size reaches 10MB

    • uses “generic” entry formatter

  • console handler

    • writes to STDERR for the current process

    • writes only INFO+ entries (so no DEBUG)

    • uses “console” entry formatter

  • email handler

    • writes only ERROR+ entries (so no DEBUG, INFO or WARNING)

    • email is From: sender and To: recip(s) with Subject: as shown

    • uses “generic” entry formatter (for message body)

Note

This will not send email when “uncaught exceptions” occur. This will only send email when an error is logged. For example:

import logging

log = logging.getLogger(__name__)

log.debug("do not email this")
log.info("nor this")
log.warning("nor this")

log.error("but *do* email this")

try:
    raise RuntimeError
except:
    log.exception("this also gets emailed")

# nb. no email is sent *here*, although possibly further up the
# stack another try/except block could be setup to log uncaught
# errors, in which case email may still be sent.
raise RuntimeError("this will just raise up the stack")

Now here is the example, which can be added to a normal config file (modifying as needed):

[loggers]
keys = root

[handlers]
keys = file, console, email

[formatters]
keys = generic, console

[logger_root]
handlers = file, console, email
level = DEBUG

[handler_file]
class = handlers.RotatingFileHandler
args = ('app/log/wutta.log', 'a', 1000000, 100, 'utf_8')
formatter = generic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
formatter = console
level = INFO

[handler_email]
class = handlers.SMTPHandler
args = ('localhost', 'poser@localhost', ['root@localhost', 'other@localhost'], "[Poser] Logging")
formatter = generic
level = ERROR

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(funcName)s: %(message)s
datefmt = %Y-%m-%d %H:%M:%S

[formatter_console]
format = %(levelname)-5.5s [%(name)s][%(threadName)s] %(funcName)s: %(message)s