Reputation: 3677
I have a custom python logger
# logger.py
import logging
#logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
c_handler = logging.StreamHandler()
c_handler.setLevel(logging.DEBUG)
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
logger.addHandler(c_handler)
I have set the level to DEBUG, but only WARNINGS (and above) are shown
from ..logger import logger
...
logger.debug('this is a debug log message')
logger.warning('too hot to handle')
...
my_module.logger:too hot to handle
if I uncomment the line
logging.basicConfig(level=logging.DEBUG)
then I get the DEBUG level, but two copies of the message
my_module.logger - DEBUG - this is a debug log message
DEBUG:my_module.logger:this is a debug log message
my_module.logger - WARNING - too hot to handle
WARNING:my_module.logger:too hot to handle
I am not importing logging at any other point in the package
How should I configure the logger?
Upvotes: 0
Views: 1051
Reputation: 3677
Having read the docs again I realise that propagate is the attribute that I need to use to turn off the ancestor logging output. So my logger becomes
# logger.py
import logging
logging.basicConfig(level=logging.DEBUG)
logger.propagate = False
logger = logging.getLogger(__name__)
c_handler = logging.StreamHandler()
c_handler.setLevel(logging.DEBUG)
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
logger.addHandler(c_handler)
And I get just one log message and the debug level is used
Upvotes: 0
Reputation: 37227
TL;DR Use logger.setLevel(logging.DEBUG)
According to Python documentation, a handler processes messages with a level equal to or higher than the handler is set to (via .setLevel()
).
But also note, emphasis mine:
When a logger is created, the level is set to
NOTSET
(which causes all messages to be processed when the logger is the root logger, or delegation to the parent when the logger is a non-root logger). Note that the root logger is created with levelWARNING
.
So without logging.basicConfig
, there's no "root logger" at program startup, and your first getLogger()
creates a stub root logger with default level WARNING, and your logger with level NOTSET (which fallbacks to that of the root logger). As a result your logger.debug
message is thrown away before it gets handled.
With logging.basicConfig
, you explicitly create a root logger with the given level and a StreamHandler with default Formatter. Your new getLogger()
is attached to the root logger and any log record is propagated to the root logger - thus printing twice with a different formatter (the default one indeed).
The stub root logger created by the first call to getLogger()
has no handler attached so any propagated record is not printed out.
If you want to have full control over your logging facility, it's better to give your logger an explicit level than relying on basicConfig
, which creates a root logger that you may not want:
logger.setLevel(logging.DEBUG)
Upvotes: 1