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