Logging documentation update.

This commit is contained in:
Vinay Sajip 2010-12-14 19:40:21 +00:00
parent 31d04f2183
commit 9a6b400a59
1 changed files with 159 additions and 154 deletions

View File

@ -42,32 +42,33 @@ states, for each of a set of common tasks, the best tool to use for it.
+-------------------------------------+--------------------------------------+ +-------------------------------------+--------------------------------------+
| Task you want to perform | The best tool for the task | | Task you want to perform | The best tool for the task |
+=====================================+======================================+ +=====================================+======================================+
| Display console output for ordinary | print() | | Display console output for ordinary | :func:`print` |
| usage of a command line script or | | | usage of a command line script or | |
| program | | | program | |
+-------------------------------------+--------------------------------------+ +-------------------------------------+--------------------------------------+
| Report events that occur during | logging.info() (or logging.debug() | | Report events that occur during | :func:`logging.info` (or |
| normal operation of a program (e.g. | for very detailed output for | | normal operation of a program (e.g. | :func:`logging.debug` for very |
| for status monitoring or fault | diagnostic purposes) | | for status monitoring or fault | detailed output for diagnostic |
| investigation) | | | investigation) | purposes) |
+-------------------------------------+--------------------------------------+ +-------------------------------------+--------------------------------------+
| Issue a warning regarding a | warnings.warn() in library code | | Issue a warning regarding a | :func:`warnings.warn` in library |
| particular runtime event | if the issue is avoidable and the | | particular runtime event | code if the issue is avoidable and |
| | client application should be | | | the client application should be |
| | modified to eliminate the warning | | | modified to eliminate the warning |
| | | | | |
| | logging.warn() if there is nothing | | | :func:`logging.warning` if there is |
| | the client application can do about | | | nothing the client application can do|
| | the situation, but the event should | | | about the situation, but the event |
| | still be noted | | | should still be noted |
+-------------------------------------+--------------------------------------+ +-------------------------------------+--------------------------------------+
| Report an error regarding a | Raise an exception | | Report an error regarding a | Raise an exception |
| particular runtime event | | | particular runtime event | |
+-------------------------------------+--------------------------------------+ +-------------------------------------+--------------------------------------+
| Report suppression of an error | logging.error(), logging.exception(),| | Report suppression of an error | :func:`logging.error`, |
| without raising an exception (e.g. | or logging.critical() as appropriate | | without raising an exception (e.g. | :func:`logging.exception` or |
| error handler in a long-running | for the specific error and | | error handler in a long-running | :func:`logging.critical` as |
| server process) | application domain | | server process) | appropriate for the specific error |
| | and application domain |
+-------------------------------------+--------------------------------------+ +-------------------------------------+--------------------------------------+
The logging functions are named after the level or severity of the events The logging functions are named after the level or severity of the events
@ -85,7 +86,7 @@ described below (in increasing order of severity):
+--------------+---------------------------------------------+ +--------------+---------------------------------------------+
| ``WARNING`` | An indication that something unexpected | | ``WARNING`` | An indication that something unexpected |
| | happened, or indicative of some problem in | | | happened, or indicative of some problem in |
| | the near future (e.g. "disk space low"). | | | the near future (e.g. 'disk space low'). |
| | The software is still working as expected. | | | The software is still working as expected. |
+--------------+---------------------------------------------+ +--------------+---------------------------------------------+
| ``ERROR`` | Due to a more serious problem, the software | | ``ERROR`` | Due to a more serious problem, the software |
@ -214,7 +215,7 @@ could organize logging in it::
def do_something(): def do_something():
logging.info('Doing something') logging.info('Doing something')
If you run myapp.py, you should see this in myapp.log:: If you run *myapp.py*, you should see this in *myapp.log*::
INFO:root:Started INFO:root:Started
INFO:root:Doing something INFO:root:Doing something
@ -279,7 +280,7 @@ described in the next section.
Displaying the date/time in messages Displaying the date/time in messages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To display the date and time of an event, you would place "%(asctime)s" in To display the date and time of an event, you would place '%(asctime)s' in
your format string:: your format string::
import logging import logging
@ -337,17 +338,20 @@ More advanced logging
--------------------- ---------------------
The logging library takes a modular approach and offers several categories The logging library takes a modular approach and offers several categories
of components: loggers, handlers, filters, and formatters. Loggers expose the of components: loggers, handlers, filters, and formatters.
interface that application code directly uses. Handlers send the log records
(created by loggers) to the appropriate destination. Filters provide a finer * Loggers expose the interface that application code directly uses.
grained facility for determining which log records to output. Formatters * Handlers send the log records (created by loggers) to the appropriate
specify the layout of the resultant log record in the final output. destination.
* Filters provide a finer grained facility for determining which log records
to output.
* Formatters specify the layout of log records in the final output.
Logging is performed by calling methods on instances of the :class:`Logger` Logging is performed by calling methods on instances of the :class:`Logger`
class (hereafter called :dfn:`loggers`). Each instance has a name, and they are class (hereafter called :dfn:`loggers`). Each instance has a name, and they are
conceptually arranged in a namespace hierarchy using dots (periods) as conceptually arranged in a namespace hierarchy using dots (periods) as
separators. For example, a logger named "scan" is the parent of loggers separators. For example, a logger named 'scan' is the parent of loggers
"scan.text", "scan.html" and "scan.pdf". Logger names can be anything you want, 'scan.text', 'scan.html' and 'scan.pdf'. Logger names can be anything you want,
and indicate the area of an application in which a logged message originates. and indicate the area of an application in which a logged message originates.
A good convention to use when naming loggers is to use a module-level logger, A good convention to use when naming loggers is to use a module-level logger,
@ -365,11 +369,11 @@ the root logger. The functions and the methods have the same signatures. The
root logger's name is printed as 'root' in the logged output. root logger's name is printed as 'root' in the logged output.
It is, of course, possible to log messages to different destinations. Support It is, of course, possible to log messages to different destinations. Support
for writing log messages to files, HTTP GET/POST locations, email via SMTP, is included in the package for writing log messages to files, HTTP GET/POST
generic sockets, or OS-specific logging mechanisms is included in the package. locations, email via SMTP, generic sockets, queues, or OS-specific logging
Destinations are served by :dfn:`handler` classes. You can create your own log mechanisms such as syslog or the Windows NT event log. Destinations are served
destination class if you have special requirements not met by any of the by :dfn:`handler` classes. You can create your own log destination class if
built-in handler classes. you have special requirements not met by any of the built-in handler classes.
By default, no destination is set for any logging messages. You can specify By default, no destination is set for any logging messages. You can specify
a destination (such as console or file) by using :func:`basicConfig` as in the a destination (such as console or file) by using :func:`basicConfig` as in the
@ -537,7 +541,7 @@ The following message format string will log the time in a human-readable
format, the severity of the message, and the contents of the message, in that format, the severity of the message, and the contents of the message, in that
order:: order::
"%(asctime)s - %(levelname)s - %(message)s" '%(asctime)s - %(levelname)s - %(message)s'
Formatters use a user-configurable function to convert the creation time of a Formatters use a user-configurable function to convert the creation time of a
record to a tuple. By default, :func:`time.localtime` is used; to change this record to a tuple. By default, :func:`time.localtime` is used; to change this
@ -566,7 +570,7 @@ handler, and a simple formatter using Python code::
import logging import logging
# create logger # create logger
logger = logging.getLogger("simple_example") logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
# create console handler and set level to debug # create console handler and set level to debug
@ -574,7 +578,7 @@ handler, and a simple formatter using Python code::
ch.setLevel(logging.DEBUG) ch.setLevel(logging.DEBUG)
# create formatter # create formatter
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch # add formatter to ch
ch.setFormatter(formatter) ch.setFormatter(formatter)
@ -582,12 +586,12 @@ handler, and a simple formatter using Python code::
# add ch to logger # add ch to logger
logger.addHandler(ch) logger.addHandler(ch)
# "application" code # 'application' code
logger.debug("debug message") logger.debug('debug message')
logger.info("info message") logger.info('info message')
logger.warn("warn message") logger.warn('warn message')
logger.error("error message") logger.error('error message')
logger.critical("critical message") logger.critical('critical message')
Running this module from the command line produces the following output:: Running this module from the command line produces the following output::
@ -605,17 +609,17 @@ the names of the objects::
import logging import logging
import logging.config import logging.config
logging.config.fileConfig("logging.conf") logging.config.fileConfig('logging.conf')
# create logger # create logger
logger = logging.getLogger("simpleExample") logger = logging.getLogger('simpleExample')
# "application" code # 'application' code
logger.debug("debug message") logger.debug('debug message')
logger.info("info message") logger.info('info message')
logger.warn("warn message") logger.warn('warn message')
logger.error("error message") logger.error('error message')
logger.critical("critical message") logger.critical('critical message')
Here is the logging.conf file:: Here is the logging.conf file::
@ -720,11 +724,11 @@ For versions of Python prior to 3.2, the behaviour is as follows:
silently dropped. silently dropped.
* If *logging.raiseExceptions* is *True* (development mode), a message * If *logging.raiseExceptions* is *True* (development mode), a message
"No handlers could be found for logger X.Y.Z" is printed once. 'No handlers could be found for logger X.Y.Z' is printed once.
In Python 3.2 and later, the behaviour is as follows: In Python 3.2 and later, the behaviour is as follows:
* The event is output using a 'handler of last resort", stored in * The event is output using a 'handler of last resort', stored in
``logging.lastResort``. This internal handler is not associated with any ``logging.lastResort``. This internal handler is not associated with any
logger, and acts like a :class:`StreamHandler` which writes the event logger, and acts like a :class:`StreamHandler` which writes the event
description message to the current value of ``sys.stderr`` (therefore description message to the current value of ``sys.stderr`` (therefore
@ -776,7 +780,7 @@ than* :class:`NullHandler` *to your library's loggers*. This is because the
configuration of handlers is the prerogative of the application developer who configuration of handlers is the prerogative of the application developer who
uses your library. The application developer knows their target audience and uses your library. The application developer knows their target audience and
what handlers are most appropriate for their application: if you add handlers what handlers are most appropriate for their application: if you add handlers
"under the hood", you might well interfere with their ability to carry out 'under the hood', you might well interfere with their ability to carry out
unit tests and deliver logs which suit their requirements. unit tests and deliver logs which suit their requirements.
@ -910,8 +914,8 @@ provided:
.. currentmodule:: logging .. currentmodule:: logging
#. :class:`NullHandler` instances do nothing with error messages. They are used #. :class:`NullHandler` instances do nothing with error messages. They are used
by library developers who want to use logging, but want to avoid the "No by library developers who want to use logging, but want to avoid the 'No
handlers could be found for logger XXX" message which can be displayed if handlers could be found for logger XXX' message which can be displayed if
the library user has not configured logging. See :ref:`library-config` for the library user has not configured logging. See :ref:`library-config` for
more information. more information.
@ -957,7 +961,7 @@ functions.
Return a logger with the specified name or, if name is ``None``, return a Return a logger with the specified name or, if name is ``None``, return a
logger which is the root logger of the hierarchy. If specified, the name is logger which is the root logger of the hierarchy. If specified, the name is
typically a dot-separated hierarchical name like *"a"*, *"a.b"* or *"a.b.c.d"*. typically a dot-separated hierarchical name like *'a'*, *'a.b'* or *'a.b.c.d'*.
Choice of these names is entirely up to the developer who is using logging. Choice of these names is entirely up to the developer who is using logging.
All calls to this function with a given name return the same logger instance. All calls to this function with a given name return the same logger instance.
@ -1025,10 +1029,10 @@ functions.
be used as you like. For example, they could be incorporated into logged be used as you like. For example, they could be incorporated into logged
messages. For example:: messages. For example::
FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s" FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT) logging.basicConfig(format=FORMAT)
d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
logging.warning("Protocol problem: %s", "connection reset", extra=d) logging.warning('Protocol problem: %s', 'connection reset', extra=d)
would print something like:: would print something like::
@ -1130,7 +1134,7 @@ functions.
have associated levels with names using :func:`addLevelName` then the name you have associated levels with names using :func:`addLevelName` then the name you
have associated with *lvl* is returned. If a numeric value corresponding to one have associated with *lvl* is returned. If a numeric value corresponding to one
of the defined levels is passed in, the corresponding string representation is of the defined levels is passed in, the corresponding string representation is
returned. Otherwise, the string "Level %s" % lvl is returned. returned. Otherwise, the string 'Level %s' % lvl is returned.
.. function:: makeLogRecord(attrdict) .. function:: makeLogRecord(attrdict)
@ -1225,7 +1229,7 @@ functions.
The factory has the following signature: The factory has the following signature:
``factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, \*\*kwargs)`` ``factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, **kwargs)``
:name: The logger name. :name: The logger name.
:level: The logging level (numeric). :level: The logging level (numeric).
@ -1279,7 +1283,7 @@ instantiated directly, but always through the module-level function
the root logger, or delegation to the parent when the logger is a non-root the root logger, or delegation to the parent when the logger is a non-root
logger). Note that the root logger is created with level :const:`WARNING`. logger). Note that the root logger is created with level :const:`WARNING`.
The term "delegation to the parent" means that if a logger has a level of The term 'delegation to the parent' means that if a logger has a level of
NOTSET, its chain of ancestor loggers is traversed until either an ancestor with NOTSET, its chain of ancestor loggers is traversed until either an ancestor with
a level other than NOTSET is found, or the root is reached. a level other than NOTSET is found, or the root is reached.
@ -1355,11 +1359,11 @@ instantiated directly, but always through the module-level function
be used as you like. For example, they could be incorporated into logged be used as you like. For example, they could be incorporated into logged
messages. For example:: messages. For example::
FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s" FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
logging.basicConfig(format=FORMAT) logging.basicConfig(format=FORMAT)
d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' } d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
logger = logging.getLogger("tcpserver") logger = logging.getLogger('tcpserver')
logger.warning("Protocol problem: %s", "connection reset", extra=d) logger.warning('Protocol problem: %s', 'connection reset', extra=d)
would print something like :: would print something like ::
@ -1475,7 +1479,7 @@ instantiated directly, but always through the module-level function
Checks to see if this logger has any handlers configured. This is done by Checks to see if this logger has any handlers configured. This is done by
looking for handlers in this logger and its parents in the logger hierarchy. looking for handlers in this logger and its parents in the logger hierarchy.
Returns True if a handler was found, else False. The method stops searching Returns True if a handler was found, else False. The method stops searching
up the hierarchy whenever a logger with the "propagate" attribute set to up the hierarchy whenever a logger with the 'propagate' attribute set to
False is found - that will be the last logger which is checked for the False is found - that will be the last logger which is checked for the
existence of handlers. existence of handlers.
@ -1549,7 +1553,7 @@ documentation.
+-------------------+-----------------------------------------------+ +-------------------+-----------------------------------------------+
| ``%(asctime)s`` | Human-readable time when the | | ``%(asctime)s`` | Human-readable time when the |
| | :class:`LogRecord` was created. By default | | | :class:`LogRecord` was created. By default |
| | this is of the form "2003-07-08 16:49:45,896" | | | this is of the form '2003-07-08 16:49:45,896' |
| | (the numbers after the comma are millisecond | | | (the numbers after the comma are millisecond |
| | portion of the time). | | | portion of the time). |
+-------------------+-----------------------------------------------+ +-------------------+-----------------------------------------------+
@ -1705,7 +1709,7 @@ show up at different levels::
You will notice that these log messages all have ``root`` embedded in them. The You will notice that these log messages all have ``root`` embedded in them. The
logging module supports a hierarchy of loggers with different names. An easy logging module supports a hierarchy of loggers with different names. An easy
way to tell where a specific log message comes from is to use a separate logger way to tell where a specific log message comes from is to use a separate logger
object for each of your modules. Each new logger "inherits" the configuration object for each of your modules. Each new logger 'inherits' the configuration
of its parent, and log messages sent to a logger include the name of that of its parent, and log messages sent to a logger include the name of that
logger. Optionally, each logger can be configured differently, so that messages logger. Optionally, each logger can be configured differently, so that messages
from different modules are handled in different ways. Let's look at a simple from different modules are handled in different ways. Let's look at a simple
@ -1873,11 +1877,11 @@ information is added to the logging output. It's passed the message and
keyword arguments of the logging call, and it passes back (potentially) keyword arguments of the logging call, and it passes back (potentially)
modified versions of these to use in the call to the underlying logger. The modified versions of these to use in the call to the underlying logger. The
default implementation of this method leaves the message alone, but inserts default implementation of this method leaves the message alone, but inserts
an "extra" key in the keyword argument whose value is the dict-like object an 'extra' key in the keyword argument whose value is the dict-like object
passed to the constructor. Of course, if you had passed an "extra" keyword passed to the constructor. Of course, if you had passed an 'extra' keyword
argument in the call to the adapter, it will be silently overwritten. argument in the call to the adapter, it will be silently overwritten.
The advantage of using "extra" is that the values in the dict-like object are The advantage of using 'extra' is that the values in the dict-like object are
merged into the :class:`LogRecord` instance's __dict__, allowing you to use merged into the :class:`LogRecord` instance's __dict__, allowing you to use
customized strings with your :class:`Formatter` instances which know about customized strings with your :class:`Formatter` instances which know about
the keys of the dict-like object. If you need a different method, e.g. if you the keys of the dict-like object. If you need a different method, e.g. if you
@ -1885,7 +1889,7 @@ want to prepend or append the contextual information to the message string,
you just need to subclass :class:`LoggerAdapter` and override :meth:`process` you just need to subclass :class:`LoggerAdapter` and override :meth:`process`
to do what you need. Here's an example script which uses this class, which to do what you need. Here's an example script which uses this class, which
also illustrates what dict-like behaviour is needed from an arbitrary also illustrates what dict-like behaviour is needed from an arbitrary
"dict-like" object for use in the constructor:: 'dict-like' object for use in the constructor::
import logging import logging
@ -1900,12 +1904,12 @@ also illustrates what dict-like behaviour is needed from an arbitrary
To allow this instance to look like a dict. To allow this instance to look like a dict.
""" """
from random import choice from random import choice
if name == "ip": if name == 'ip':
result = choice(["127.0.0.1", "192.168.0.1"]) result = choice(['127.0.0.1', '192.168.0.1'])
elif name == "user": elif name == 'user':
result = choice(["jim", "fred", "sheila"]) result = choice(['jim', 'fred', 'sheila'])
else: else:
result = self.__dict__.get(name, "?") result = self.__dict__.get(name, '?')
return result return result
def __iter__(self): def __iter__(self):
@ -1913,24 +1917,24 @@ also illustrates what dict-like behaviour is needed from an arbitrary
To allow iteration over keys, which will be merged into To allow iteration over keys, which will be merged into
the LogRecord dict before formatting and output. the LogRecord dict before formatting and output.
""" """
keys = ["ip", "user"] keys = ['ip', 'user']
keys.extend(self.__dict__.keys()) keys.extend(self.__dict__.keys())
return keys.__iter__() return keys.__iter__()
if __name__ == "__main__": if __name__ == '__main__':
from random import choice from random import choice
levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"), a1 = logging.LoggerAdapter(logging.getLogger('a.b.c'),
{ "ip" : "123.231.231.123", "user" : "sheila" }) { 'ip' : '123.231.231.123', 'user' : 'sheila' })
logging.basicConfig(level=logging.DEBUG, logging.basicConfig(level=logging.DEBUG,
format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s") format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s')
a1.debug("A debug message") a1.debug('A debug message')
a1.info("An info message with %s", "some parameters") a1.info('An info message with %s', 'some parameters')
a2 = logging.LoggerAdapter(logging.getLogger("d.e.f"), ConnInfo()) a2 = logging.LoggerAdapter(logging.getLogger('d.e.f'), ConnInfo())
for x in range(10): for x in range(10):
lvl = choice(levels) lvl = choice(levels)
lvlname = logging.getLevelName(lvl) lvlname = logging.getLevelName(lvl)
a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters") a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')
When this script is run, the output should look something like this:: When this script is run, the output should look something like this::
@ -1987,24 +1991,24 @@ script::
record.user = choice(ContextFilter.USERS) record.user = choice(ContextFilter.USERS)
return True return True
if __name__ == "__main__": if __name__ == '__main__':
levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"), a1 = logging.LoggerAdapter(logging.getLogger('a.b.c'),
{ "ip" : "123.231.231.123", "user" : "sheila" }) { 'ip' : '123.231.231.123', 'user' : 'sheila' })
logging.basicConfig(level=logging.DEBUG, logging.basicConfig(level=logging.DEBUG,
format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s") format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s')
a1 = logging.getLogger("a.b.c") a1 = logging.getLogger('a.b.c')
a2 = logging.getLogger("d.e.f") a2 = logging.getLogger('d.e.f')
f = ContextFilter() f = ContextFilter()
a1.addFilter(f) a1.addFilter(f)
a2.addFilter(f) a2.addFilter(f)
a1.debug("A debug message") a1.debug('A debug message')
a1.info("An info message with %s", "some parameters") a1.info('An info message with %s', 'some parameters')
for x in range(10): for x in range(10):
lvl = choice(levels) lvl = choice(levels)
lvlname = logging.getLevelName(lvl) lvlname = logging.getLevelName(lvl)
a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters") a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')
which, when run, produces something like:: which, when run, produces something like::
@ -2231,7 +2235,7 @@ module. Here is a basic working example::
chunk = self.connection.recv(4) chunk = self.connection.recv(4)
if len(chunk) < 4: if len(chunk) < 4:
break break
slen = struct.unpack(">L", chunk)[0] slen = struct.unpack('>L', chunk)[0]
chunk = self.connection.recv(slen) chunk = self.connection.recv(slen)
while len(chunk) < slen: while len(chunk) < slen:
chunk = chunk + self.connection.recv(slen - len(chunk)) chunk = chunk + self.connection.recv(slen - len(chunk))
@ -2257,7 +2261,8 @@ module. Here is a basic working example::
logger.handle(record) logger.handle(record)
class LogRecordSocketReceiver(socketserver.ThreadingTCPServer): class LogRecordSocketReceiver(socketserver.ThreadingTCPServer):
"""simple TCP socket-based logging receiver suitable for testing. """
Simple TCP socket-based logging receiver suitable for testing.
""" """
allow_reuse_address = 1 allow_reuse_address = 1
@ -2283,12 +2288,12 @@ module. Here is a basic working example::
def main(): def main():
logging.basicConfig( logging.basicConfig(
format="%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s") format='%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s')
tcpserver = LogRecordSocketReceiver() tcpserver = LogRecordSocketReceiver()
print("About to start TCP server...") print('About to start TCP server...')
tcpserver.serve_until_stopped() tcpserver.serve_until_stopped()
if __name__ == "__main__": if __name__ == '__main__':
main() main()
First run the server, and then the client. On the client side, nothing is First run the server, and then the client. On the client side, nothing is
@ -2395,7 +2400,7 @@ method which takes a level argument and returns true if the event would be
created by the Logger for that level of call. You can write code like this:: created by the Logger for that level of call. You can write code like this::
if logger.isEnabledFor(logging.DEBUG): if logger.isEnabledFor(logging.DEBUG):
logger.debug("Message with %s, %s", expensive_func1(), logger.debug('Message with %s, %s', expensive_func1(),
expensive_func2()) expensive_func2())
so that if the logger's threshold is set above ``DEBUG``, the calls to so that if the logger's threshold is set above ``DEBUG``, the calls to
@ -2563,7 +2568,7 @@ and :meth:`flush` methods).
.. versionchanged:: 3.2 .. versionchanged:: 3.2
The ``StreamHandler`` class now has a ``terminator`` attribute, default The ``StreamHandler`` class now has a ``terminator`` attribute, default
value ``"\n"``, which is used as the terminator when writing a formatted value ``'\n'``, which is used as the terminator when writing a formatted
record to a stream. If you don't want this newline termination, you can record to a stream. If you don't want this newline termination, you can
set the handler instance's ``terminator`` attribute to the empty string. set the handler instance's ``terminator`` attribute to the empty string.
@ -2604,7 +2609,7 @@ NullHandler
.. versionadded:: 3.1 .. versionadded:: 3.1
The :class:`NullHandler` class, located in the core :mod:`logging` package, The :class:`NullHandler` class, located in the core :mod:`logging` package,
does not do any formatting or output. It is essentially a "no-op" handler does not do any formatting or output. It is essentially a 'no-op' handler
for use by library developers. for use by library developers.
.. class:: NullHandler() .. class:: NullHandler()
@ -2690,7 +2695,7 @@ module, supports rotation of disk log files.
the file is closed and a new file is silently opened for output. Rollover occurs the file is closed and a new file is silently opened for output. Rollover occurs
whenever the current log file is nearly *maxBytes* in length; if *maxBytes* is whenever the current log file is nearly *maxBytes* in length; if *maxBytes* is
zero, rollover never occurs. If *backupCount* is non-zero, the system will save zero, rollover never occurs. If *backupCount* is non-zero, the system will save
old log files by appending the extensions ".1", ".2" etc., to the filename. For old log files by appending the extensions '.1', '.2' etc., to the filename. For
example, with a *backupCount* of 5 and a base file name of :file:`app.log`, you example, with a *backupCount* of 5 and a base file name of :file:`app.log`, you
would get :file:`app.log`, :file:`app.log.1`, :file:`app.log.2`, up to would get :file:`app.log`, :file:`app.log.1`, :file:`app.log.2`, up to
:file:`app.log.5`. The file being written to is always :file:`app.log`. When :file:`app.log.5`. The file being written to is always :file:`app.log`. When
@ -2887,7 +2892,7 @@ supports sending logging messages to a remote or local Unix syslog.
the form of a ``(host, port)`` tuple. If *address* is not specified, the form of a ``(host, port)`` tuple. If *address* is not specified,
``('localhost', 514)`` is used. The address is used to open a socket. An ``('localhost', 514)`` is used. The address is used to open a socket. An
alternative to providing a ``(host, port)`` tuple is providing an address as a alternative to providing a ``(host, port)`` tuple is providing an address as a
string, for example "/dev/log". In this case, a Unix domain socket is used to string, for example '/dev/log'. In this case, a Unix domain socket is used to
send the message to the syslog. If *facility* is not specified, send the message to the syslog. If *facility* is not specified,
:const:`LOG_USER` is used. The type of socket opened depends on the :const:`LOG_USER` is used. The type of socket opened depends on the
*socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus *socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus
@ -2897,8 +2902,8 @@ supports sending logging messages to a remote or local Unix syslog.
Note that if your server is not listening on UDP port 514, Note that if your server is not listening on UDP port 514,
:class:`SysLogHandler` may appear not to work. In that case, check what :class:`SysLogHandler` may appear not to work. In that case, check what
address you should be using for a domain socket - it's system dependent. address you should be using for a domain socket - it's system dependent.
For example, on Linux it's usually "/dev/log" but on OS/X it's For example, on Linux it's usually '/dev/log' but on OS/X it's
"/var/run/syslog". You'll need to check your platform and use the '/var/run/syslog'. You'll need to check your platform and use the
appropriate address (you may need to do this check at runtime if your appropriate address (you may need to do this check at runtime if your
application needs to run on several platforms). On Windows, you pretty application needs to run on several platforms). On Windows, you pretty
much have to use the UDP option. much have to use the UDP option.
@ -3002,7 +3007,7 @@ supports sending logging messages to a remote or local Unix syslog.
if the default algorithm is not suitable for your needs. The if the default algorithm is not suitable for your needs. The
default algorithm maps ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and default algorithm maps ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and
``CRITICAL`` to the equivalent syslog names, and all other level ``CRITICAL`` to the equivalent syslog names, and all other level
names to "warning". names to 'warning'.
.. _nt-eventlog-handler: .. _nt-eventlog-handler:
@ -3326,7 +3331,7 @@ Subclassing QueueHandler
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
You can use a :class:`QueueHandler` subclass to send messages to other kinds You can use a :class:`QueueHandler` subclass to send messages to other kinds
of queues, for example a ZeroMQ "publish" socket. In the example below,the of queues, for example a ZeroMQ 'publish' socket. In the example below,the
socket is created separately and passed to the handler (as its 'queue'):: socket is created separately and passed to the handler (as its 'queue')::
import zmq # using pyzmq, the Python binding for ZeroMQ import zmq # using pyzmq, the Python binding for ZeroMQ
@ -3366,7 +3371,7 @@ Subclassing QueueListener
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
You can also subclass :class:`QueueListener` to get messages from other kinds You can also subclass :class:`QueueListener` to get messages from other kinds
of queues, for example a ZeroMQ "subscribe" socket. Here's an example:: of queues, for example a ZeroMQ 'subscribe' socket. Here's an example::
class ZeroMQSocketListener(QueueListener): class ZeroMQSocketListener(QueueListener):
def __init__(self, uri, *handlers, **kwargs): def __init__(self, uri, *handlers, **kwargs):
@ -3466,8 +3471,8 @@ Filter Objects
``Filters`` can be used by ``Handlers`` and ``Loggers`` for more sophisticated ``Filters`` can be used by ``Handlers`` and ``Loggers`` for more sophisticated
filtering than is provided by levels. The base filter class only allows events filtering than is provided by levels. The base filter class only allows events
which are below a certain point in the logger hierarchy. For example, a filter which are below a certain point in the logger hierarchy. For example, a filter
initialized with "A.B" will allow events logged by loggers "A.B", "A.B.C", initialized with 'A.B' will allow events logged by loggers 'A.B', 'A.B.C',
"A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If initialized with the 'A.B.C.D', 'A.B.D' etc. but not 'A.BB', 'B.A.B' etc. If initialized with the
empty string, all events are passed. empty string, all events are passed.
@ -3619,7 +3624,7 @@ the options available to you.
+----------------+-------------------------+-----------------------------------------------+ +----------------+-------------------------+-----------------------------------------------+
| asctime | ``%(asctime)s`` | Human-readable time when the | | asctime | ``%(asctime)s`` | Human-readable time when the |
| | | :class:`LogRecord` was created. By default | | | | :class:`LogRecord` was created. By default |
| | | this is of the form "2003-07-08 16:49:45,896" | | | | this is of the form '2003-07-08 16:49:45,896' |
| | | (the numbers after the comma are millisecond | | | | (the numbers after the comma are millisecond |
| | | portion of the time). | | | | portion of the time). |
+----------------+-------------------------+-----------------------------------------------+ +----------------+-------------------------+-----------------------------------------------+
@ -3749,7 +3754,7 @@ with the :mod:`warnings` module.
If *capture* is ``True``, warnings issued by the :mod:`warnings` module will If *capture* is ``True``, warnings issued by the :mod:`warnings` module will
be redirected to the logging system. Specifically, a warning will be be redirected to the logging system. Specifically, a warning will be
formatted using :func:`warnings.formatwarning` and the resulting string formatted using :func:`warnings.formatwarning` and the resulting string
logged to a logger named "py.warnings" with a severity of `WARNING`. logged to a logger named 'py.warnings' with a severity of `WARNING`.
If *capture* is ``False``, the redirection of warnings to the logging system If *capture* is ``False``, the redirection of warnings to the logging system
will stop, and warnings will be redirected to their original destinations will stop, and warnings will be redirected to their original destinations
@ -3852,8 +3857,8 @@ Configuration dictionary schema
Describing a logging configuration requires listing the various Describing a logging configuration requires listing the various
objects to create and the connections between them; for example, you objects to create and the connections between them; for example, you
may create a handler named "console" and then say that the logger may create a handler named 'console' and then say that the logger
named "startup" will send its messages to the "console" handler. named 'startup' will send its messages to the 'console' handler.
These objects aren't limited to those provided by the :mod:`logging` These objects aren't limited to those provided by the :mod:`logging`
module because you might write your own formatter or handler class. module because you might write your own formatter or handler class.
The parameters to these classes may also need to include external The parameters to these classes may also need to include external
@ -4316,7 +4321,7 @@ Sections which specify handler configuration are exemplified by the following.
The ``class`` entry indicates the handler's class (as determined by :func:`eval` The ``class`` entry indicates the handler's class (as determined by :func:`eval`
in the ``logging`` package's namespace). The ``level`` is interpreted as for in the ``logging`` package's namespace). The ``level`` is interpreted as for
loggers, and ``NOTSET`` is taken to mean "log everything". loggers, and ``NOTSET`` is taken to mean 'log everything'.
The ``formatter`` entry indicates the key name of the formatter for this The ``formatter`` entry indicates the key name of the formatter for this
handler. If blank, a default formatter (``logging._defaultFormatter``) is used. handler. If blank, a default formatter (``logging._defaultFormatter``) is used.
@ -4387,7 +4392,7 @@ Sections which specify formatter configuration are typified by the following. ::
The ``format`` entry is the overall format string, and the ``datefmt`` entry is The ``format`` entry is the overall format string, and the ``datefmt`` entry is
the :func:`strftime`\ -compatible date/time format string. If empty, the the :func:`strftime`\ -compatible date/time format string. If empty, the
package substitutes ISO8601 format date/times, which is almost equivalent to package substitutes ISO8601 format date/times, which is almost equivalent to
specifying the date format string ``"%Y-%m-%d %H:%M:%S"``. The ISO8601 format specifying the date format string ``'%Y-%m-%d %H:%M:%S'``. The ISO8601 format
also specifies milliseconds, which are appended to the result of using the above also specifies milliseconds, which are appended to the result of using the above
format string, with a comma separator. An example time in ISO8601 format is format string, with a comma separator. An example time in ISO8601 format is
``2003-01-23 00:29:50,411``. ``2003-01-23 00:29:50,411``.
@ -4409,23 +4414,23 @@ Here is an example of a module using the logging configuration server::
import os import os
# read initial config file # read initial config file
logging.config.fileConfig("logging.conf") logging.config.fileConfig('logging.conf')
# create and start listener on port 9999 # create and start listener on port 9999
t = logging.config.listen(9999) t = logging.config.listen(9999)
t.start() t.start()
logger = logging.getLogger("simpleExample") logger = logging.getLogger('simpleExample')
try: try:
# loop through logging calls to see the difference # loop through logging calls to see the difference
# new configurations make, until Ctrl+C is pressed # new configurations make, until Ctrl+C is pressed
while True: while True:
logger.debug("debug message") logger.debug('debug message')
logger.info("info message") logger.info('info message')
logger.warn("warn message") logger.warn('warn message')
logger.error("error message") logger.error('error message')
logger.critical("critical message") logger.critical('critical message')
time.sleep(5) time.sleep(5)
except KeyboardInterrupt: except KeyboardInterrupt:
# cleanup # cleanup
@ -4439,18 +4444,18 @@ configuration::
#!/usr/bin/env python #!/usr/bin/env python
import socket, sys, struct import socket, sys, struct
data_to_send = open(sys.argv[1], "r").read() data_to_send = open(sys.argv[1], 'r').read()
HOST = 'localhost' HOST = 'localhost'
PORT = 9999 PORT = 9999
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("connecting...") print('connecting...')
s.connect((HOST, PORT)) s.connect((HOST, PORT))
print("sending config...") print('sending config...')
s.send(struct.pack(">L", len(data_to_send))) s.send(struct.pack('>L', len(data_to_send)))
s.send(data_to_send) s.send(data_to_send)
s.close() s.close()
print("complete") print('complete')
More examples More examples
@ -4469,30 +4474,30 @@ previous simple module-based configuration example::
import logging import logging
logger = logging.getLogger("simple_example") logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages # create file handler which logs even debug messages
fh = logging.FileHandler("spam.log") fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG) fh.setLevel(logging.DEBUG)
# create console handler with a higher log level # create console handler with a higher log level
ch = logging.StreamHandler() ch = logging.StreamHandler()
ch.setLevel(logging.ERROR) ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers # create formatter and add it to the handlers
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter) ch.setFormatter(formatter)
fh.setFormatter(formatter) fh.setFormatter(formatter)
# add the handlers to logger # add the handlers to logger
logger.addHandler(ch) logger.addHandler(ch)
logger.addHandler(fh) logger.addHandler(fh)
# "application" code # 'application' code
logger.debug("debug message") logger.debug('debug message')
logger.info("info message") logger.info('info message')
logger.warn("warn message") logger.warn('warn message')
logger.error("error message") logger.error('error message')
logger.critical("critical message") logger.critical('critical message')
Notice that the "application" code does not care about multiple handlers. All Notice that the 'application' code does not care about multiple handlers. All
that changed was the addition and configuration of a new handler named *fh*. that changed was the addition and configuration of a new handler named *fh*.
The ability to create new handlers with higher- or lower-severity filters can be The ability to create new handlers with higher- or lower-severity filters can be
@ -4519,51 +4524,51 @@ the parent. Here is a main module::
import logging import logging
import auxiliary_module import auxiliary_module
# create logger with "spam_application" # create logger with 'spam_application'
logger = logging.getLogger("spam_application") logger = logging.getLogger('spam_application')
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages # create file handler which logs even debug messages
fh = logging.FileHandler("spam.log") fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG) fh.setLevel(logging.DEBUG)
# create console handler with a higher log level # create console handler with a higher log level
ch = logging.StreamHandler() ch = logging.StreamHandler()
ch.setLevel(logging.ERROR) ch.setLevel(logging.ERROR)
# create formatter and add it to the handlers # create formatter and add it to the handlers
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter) fh.setFormatter(formatter)
ch.setFormatter(formatter) ch.setFormatter(formatter)
# add the handlers to the logger # add the handlers to the logger
logger.addHandler(fh) logger.addHandler(fh)
logger.addHandler(ch) logger.addHandler(ch)
logger.info("creating an instance of auxiliary_module.Auxiliary") logger.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary() a = auxiliary_module.Auxiliary()
logger.info("created an instance of auxiliary_module.Auxiliary") logger.info('created an instance of auxiliary_module.Auxiliary')
logger.info("calling auxiliary_module.Auxiliary.do_something") logger.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something() a.do_something()
logger.info("finished auxiliary_module.Auxiliary.do_something") logger.info('finished auxiliary_module.Auxiliary.do_something')
logger.info("calling auxiliary_module.some_function()") logger.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function() auxiliary_module.some_function()
logger.info("done with auxiliary_module.some_function()") logger.info('done with auxiliary_module.some_function()')
Here is the auxiliary module:: Here is the auxiliary module::
import logging import logging
# create logger # create logger
module_logger = logging.getLogger("spam_application.auxiliary") module_logger = logging.getLogger('spam_application.auxiliary')
class Auxiliary: class Auxiliary:
def __init__(self): def __init__(self):
self.logger = logging.getLogger("spam_application.auxiliary.Auxiliary") self.logger = logging.getLogger('spam_application.auxiliary.Auxiliary')
self.logger.info("creating an instance of Auxiliary") self.logger.info('creating an instance of Auxiliary')
def do_something(self): def do_something(self):
self.logger.info("doing something") self.logger.info('doing something')
a = 1 + 1 a = 1 + 1
self.logger.info("done doing something") self.logger.info('done doing something')
def some_function(): def some_function():
module_logger.info("received a call to \"some_function\"") module_logger.info('received a call to "some_function"')
The output looks like this:: The output looks like this::
@ -4584,7 +4589,7 @@ The output looks like this::
2005-03-23 23:47:11,671 - spam_application - INFO - 2005-03-23 23:47:11,671 - spam_application - INFO -
calling auxiliary_module.some_function() calling auxiliary_module.some_function()
2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO - 2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO -
received a call to "some_function" received a call to 'some_function'
2005-03-23 23:47:11,673 - spam_application - INFO - 2005-03-23 23:47:11,673 - spam_application - INFO -
done with auxiliary_module.some_function() done with auxiliary_module.some_function()