blob: 399d4dcc53ad6a7917085b6c38bd7553b77e4d09 [file] [log] [blame]
Vinay Sajipc63619b2010-12-19 12:56:57 +00001:mod:`logging.config` --- Logging configuration
2===============================================
3
4.. module:: logging.config
5 :synopsis: Configuration of the logging module.
6
7
8.. moduleauthor:: Vinay Sajip <vinay_sajip@red-dove.com>
9.. sectionauthor:: Vinay Sajip <vinay_sajip@red-dove.com>
10
11
12.. _logging-config-api:
13
14Configuration functions
15^^^^^^^^^^^^^^^^^^^^^^^
16
17The following functions configure the logging module. They are located in the
18:mod:`logging.config` module. Their use is optional --- you can configure the
19logging module using these functions or by making calls to the main API (defined
20in :mod:`logging` itself) and defining handlers which are declared either in
21:mod:`logging` or :mod:`logging.handlers`.
22
23.. function:: dictConfig(config)
24
25 Takes the logging configuration from a dictionary. The contents of
26 this dictionary are described in :ref:`logging-config-dictschema`
27 below.
28
29 If an error is encountered during configuration, this function will
30 raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError`
31 or :exc:`ImportError` with a suitably descriptive message. The
32 following is a (possibly incomplete) list of conditions which will
33 raise an error:
34
35 * A ``level`` which is not a string or which is a string not
36 corresponding to an actual logging level.
37 * A ``propagate`` value which is not a boolean.
38 * An id which does not have a corresponding destination.
39 * A non-existent handler id found during an incremental call.
40 * An invalid logger name.
41 * Inability to resolve to an internal or external object.
42
43 Parsing is performed by the :class:`DictConfigurator` class, whose
44 constructor is passed the dictionary used for configuration, and
45 has a :meth:`configure` method. The :mod:`logging.config` module
46 has a callable attribute :attr:`dictConfigClass`
47 which is initially set to :class:`DictConfigurator`.
48 You can replace the value of :attr:`dictConfigClass` with a
49 suitable implementation of your own.
50
51 :func:`dictConfig` calls :attr:`dictConfigClass` passing
52 the specified dictionary, and then calls the :meth:`configure` method on
53 the returned object to put the configuration into effect::
54
55 def dictConfig(config):
56 dictConfigClass(config).configure()
57
58 For example, a subclass of :class:`DictConfigurator` could call
59 ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then
60 set up custom prefixes which would be usable in the subsequent
61 :meth:`configure` call. :attr:`dictConfigClass` would be bound to
62 this new subclass, and then :func:`dictConfig` could be called exactly as
63 in the default, uncustomized state.
64
65.. function:: fileConfig(fname[, defaults])
66
67 Reads the logging configuration from a :mod:`configparser`\-format file named
68 *fname*. This function can be called several times from an application,
69 allowing an end user to select from various pre-canned
70 configurations (if the developer provides a mechanism to present the choices
71 and load the chosen configuration). Defaults to be passed to the ConfigParser
72 can be specified in the *defaults* argument.
73
74
75.. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT)
76
77 Starts up a socket server on the specified port, and listens for new
78 configurations. If no port is specified, the module's default
79 :const:`DEFAULT_LOGGING_CONFIG_PORT` is used. Logging configurations will be
80 sent as a file suitable for processing by :func:`fileConfig`. Returns a
81 :class:`Thread` instance on which you can call :meth:`start` to start the
82 server, and which you can :meth:`join` when appropriate. To stop the server,
83 call :func:`stopListening`.
84
85 To send a configuration to the socket, read in the configuration file and
86 send it to the socket as a string of bytes preceded by a four-byte length
87 string packed in binary using ``struct.pack('>L', n)``.
88
89
90.. function:: stopListening()
91
92 Stops the listening server which was created with a call to :func:`listen`.
93 This is typically called before calling :meth:`join` on the return value from
94 :func:`listen`.
95
96
97.. _logging-config-dictschema:
98
99Configuration dictionary schema
100^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
101
102Describing a logging configuration requires listing the various
103objects to create and the connections between them; for example, you
104may create a handler named 'console' and then say that the logger
105named 'startup' will send its messages to the 'console' handler.
106These objects aren't limited to those provided by the :mod:`logging`
107module because you might write your own formatter or handler class.
108The parameters to these classes may also need to include external
109objects such as ``sys.stderr``. The syntax for describing these
110objects and connections is defined in :ref:`logging-config-dict-connections`
111below.
112
113Dictionary Schema Details
114"""""""""""""""""""""""""
115
116The dictionary passed to :func:`dictConfig` must contain the following
117keys:
118
119* *version* - to be set to an integer value representing the schema
120 version. The only valid value at present is 1, but having this key
121 allows the schema to evolve while still preserving backwards
122 compatibility.
123
124All other keys are optional, but if present they will be interpreted
125as described below. In all cases below where a 'configuring dict' is
126mentioned, it will be checked for the special ``'()'`` key to see if a
127custom instantiation is required. If so, the mechanism described in
128:ref:`logging-config-dict-userdef` below is used to create an instance;
129otherwise, the context is used to determine what to instantiate.
130
131* *formatters* - the corresponding value will be a dict in which each
132 key is a formatter id and each value is a dict describing how to
133 configure the corresponding Formatter instance.
134
135 The configuring dict is searched for keys ``format`` and ``datefmt``
136 (with defaults of ``None``) and these are used to construct a
137 :class:`logging.Formatter` instance.
138
139* *filters* - the corresponding value will be a dict in which each key
140 is a filter id and each value is a dict describing how to configure
141 the corresponding Filter instance.
142
143 The configuring dict is searched for the key ``name`` (defaulting to the
144 empty string) and this is used to construct a :class:`logging.Filter`
145 instance.
146
147* *handlers* - the corresponding value will be a dict in which each
148 key is a handler id and each value is a dict describing how to
149 configure the corresponding Handler instance.
150
151 The configuring dict is searched for the following keys:
152
153 * ``class`` (mandatory). This is the fully qualified name of the
154 handler class.
155
156 * ``level`` (optional). The level of the handler.
157
158 * ``formatter`` (optional). The id of the formatter for this
159 handler.
160
161 * ``filters`` (optional). A list of ids of the filters for this
162 handler.
163
164 All *other* keys are passed through as keyword arguments to the
165 handler's constructor. For example, given the snippet::
166
167 handlers:
168 console:
169 class : logging.StreamHandler
170 formatter: brief
171 level : INFO
172 filters: [allow_foo]
173 stream : ext://sys.stdout
174 file:
175 class : logging.handlers.RotatingFileHandler
176 formatter: precise
177 filename: logconfig.log
178 maxBytes: 1024
179 backupCount: 3
180
181 the handler with id ``console`` is instantiated as a
182 :class:`logging.StreamHandler`, using ``sys.stdout`` as the underlying
183 stream. The handler with id ``file`` is instantiated as a
184 :class:`logging.handlers.RotatingFileHandler` with the keyword arguments
185 ``filename='logconfig.log', maxBytes=1024, backupCount=3``.
186
187* *loggers* - the corresponding value will be a dict in which each key
188 is a logger name and each value is a dict describing how to
189 configure the corresponding Logger instance.
190
191 The configuring dict is searched for the following keys:
192
193 * ``level`` (optional). The level of the logger.
194
195 * ``propagate`` (optional). The propagation setting of the logger.
196
197 * ``filters`` (optional). A list of ids of the filters for this
198 logger.
199
200 * ``handlers`` (optional). A list of ids of the handlers for this
201 logger.
202
203 The specified loggers will be configured according to the level,
204 propagation, filters and handlers specified.
205
206* *root* - this will be the configuration for the root logger.
207 Processing of the configuration will be as for any logger, except
208 that the ``propagate`` setting will not be applicable.
209
210* *incremental* - whether the configuration is to be interpreted as
211 incremental to the existing configuration. This value defaults to
212 ``False``, which means that the specified configuration replaces the
213 existing configuration with the same semantics as used by the
214 existing :func:`fileConfig` API.
215
216 If the specified value is ``True``, the configuration is processed
217 as described in the section on :ref:`logging-config-dict-incremental`.
218
219* *disable_existing_loggers* - whether any existing loggers are to be
220 disabled. This setting mirrors the parameter of the same name in
221 :func:`fileConfig`. If absent, this parameter defaults to ``True``.
222 This value is ignored if *incremental* is ``True``.
223
224.. _logging-config-dict-incremental:
225
226Incremental Configuration
227"""""""""""""""""""""""""
228
229It is difficult to provide complete flexibility for incremental
230configuration. For example, because objects such as filters
231and formatters are anonymous, once a configuration is set up, it is
232not possible to refer to such anonymous objects when augmenting a
233configuration.
234
235Furthermore, there is not a compelling case for arbitrarily altering
236the object graph of loggers, handlers, filters, formatters at
237run-time, once a configuration is set up; the verbosity of loggers and
238handlers can be controlled just by setting levels (and, in the case of
239loggers, propagation flags). Changing the object graph arbitrarily in
240a safe way is problematic in a multi-threaded environment; while not
241impossible, the benefits are not worth the complexity it adds to the
242implementation.
243
244Thus, when the ``incremental`` key of a configuration dict is present
245and is ``True``, the system will completely ignore any ``formatters`` and
246``filters`` entries, and process only the ``level``
247settings in the ``handlers`` entries, and the ``level`` and
248``propagate`` settings in the ``loggers`` and ``root`` entries.
249
250Using a value in the configuration dict lets configurations to be sent
251over the wire as pickled dicts to a socket listener. Thus, the logging
252verbosity of a long-running application can be altered over time with
253no need to stop and restart the application.
254
255.. _logging-config-dict-connections:
256
257Object connections
258""""""""""""""""""
259
260The schema describes a set of logging objects - loggers,
261handlers, formatters, filters - which are connected to each other in
262an object graph. Thus, the schema needs to represent connections
263between the objects. For example, say that, once configured, a
264particular logger has attached to it a particular handler. For the
265purposes of this discussion, we can say that the logger represents the
266source, and the handler the destination, of a connection between the
267two. Of course in the configured objects this is represented by the
268logger holding a reference to the handler. In the configuration dict,
269this is done by giving each destination object an id which identifies
270it unambiguously, and then using the id in the source object's
271configuration to indicate that a connection exists between the source
272and the destination object with that id.
273
274So, for example, consider the following YAML snippet::
275
276 formatters:
277 brief:
278 # configuration for formatter with id 'brief' goes here
279 precise:
280 # configuration for formatter with id 'precise' goes here
281 handlers:
282 h1: #This is an id
283 # configuration of handler with id 'h1' goes here
284 formatter: brief
285 h2: #This is another id
286 # configuration of handler with id 'h2' goes here
287 formatter: precise
288 loggers:
289 foo.bar.baz:
290 # other configuration for logger 'foo.bar.baz'
291 handlers: [h1, h2]
292
293(Note: YAML used here because it's a little more readable than the
294equivalent Python source form for the dictionary.)
295
296The ids for loggers are the logger names which would be used
297programmatically to obtain a reference to those loggers, e.g.
298``foo.bar.baz``. The ids for Formatters and Filters can be any string
299value (such as ``brief``, ``precise`` above) and they are transient,
300in that they are only meaningful for processing the configuration
301dictionary and used to determine connections between objects, and are
302not persisted anywhere when the configuration call is complete.
303
304The above snippet indicates that logger named ``foo.bar.baz`` should
305have two handlers attached to it, which are described by the handler
306ids ``h1`` and ``h2``. The formatter for ``h1`` is that described by id
307``brief``, and the formatter for ``h2`` is that described by id
308``precise``.
309
310
311.. _logging-config-dict-userdef:
312
313User-defined objects
314""""""""""""""""""""
315
316The schema supports user-defined objects for handlers, filters and
317formatters. (Loggers do not need to have different types for
318different instances, so there is no support in this configuration
319schema for user-defined logger classes.)
320
321Objects to be configured are described by dictionaries
322which detail their configuration. In some places, the logging system
323will be able to infer from the context how an object is to be
324instantiated, but when a user-defined object is to be instantiated,
325the system will not know how to do this. In order to provide complete
326flexibility for user-defined object instantiation, the user needs
327to provide a 'factory' - a callable which is called with a
328configuration dictionary and which returns the instantiated object.
329This is signalled by an absolute import path to the factory being
330made available under the special key ``'()'``. Here's a concrete
331example::
332
333 formatters:
334 brief:
335 format: '%(message)s'
336 default:
337 format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
338 datefmt: '%Y-%m-%d %H:%M:%S'
339 custom:
340 (): my.package.customFormatterFactory
341 bar: baz
342 spam: 99.9
343 answer: 42
344
345The above YAML snippet defines three formatters. The first, with id
346``brief``, is a standard :class:`logging.Formatter` instance with the
347specified format string. The second, with id ``default``, has a
348longer format and also defines the time format explicitly, and will
349result in a :class:`logging.Formatter` initialized with those two format
350strings. Shown in Python source form, the ``brief`` and ``default``
351formatters have configuration sub-dictionaries::
352
353 {
354 'format' : '%(message)s'
355 }
356
357and::
358
359 {
360 'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
361 'datefmt' : '%Y-%m-%d %H:%M:%S'
362 }
363
364respectively, and as these dictionaries do not contain the special key
365``'()'``, the instantiation is inferred from the context: as a result,
366standard :class:`logging.Formatter` instances are created. The
367configuration sub-dictionary for the third formatter, with id
368``custom``, is::
369
370 {
371 '()' : 'my.package.customFormatterFactory',
372 'bar' : 'baz',
373 'spam' : 99.9,
374 'answer' : 42
375 }
376
377and this contains the special key ``'()'``, which means that
378user-defined instantiation is wanted. In this case, the specified
379factory callable will be used. If it is an actual callable it will be
380used directly - otherwise, if you specify a string (as in the example)
381the actual callable will be located using normal import mechanisms.
382The callable will be called with the **remaining** items in the
383configuration sub-dictionary as keyword arguments. In the above
384example, the formatter with id ``custom`` will be assumed to be
385returned by the call::
386
387 my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)
388
389The key ``'()'`` has been used as the special key because it is not a
390valid keyword parameter name, and so will not clash with the names of
391the keyword arguments used in the call. The ``'()'`` also serves as a
392mnemonic that the corresponding value is a callable.
393
394
395.. _logging-config-dict-externalobj:
396
397Access to external objects
398""""""""""""""""""""""""""
399
400There are times where a configuration needs to refer to objects
401external to the configuration, for example ``sys.stderr``. If the
402configuration dict is constructed using Python code, this is
403straightforward, but a problem arises when the configuration is
404provided via a text file (e.g. JSON, YAML). In a text file, there is
405no standard way to distinguish ``sys.stderr`` from the literal string
406``'sys.stderr'``. To facilitate this distinction, the configuration
407system looks for certain special prefixes in string values and
408treat them specially. For example, if the literal string
409``'ext://sys.stderr'`` is provided as a value in the configuration,
410then the ``ext://`` will be stripped off and the remainder of the
411value processed using normal import mechanisms.
412
413The handling of such prefixes is done in a way analogous to protocol
414handling: there is a generic mechanism to look for prefixes which
415match the regular expression ``^(?P<prefix>[a-z]+)://(?P<suffix>.*)$``
416whereby, if the ``prefix`` is recognised, the ``suffix`` is processed
417in a prefix-dependent manner and the result of the processing replaces
418the string value. If the prefix is not recognised, then the string
419value will be left as-is.
420
421
422.. _logging-config-dict-internalobj:
423
424Access to internal objects
425""""""""""""""""""""""""""
426
427As well as external objects, there is sometimes also a need to refer
428to objects in the configuration. This will be done implicitly by the
429configuration system for things that it knows about. For example, the
430string value ``'DEBUG'`` for a ``level`` in a logger or handler will
431automatically be converted to the value ``logging.DEBUG``, and the
432``handlers``, ``filters`` and ``formatter`` entries will take an
433object id and resolve to the appropriate destination object.
434
435However, a more generic mechanism is needed for user-defined
436objects which are not known to the :mod:`logging` module. For
437example, consider :class:`logging.handlers.MemoryHandler`, which takes
438a ``target`` argument which is another handler to delegate to. Since
439the system already knows about this class, then in the configuration,
440the given ``target`` just needs to be the object id of the relevant
441target handler, and the system will resolve to the handler from the
442id. If, however, a user defines a ``my.package.MyHandler`` which has
443an ``alternate`` handler, the configuration system would not know that
444the ``alternate`` referred to a handler. To cater for this, a generic
445resolution system allows the user to specify::
446
447 handlers:
448 file:
449 # configuration of file handler goes here
450
451 custom:
452 (): my.package.MyHandler
453 alternate: cfg://handlers.file
454
455The literal string ``'cfg://handlers.file'`` will be resolved in an
456analogous way to strings with the ``ext://`` prefix, but looking
457in the configuration itself rather than the import namespace. The
458mechanism allows access by dot or by index, in a similar way to
459that provided by ``str.format``. Thus, given the following snippet::
460
461 handlers:
462 email:
463 class: logging.handlers.SMTPHandler
464 mailhost: localhost
465 fromaddr: my_app@domain.tld
466 toaddrs:
467 - support_team@domain.tld
468 - dev_team@domain.tld
469 subject: Houston, we have a problem.
470
471in the configuration, the string ``'cfg://handlers'`` would resolve to
472the dict with key ``handlers``, the string ``'cfg://handlers.email``
473would resolve to the dict with key ``email`` in the ``handlers`` dict,
474and so on. The string ``'cfg://handlers.email.toaddrs[1]`` would
475resolve to ``'dev_team.domain.tld'`` and the string
476``'cfg://handlers.email.toaddrs[0]'`` would resolve to the value
477``'support_team@domain.tld'``. The ``subject`` value could be accessed
478using either ``'cfg://handlers.email.subject'`` or, equivalently,
479``'cfg://handlers.email[subject]'``. The latter form only needs to be
480used if the key contains spaces or non-alphanumeric characters. If an
481index value consists only of decimal digits, access will be attempted
482using the corresponding integer value, falling back to the string
483value if needed.
484
485Given a string ``cfg://handlers.myhandler.mykey.123``, this will
486resolve to ``config_dict['handlers']['myhandler']['mykey']['123']``.
487If the string is specified as ``cfg://handlers.myhandler.mykey[123]``,
488the system will attempt to retrieve the value from
489``config_dict['handlers']['myhandler']['mykey'][123]``, and fall back
490to ``config_dict['handlers']['myhandler']['mykey']['123']`` if that
491fails.
492
493.. _logging-config-fileformat:
494
495Configuration file format
496^^^^^^^^^^^^^^^^^^^^^^^^^
497
498The configuration file format understood by :func:`fileConfig` is based on
499:mod:`configparser` functionality. The file must contain sections called
500``[loggers]``, ``[handlers]`` and ``[formatters]`` which identify by name the
501entities of each type which are defined in the file. For each such entity, there
502is a separate section which identifies how that entity is configured. Thus, for
503a logger named ``log01`` in the ``[loggers]`` section, the relevant
504configuration details are held in a section ``[logger_log01]``. Similarly, a
505handler called ``hand01`` in the ``[handlers]`` section will have its
506configuration held in a section called ``[handler_hand01]``, while a formatter
507called ``form01`` in the ``[formatters]`` section will have its configuration
508specified in a section called ``[formatter_form01]``. The root logger
509configuration must be specified in a section called ``[logger_root]``.
510
511Examples of these sections in the file are given below. ::
512
513 [loggers]
514 keys=root,log02,log03,log04,log05,log06,log07
515
516 [handlers]
517 keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
518
519 [formatters]
520 keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
521
522The root logger must specify a level and a list of handlers. An example of a
523root logger section is given below. ::
524
525 [logger_root]
526 level=NOTSET
527 handlers=hand01
528
529The ``level`` entry can be one of ``DEBUG, INFO, WARNING, ERROR, CRITICAL`` or
530``NOTSET``. For the root logger only, ``NOTSET`` means that all messages will be
531logged. Level values are :func:`eval`\ uated in the context of the ``logging``
532package's namespace.
533
534The ``handlers`` entry is a comma-separated list of handler names, which must
535appear in the ``[handlers]`` section. These names must appear in the
536``[handlers]`` section and have corresponding sections in the configuration
537file.
538
539For loggers other than the root logger, some additional information is required.
540This is illustrated by the following example. ::
541
542 [logger_parser]
543 level=DEBUG
544 handlers=hand01
545 propagate=1
546 qualname=compiler.parser
547
548The ``level`` and ``handlers`` entries are interpreted as for the root logger,
549except that if a non-root logger's level is specified as ``NOTSET``, the system
550consults loggers higher up the hierarchy to determine the effective level of the
551logger. The ``propagate`` entry is set to 1 to indicate that messages must
552propagate to handlers higher up the logger hierarchy from this logger, or 0 to
553indicate that messages are **not** propagated to handlers up the hierarchy. The
554``qualname`` entry is the hierarchical channel name of the logger, that is to
555say the name used by the application to get the logger.
556
557Sections which specify handler configuration are exemplified by the following.
558::
559
560 [handler_hand01]
561 class=StreamHandler
562 level=NOTSET
563 formatter=form01
564 args=(sys.stdout,)
565
566The ``class`` entry indicates the handler's class (as determined by :func:`eval`
567in the ``logging`` package's namespace). The ``level`` is interpreted as for
568loggers, and ``NOTSET`` is taken to mean 'log everything'.
569
570The ``formatter`` entry indicates the key name of the formatter for this
571handler. If blank, a default formatter (``logging._defaultFormatter``) is used.
572If a name is specified, it must appear in the ``[formatters]`` section and have
573a corresponding section in the configuration file.
574
575The ``args`` entry, when :func:`eval`\ uated in the context of the ``logging``
576package's namespace, is the list of arguments to the constructor for the handler
577class. Refer to the constructors for the relevant handlers, or to the examples
578below, to see how typical entries are constructed. ::
579
580 [handler_hand02]
581 class=FileHandler
582 level=DEBUG
583 formatter=form02
584 args=('python.log', 'w')
585
586 [handler_hand03]
587 class=handlers.SocketHandler
588 level=INFO
589 formatter=form03
590 args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
591
592 [handler_hand04]
593 class=handlers.DatagramHandler
594 level=WARN
595 formatter=form04
596 args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
597
598 [handler_hand05]
599 class=handlers.SysLogHandler
600 level=ERROR
601 formatter=form05
602 args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
603
604 [handler_hand06]
605 class=handlers.NTEventLogHandler
606 level=CRITICAL
607 formatter=form06
608 args=('Python Application', '', 'Application')
609
610 [handler_hand07]
611 class=handlers.SMTPHandler
612 level=WARN
613 formatter=form07
614 args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
615
616 [handler_hand08]
617 class=handlers.MemoryHandler
618 level=NOTSET
619 formatter=form08
620 target=
621 args=(10, ERROR)
622
623 [handler_hand09]
624 class=handlers.HTTPHandler
625 level=NOTSET
626 formatter=form09
627 args=('localhost:9022', '/log', 'GET')
628
629Sections which specify formatter configuration are typified by the following. ::
630
631 [formatter_form01]
632 format=F1 %(asctime)s %(levelname)s %(message)s
633 datefmt=
634 class=logging.Formatter
635
636The ``format`` entry is the overall format string, and the ``datefmt`` entry is
637the :func:`strftime`\ -compatible date/time format string. If empty, the
638package substitutes ISO8601 format date/times, which is almost equivalent to
639specifying the date format string ``'%Y-%m-%d %H:%M:%S'``. The ISO8601 format
640also specifies milliseconds, which are appended to the result of using the above
641format string, with a comma separator. An example time in ISO8601 format is
642``2003-01-23 00:29:50,411``.
643
644The ``class`` entry is optional. It indicates the name of the formatter's class
645(as a dotted module and class name.) This option is useful for instantiating a
646:class:`Formatter` subclass. Subclasses of :class:`Formatter` can present
647exception tracebacks in an expanded or condensed format.
648
649.. seealso::
650
651 Module :mod:`logging`
652 API reference for the logging module.
653
654 Module :mod:`logging.handlers`
655 Useful handlers included with the logging module.
656
657