MailingLogger
Note
Throughout the examples below, mail messages sent using
smtplib
are printed to the screen so we can see what’s going on:
>>> import smtplib
>>> server = smtplib.SMTP('localhost')
>>> server.sendmail('from@example.com', ['to@example.com'], 'The message')
sending to ['to@example.com'] from 'from@example.com' using ('localhost', 25)
The message
MailingLogger
is a handler for the python logging framework that
sends log entries as email messages using an SMTP server. It is
configured as any other logging
handler would be, full details
of which can be found in the Python core documentation. For the
examples below, we’ll stick to manually configuring the logging
elements.
A MailingLogger
is instantiated as follows:
>>> from mailinglogger import MailingLogger
>>> handler = MailingLogger('from@example.com',('to@example.com',))
It can then be added as a handler for any logger as follows:
>>> import logging
>>> logger = logging.getLogger()
>>> logger.addHandler(handler)
Now, when that logger receives a message, an email containing the message will be sent:
>>> logging.error('my message')
sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: my message
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
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.
An X-Log-Level
header has also been added indicating the level of
the message that was logged. These can be useful for filtering mail
sent by MailingLogger
. If you wish to filter mail by
environment or other configuration data, the support for adding
extra headers may be useful.
Now, to continue with the examples, just like any other handler, we can also set the logging level, and messages logged below this level will not result in emails being sent:
>>> 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-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: my message
To: to@example.com
X-Log-Level: WARNING
X-Mailer: MailingLogger...
my message
Controlling the subject line
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:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... subject='[MyLogger] %(line)s')
>>> logger.addHandler(handler)
>>> logging.error('my %i message',13)
sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: [MyLogger] my 13 message
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
my 13 message
Full details of how the subject line can be formatted can be found in the SubjectFormatter documentation.
Sending empty emails
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:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... send_empty_entries=True)
>>> logger.addHandler(handler)
>>> logging.error(' ')
sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: ...
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
Limiting the number of emails sent
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:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... flood_level=1)
>>> logger.addHandler(handler)
With this setup, we can log at most one message:
>>> logging.error('An Error')
sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: Mon, 01 Jan 2007 10:00:00 -0000
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: An Error
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
An Error
Now that the flood level has been reached, a final warning message is sent if any more messages are logged:
>>> logging.error('Another Error')
sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: Mon, 01 Jan 2007 10:00:00 -0000
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: Too Many Log Entries
To: to@example.com
X-Log-Level: CRITICAL
X-Mailer: MailingLogger...
Too Many Log Entries
More than 1 entries have been logged that would have resulted in
emails being sent.
No further emails will be sent for log entries generated between
10:00:00 and 11:00:00
Please consult any other configured logs, such as a File Logger,
that may contain important entries that have not been emailed.
Any further messages logged will not result in an email being sent:
>>> logging.error('Yet Another Error')
Specifying the host to send email through
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:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... mailhost='smtp.example.com')
>>> logger.addHandler(handler)
>>> logging.error('An Error')
sending to ('to@example.com',) from 'from@example.com' using ('smtp.example.com', 25)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: An Error
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
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:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... mailhost=('smtp.example.com',2500))
>>> logger.addHandler(handler)
>>> logging.error('An Error')
sending to ('to@example.com',) from 'from@example.com' using ('smtp.example.com', 2500)
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: An Error
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
An Error
If the smtp server you wish to use requires authentication,
pass the required username and password to the MailingLogger
constructor:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... username='auser',password='theirpassword')
>>> logger.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-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: An Error
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
An Error
Warning
For performance reasons, it’s recommended that you don’t use SMTP authentication unless you absolutely need to.
If the smtp server you wish to use requires TLS (Transport Level Security),
pass the required username and password and the secure parameter to the
MailingLogger
constructor. secure
must be an empty tuple or
contain one or two members. See the smtplib documentation for details:
>>> handler = MailingLogger('from@example.com',('to@example.com',),
... username='auser',password='theirpassword',
... secure=())
>>> logger.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-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: An Error
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger...
An Error
Adding extra headers
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'})
>>> logger.addHandler(handler)
Now, when a log message results in an email being send, the email will be sent with the configured headers:
>>> logging.error('The Error!')
sending to ('to@example.com',) from 'from@example.com' using ('localhost', 25)
Baz: bob
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"
Date: ...
From: from@example.com
MIME-Version: 1.0
Message-ID: <...MailingLogger@...>
Subject: The Error!
To: to@example.com
X-Log-Level: ERROR
X-Mailer: MailingLogger ...
foo: bar
The Error!