The MailingLogger Class

 MailingLogger is a handler for the python logging framework that
 sends log entries as email messages using an SMTP server.

 Parameter Reference

  All aspects of MailingLogger's behaviour are controlled by the
  parameters passed to the constructor, these are detailed below:

  fromaddr

    The address from which email log notifications will originate.

    This must be supplied.

  toaddrs

    A sequence of addresses to which email log notifications will be
    sent.

    This must be supplied.

  mailhost

    The SMTP server that should be used to send email notifications. 
  
    This can either be a string containing the hostname of the SMTP
    server or a tuple containing the hostname and port number of the
    SMTP server. If only the hostname is specified, it is assumed that
    the SMTP server is listening on port 25.

    default: ('localhost',25)

  username

    The username to use for SMTP authentication.

    If both username and password are supplied then SMTP login will
    be performed before any email is sent. Otherwise, no SMTP
    authentication will be performed. For performance reasons, it's
    recommended that you don't use SMTP authentication unless you
    absolutely need to.

  password

    The password to use for SMTP authentication.

    If both username and password are supplied then SMTP login will
    be performed before any email is sent. Otherwise, no SMTP
    authentication will be performed. For performance reasons, it's
    recommended that you don't use SMTP authentication unless you
    absolutely need to.

  subject 

    This is a format string specifying what information will be
    included in the subject line of the email notification.

    Information on what can be included in a subject format string can
    be found in docs/subjectformatter.txt

    default: '%(line)s'

  send_empty_entries

    This is a boolean parameter which specifies whether empty log
    entries will be mailed or not. 

    default: False

  flood_level

    This is an integer parameter specifying the maximum number of
    emails that can be sent in an hour that will not be considered a
    "flood". 

    When a "flood" is detected, one email is sent at the CRITICAL
    level indicating that a flood has been detected, and no more
    emails will be sent in the same hour.

    So, this option, in effect, specifies the maximum number of
    emails that will be sent in any particular hour of the day.

    default: 10

  ignore

    This sequence of strings, each of which is compiled into a regular
    expression, allows the user to set up rules for ignoring certain
    log entries. If the body of the message logged matched any of the
    regular expressions, the log message will be silently discarded
    and not mailed out.

    default: ()

  headers

    This is a dictionary containing headers and their values to be
    added to any emails sent.
   
    default: {}

  If you would like detailed examples of how to use MailingLogger,
  please see the examples below.

 Examples

  In its simplest form, we can instantiate and use MailingLogger as
  with any other logging handler:

  >>> import logging
  >>> from mailinglogger.MailingLogger import MailingLogger
  >>> handler = MailingLogger('from@example.com',('to@example.com',))
  >>> logging.getLogger('').addHandler(handler)
  >>> logging.error('my message')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: my message
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  my message

  From the above example, you can see that MailingLogger sends mail
  messages that are correctly formatted, including Date and Message-ID
  headers.

  You will also notice that an X-Mailer header has been added
  specifying that MailingLogger is the sender of the mail. This can be
  useful for filtering mail sent by MailingLogger.

  Now, to continue with the examples, just like any other handler, we
  can also set the logging level: 

  >>> handler.setLevel(logging.CRITICAL)
  >>> logging.error('my message')
  >>> handler.setLevel(logging.WARNING)
  >>> logging.warning('my message')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: my message
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  my message

  As you can see from the above examples, the subject line of the
  email sent is, by default, the first line of the message logged.

  This can be changed by supplying the 'subject' parameter when
  instantiating the handler object:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                         subject='[MyLogger] %(line)s')
  >>> logging.getLogger('').addHandler(handler)
  >>> logging.error('my %i message',13)
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: [MyLogger] my 13 message
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  my 13 message

  Also, by default, the MailingLogger handler will not send emails if
  they would have been empty:

  >>> logging.error(' ')

  However, if you want empty entries to be mailed anyway, all you need
  to do is supply the 'send_empty_entries' parameter:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                         send_empty_entries=True)
  >>> logging.getLogger('').addHandler(handler)
  >>> logging.error(' ')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: 
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  <BLANKLINE>
    
  Now, one problem that may be encountered with a logger that sends
  emails is that if you inadvertantly log a large number of entries
  that would result in mail being sent, you may cause problems with
  MTAs, mailbox quotas and the like.

  To prevent this, MailingLogger allows a limit on the number of
  entries sent per hour to be specified. By default, this is set to 10
  entries per hour. This can be overridden by passing the flood_level
  option to the MailingLogger constructor:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                         flood_level=1)
  >>> logging.getLogger('').addHandler(handler)

  To help show what happens, we'll 'stop time':

  >>> setTime('2007-01-01 10:00:00')

  Now we log a message as normal:

  >>> logging.error('An Error')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: An Error
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: Mon, 01 Jan 2007 10:00:00 -0000
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  An Error

  Once the flood level has been reached, a final warning message is
  sent:

  >>> logging.error('Another Error')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: Too Many Log Entries
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: Mon, 01 Jan 2007 10:00:00 -0000
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  Too Many Log Entries
  <BLANKLINE>
  More than 1 entries have been logged that would have resulted in
  emails being sent.
  <BLANKLINE>
  No further emails will be sent for log entries generated between
  10:00:00 and 11:00:00
  <BLANKLINE>
  Please consult any other configured logs, such as a File Logger,
  that may contain important entries that have not been emailed.
  <BLANKLINE>

  Any further messages logged will not result in an email being sent:

  >>> logging.error('Yet Another Error')

  However, once the clock has ticked over to a new hour, messages
  logged will once again be mailed:
  
  >>> setTime('2007-01-01 11:00:00')

  >>> logging.error('Yet Another Error')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: Yet Another Error
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: Mon, 01 Jan 2007 11:00:00 -0000
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  Yet Another Error

  Now that we've demonstrated how the email flood protection works, we
  can 'start time' again:

  >>> resumeTime()

  By default, as we've seen above, MailingLogger uses the local host
  to send mails. If you wish to use a specific smtp server to send
  mail, this can be done by specifying the 'mailhost' parameter to the
  MailingLogger constructor:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                         mailhost='smtp.example.com')
  >>> logging.getLogger('').addHandler(handler)
  >>> logging.error('An Error')
  sending to ('to@example.com',) from 'from@example.com' using ('smtp.example.com', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: An Error
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  An Error

  If the smtp server you wish to use is running on non-standard port,
  you can configure MailingLogger to use this port by specifying
  'mailhost' as a tuple containing the smtp server's hostname and the
  port on which it is listening:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                         mailhost=('smtp.example.com',2500))
  >>> logging.getLogger('').addHandler(handler)
  >>> logging.error('An Error')
  sending to ('to@example.com',) from 'from@example.com' using ('smtp.example.com', 2500)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: An Error
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  An Error

  If the smtp server you wish to use requires authentication,
  pass the required username and password to the MailingLogger
  constructor: 

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                         username='auser',password='theirpassword')
  >>> logging.getLogger('').addHandler(handler)
  >>> logging.error('An Error')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  (authenticated using username:'auser' and password:'theirpassword')
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: An Error
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  An Error

  For performance reasons, it's recommended that you don't use SMTP
  authentication unless you absolutely need to.

  In order to ignore certain log entries you can use the 'ignore' parameter:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                          ignore='^An Err')
  >>> logging.getLogger('').addHandler(handler)

  Now if the regular expression specified is matched, the log entry
  will not be sent:

  >>> logging.error('An Error')

  However, other log entries are still sent:

  >>> logging.error('The Error!')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  Subject: The Error!
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  The Error!

  A sequence of regular expressions to ignore can also be supplied:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('fromz@example.com',('toz@example.com',),
  ...                          ignore=('^An Err','Error!'))
  >>> logging.getLogger('').addHandler(handler)

  Now, anything matching any of the expressions will be ignored:

  >>> logging.error('An Error')
  >>> logging.error('The Error!')

  If you wish to add headers for filtering purposes, you can use the
  headers parameter:

  >>> logging.getLogger('').removeHandler(handler)
  >>> handler = MailingLogger('from@example.com',('to@example.com',),
  ...                             headers={'foo':'bar','Baz':'bob'})
  >>> logging.getLogger('').addHandler(handler)

  >>> logging.error('The Error!')
  sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
  Content-Type: text/plain; charset="us-ascii"
  MIME-Version: 1.0
  Content-Transfer-Encoding: 7bit
  foo: bar
  Baz: bob
  Subject: The Error!
  From: from@example.com
  To: to@example.com
  X-Mailer: MailingLogger ...
  Date: ...
  Message-ID: <...MailingLogger@...>
  <BLANKLINE>
  The Error!

