Let's explain by example that UNSET does NOT do anything when creating concrete instances of loggers (for some mysterious reason):
def logging_unset_level():
"""My sample logger explaining UNSET level
Resources:
- https://mcmap.net/q/37716/-about-notset-in-python-logging
- https://www.youtube.com/watch?v=jxmzY9soFXg&t=468s
- https://github.com/CoreyMSchafer/code_snippets/tree/master/Logging-Advanced
"""
import logging
logger = logging.getLogger(__name__) # loggers are created in hierarchy using dot notation, thus __name__ ensures no name collisions.
print(f'DEFAULT VALUE: logger.level = {logger.level}')
file_handler = logging.FileHandler(filename='my_log.log')
log_format = "{asctime}:{levelname}:{lineno}:{name}:{message}" # see for logrecord attributes https://docs.python.org/3/library/logging.html#logrecord-attributes
formatter = logging.Formatter(fmt=log_format, style='{')
file_handler.setFormatter(fmt=formatter)
stdout_stream_handler = logging.StreamHandler(stream=sys.stdout)
stdout_stream_handler.setLevel(logging.INFO)
log_format = "{name}:{levelname}:-> {message}" # see for logrecord attributes https://docs.python.org/3/library/logging.html#logrecord-attributes
formatter = logging.Formatter(fmt=log_format, style='{')
stdout_stream_handler.setFormatter(fmt=formatter)
logger.addHandler(hdlr=file_handler)
logger.addHandler(hdlr=stdout_stream_handler)
logger.log(logging.NOTSET, 'notset')
logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
the output to screen is:
DEFAULT VALUE: logger.level = 0
__main__:WARNING:-> warning
__main__:ERROR:-> error
__main__:CRITICAL:-> critical
the output to stdout
is:
2020-04-15 17:00:38,384:WARNING:200:__main__:warning
2020-04-15 17:00:38,384:ERROR:201:__main__:error
2020-04-15 17:00:38,384:CRITICAL:202:__main__:critical
as expected from the question's body, when the logger is instantiated its setting is UNSET
. If you are using the basic config for some reason it does work as the docs imply it should everything from UNSET to higher get logged BUT when instantiating loggers concretely this setting makes only error messages work for some reason (find me a reference!).
Ok, now if you run it again but increase the level of the top logger everything works as you would expect (except the unset):
logger.setLevel(logging.DEBUG)
The output of stdout (note the stdout handler has level INFO in my example for pedagogical reasons, different from the file handler, trying to show inheritance of the .level value from the top logger):
DEFAULT VALUE: logger.level = 10
__main__:INFO:-> info
__main__:WARNING:-> warning
__main__:ERROR:-> error
__main__:CRITICAL:-> critical
and the output of the logger file my_log.log
(this one DOES output the debug statements! :D ):
2020-04-15 17:05:58,782:DEBUG:198:__main__:debug
2020-04-15 17:05:58,784:INFO:199:__main__:info
2020-04-15 17:05:58,784:WARNING:200:__main__:warning
2020-04-15 17:05:58,784:ERROR:201:__main__:error
2020-04-15 17:05:58,784:CRITICAL:202:__main__:critica
is as expected. It inherited the top level loggers level so it printed everything from DEBUG level upwards.
logging.NOTSET
is not an effective level, it's used for delegation. – Findley