.. currentmodule:: mailinglogger

SubjectFormatter
================

A :class:`~mailinglogger.common.SubjectFormatter` is a
special type of `logging formatter`__ that is
created from the `subject` parameter to the constuctor of a
:class:`MailingLogger` or :class:`SummarisingLogger`.
It is tailored for formatting a log record to form the subject
line of an email message.

__ http://docs.python.org/library/logging.html#formatter-objects

As can be seen below,
:class:`~mailinglogger.common.SubjectFormatter` supports all
the usual keyword substitutions supported by normal Formatter objects:

>>> from mailinglogger.common import SubjectFormatter
>>> formatter = SubjectFormatter('''
... %(name)r
... %(levelno)r
... %(levelname)r
... %(pathname)r
... %(filename)r
... %(module)r
... %(lineno)d
... %(created)f
... %(asctime)r
... %(msecs)d
... %(relativeCreated)f
... %(thread)d
... %(process)d
... %(message)r
... ''',None)

To show this in action, we can instantiate a log record and then
format it with our formatter:

>>> from logging import LogRecord
>>> record = LogRecord(name='aname', 
...               level=10, 
...               pathname='somepath.py', 
...               lineno=123,
...               msg='msgline%i\nmsgline%i',
...               args=(1,2), 
...               exc_info=None)
>>> print(formatter.format(record))
<BLANKLINE>
'aname'
10
'DEBUG'
'somepath.py'
'somepath.py'
'somepath'
123
1167645600.000000
'2007-01-01 10:00:00,000'
0
...
...
...
'msgline1\nmsgline2'
<BLANKLINE>

The example above, however, would not generate a valid email, as
the subject line would contain newlines. For this reason, an
additional keyword substitution is provided that is computed to be the
first line of any message logged:

>>> f = SubjectFormatter('%(line)r')

We can now see how this formatter represents the log record
generated previously:

>>> print(f.format(record))
'msgline1'

As you can see, this only includes the first line of the message
logged making it ideal for use in the generation of email subject
lines.

Again, in order to prevent multi-line subjects, any exception
information provided in a logging call is not added to the end of
the subject line. This can be seen by creating a log entry as it would
be by the python logging framework when an exception is logged:

>>> import sys
>>> try:
...     raise RuntimeException('something bad happened')
... except:
...     exc_info = sys.exc_info()
>>> record = LogRecord(name='aname', 
...               level=10, 
...               pathname='somepath.py', 
...               lineno=123,
...               msg='bad things caught',
...               args=(), 
...               exc_info=exc_info)

Normally, a logging formatter would include a traceback when
representing this entry:

>>> from logging import Formatter
>>> print(Formatter().format(record))
bad things caught
Traceback (most recent call last):
  File "...", line 2, in <module>
NameError: name 'RuntimeException' is not defined

However, if we use the subject formatter we previously created,
the log entry is formatted as follows:

>>> print(f.format(record))
'bad things caught'

To aid administration where the same python software runs
on a cluster of machines, the hostname of the machine from which
the message is logged can also be easilly included:

>>> f = SubjectFormatter('[%(hostname)s] %(line)r')
>>> print(f.format(record))
[host.example.com] 'bad things caught'

Available LogRecord attributes
------------------------------

The attributes of the :class:`~logging.LogRecord` control what can be
included in the format string of any :class:`~logging.Formatter`
including :class:`~mailinglogger.common.SubjectFormatter`.
The `LogRecord attributes`__ documentation gives full details of all
of these attributes, but the following table shows the ones added by 
:class:`~mailinglogger.common.SubjectFormatter`:

__ http://docs.python.org/library/logging.html#logrecord-attributes

+----------------+------------------+----------------------------------+
| Attribute name | Format           | Description                      |
+================+==================+==================================+
| line           | ``%(line)s``     | The first line of the message    |
|                |                  | that was logged.                 |
+----------------+------------------+----------------------------------+
| hostname       | ``%(hostname)s`` | The hostname of the machine from |
|                |                  | which the message is logged.     |
+----------------+------------------+----------------------------------+
