Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6b883a2

Browse files
committed
Updated logging cookbook with info on alternative format styles.
1 parent f12b447 commit 6b883a2

1 file changed

Lines changed: 132 additions & 4 deletions

File tree

Doc/howto/logging-cookbook.rst

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,12 @@ Dealing with handlers that block
268268
.. currentmodule:: logging.handlers
269269

270270
Sometimes you have to get your logging handlers to do their work without
271-
blocking the thread youre logging from. This is common in Web applications,
271+
blocking the thread you're logging from. This is common in Web applications,
272272
though of course it also occurs in other scenarios.
273273

274274
A common culprit which demonstrates sluggish behaviour is the
275275
:class:`SMTPHandler`: sending emails can take a long time, for a
276-
number of reasons outside the developers control (for example, a poorly
276+
number of reasons outside the developer's control (for example, a poorly
277277
performing mail or network infrastructure). But almost any network-based
278278
handler can block: Even a :class:`SocketHandler` operation may do a
279279
DNS query under the hood which is too slow (and this query can be deep in the
@@ -292,7 +292,7 @@ developers who will use your code.
292292

293293
The second part of the solution is :class:`QueueListener`, which has been
294294
designed as the counterpart to :class:`QueueHandler`. A
295-
:class:`QueueListener` is very simple: its passed a queue and some handlers,
295+
:class:`QueueListener` is very simple: it's passed a queue and some handlers,
296296
and it fires up an internal thread which listens to its queue for LogRecords
297297
sent from ``QueueHandlers`` (or any other source of ``LogRecords``, for that
298298
matter). The ``LogRecords`` are removed from the queue and passed to the
@@ -745,7 +745,7 @@ the basis for code meeting your own specific requirements::
745745
raise
746746
except:
747747
import sys, traceback
748-
print >> sys.stderr, 'Whoops! Problem:'
748+
print('Whoops! Problem:', file=sys.stderr)
749749
traceback.print_exc(file=sys.stderr)
750750

751751
# Arrays used for random selections in this demo
@@ -964,6 +964,134 @@ and each time it reaches the size limit it is renamed with the suffix
964964
Obviously this example sets the log length much too small as an extreme
965965
example. You would want to set *maxBytes* to an appropriate value.
966966

967+
.. _format-styles:
968+
969+
Use of alternative formatting styles
970+
------------------------------------
971+
972+
When logging was added to the Python standard library, the only way of
973+
formatting messages with variable content was to use the %-formatting
974+
method. Since then, Python has gained two new formatting approaches:
975+
string.Template (added in Python 2.4) and str.format (added in Python 2.6).
976+
977+
Logging now (as of 3.2) provides improved support for these two additional
978+
formatting styles. The :class:`Formatter` class been enhanced for Python 3.2 to
979+
take an additional, optional keyword parameter named ``style``. This defaults
980+
to ``'%'``, but other possible values are ``'{'`` and ``'$'``, which correspond
981+
to the other two formatting styles. Backwards compatibility is maintained by
982+
default (as you would expect), but by explicitly specifying a style parameter,
983+
you get the ability to specify format strings which work with
984+
:meth:`str.format` or :class:`string.Template`. Here's an example console
985+
session to show the possibilities:
986+
987+
.. code-block:: pycon
988+
989+
>>> import logging
990+
>>> root = logging.getLogger()
991+
>>> root.setLevel(logging.DEBUG)
992+
>>> handler = logging.StreamHandler()
993+
>>> bf = logging.Formatter('{asctime} {name} {levelname:8s} {message}',
994+
... style='{')
995+
>>> handler.setFormatter(bf)
996+
>>> root.addHandler(handler)
997+
>>> logger = logging.getLogger('foo.bar')
998+
>>> logger.debug('This is a DEBUG message')
999+
2010-10-28 15:11:55,341 foo.bar DEBUG This is a DEBUG message
1000+
>>> logger.critical('This is a CRITICAL message')
1001+
2010-10-28 15:12:11,526 foo.bar CRITICAL This is a CRITICAL message
1002+
>>> df = logging.Formatter('$asctime $name ${levelname} $message',
1003+
... style='$')
1004+
>>> handler.setFormatter(df)
1005+
>>> logger.debug('This is a DEBUG message')
1006+
2010-10-28 15:13:06,924 foo.bar DEBUG This is a DEBUG message
1007+
>>> logger.critical('This is a CRITICAL message')
1008+
2010-10-28 15:13:11,494 foo.bar CRITICAL This is a CRITICAL message
1009+
>>>
1010+
1011+
Note that the formatting of logging messages for final output to logs is
1012+
completely independent of how an individual logging message is constructed.
1013+
That can still use %-formatting, as shown here::
1014+
1015+
>>> logger.error('This is an%s %s %s', 'other,', 'ERROR,', 'message')
1016+
2010-10-28 15:19:29,833 foo.bar ERROR This is another, ERROR, message
1017+
>>>
1018+
1019+
Logging calls (``logger.debug()``, ``logger.info()`` etc.) only take
1020+
positional parameters for the actual logging message itself, with keyword
1021+
parameters used only for determining options for how to handle the actual
1022+
logging call (e.g. the ``exc_info`` keyword parameter to indicate that
1023+
traceback information should be logged, or the ``extra`` keyword parameter
1024+
to indicate additional contextual information to be added to the log). So
1025+
you cannot directly make logging calls using :meth:`str.format` or
1026+
:class:`string.Template` syntax, because internally the logging package
1027+
uses %-formatting to merge the format string and the variable arguments.
1028+
There would no changing this while preserving backward compatibility, since
1029+
all logging calls which are out there in existing code will be using %-format
1030+
strings.
1031+
1032+
There is, however, a way that you can use {}- and $- formatting to construct
1033+
your individual log messages. Recall that for a message you can use an
1034+
arbitrary object as a message format string, and that the logging package will
1035+
call ``str()`` on that object to get the actual format string. Consider the
1036+
following two classes::
1037+
1038+
class BraceMessage(object):
1039+
def __init__(self, fmt, *args, **kwargs):
1040+
self.fmt = fmt
1041+
self.args = args
1042+
self.kwargs = kwargs
1043+
1044+
def __str__(self):
1045+
return self.fmt.format(*self.args, **self.kwargs)
1046+
1047+
class DollarMessage(object):
1048+
def __init__(self, fmt, **kwargs):
1049+
self.fmt = fmt
1050+
self.kwargs = kwargs
1051+
1052+
def __str__(self):
1053+
from string import Template
1054+
return Template(self.fmt).substitute(**self.kwargs)
1055+
1056+
Either of these can be used in place of a format string, to allow {}- or
1057+
$-formatting to be used to build the actual "message" part which appears in the
1058+
formatted log output in place of "%(message)s" or "{message}" or "$message".
1059+
It's a little unwieldy to use the class names whenever you want to log
1060+
something, but it's quite palatable if you use an alias such as __ (double
1061+
underscore – not to be confused with _, the single underscore used as a
1062+
synonym/alias for :func:`gettext.gettext` or its brethren).
1063+
1064+
The above classes are not included in Python, though they're easy enough to
1065+
copy and paste into your own code. They can be used as follows (assuming that
1066+
they're declared in a module called ``wherever``):
1067+
1068+
.. code-block:: pycon
1069+
1070+
>>> from wherever import BraceMessage as __
1071+
>>> print(__('Message with {0} {1}', 2, 'placeholders'))
1072+
Message with 2 placeholders
1073+
>>> class Point: pass
1074+
...
1075+
>>> p = Point()
1076+
>>> p.x = 0.5
1077+
>>> p.y = 0.5
1078+
>>> print(__('Message with coordinates: ({point.x:.2f}, {point.y:.2f})',
1079+
... point=p))
1080+
Message with coordinates: (0.50, 0.50)
1081+
>>> from wherever import DollarMessage as __
1082+
>>> print(__('Message with $num $what', num=2, what='placeholders'))
1083+
Message with 2 placeholders
1084+
>>>
1085+
1086+
One thing to note is that you pay no significant performance penalty with this
1087+
approach: the actual formatting happens not when you make the logging call, but
1088+
when (and if) the logged message is actually about to be output to a log by a
1089+
handler. So the only slightly unusual thing which might trip you up is that the
1090+
parentheses go around the format string and the arguments, not just the format
1091+
string. That's because the __ notation is just syntax sugar for a constructor
1092+
call to one of the XXXMessage classes.
1093+
1094+
9671095
.. _zeromq-handlers:
9681096

9691097
Subclassing QueueHandler - a ZeroMQ example

0 commit comments

Comments
 (0)