import logging
# root logger
root = logging.getLogger() # root
ch = logging.StreamHandler()
ch.setLevel(logging.WARN)
formatter = logging.Formatter('[root] %(levelname)s - %(message)s')
ch.setFormatter(formatter)
root.addHandler(ch)
# logging as child
c = logging.getLogger('mod')
c.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('[mod] - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
c.addHandler(ch)
c.error('foo')
c.warning('foo')
c.info('foo')
c.debug('foo')
output:
[mod] - ERROR - foo
[root] ERROR - foo
[mod] - WARNING - foo
[root] WARNING - foo
[mod] - INFO - foo
[mod] - DEBUG - foo
It's OK. Level of root is WARN
, so INFO
and DEBUG
of root is not printed.
But when I use basicConfig
:
import logging
# config root logger
logging.basicConfig(level=logging.WARN, format='[root] %(levelname)s - %(message)s')
# logging as child
c = logging.getLogger('mod')
c.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter('[mod] - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
c.addHandler(ch)
c.error('foo')
c.warning('foo')
c.info('foo')
c.debug('foo')
output:
[mod] - ERROR - foo
[root] ERROR - foo
[mod] - WARNING - foo
[root] WARNING - foo
[mod] - INFO - foo
[root] INFO - foo
[mod] - DEBUG - foo
[root] DEBUG - foo
The level of basicConfig
is WARN
, why level INFO
and DEBUG
of root can be printed?
And when I use logging.info
, it effects.
You are seeing those [root]
info and debug messages because your call to logging.basicConfig
creates a root Handler with a level of NOTSET
. A handler with a level of NOTSET
will output any message it receives (see Handler.setLevel).
>>> import logging
>>> logging.basicConfig(level=logging.WARN, format='[root] %(levelname)s - %(message)s')
>>> [handler.level == logging.NOTSET for handler in logging.getLogger().handlers]
[True]
This differs from your first example because in your first example you are creating a root handler with a level of WARN
.
The level=
parameter for logging.basicConfig
is used to set the level of the root Logger not any root Handler.
Log messages are propagated up to parent Loggers but the level of any parent Loggers is not considered. It is the level of any Handlers that decides what gets "outputted".
From the docs for logging.Logger.propagate:
Messages are passed directly to the ancestor loggers’ handlers - neither the level nor filters of the ancestor loggers in question are considered.
A Logger uses its level to decide if to propagate a message to its and any parent loggers' handlers.
If a Logger does not have a level set then it asks its ancestor Loggers for their level and uses that (see logging.Logger.setLevel
).
So, the root logger's level is only relevant if you have not set the level on your child logger.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With