Python Logger : StreamHandler not controlling my terminal stdout?
Question:
I’ve got – I believe – a rather standard logger config with two Handlers : file and stream. The file handler works very nicely and I can control the content of the output file with its own level, but the stream handler does not seem to do anything, all root logs are passed to stdout whether I add the StreamHandler or not. Anyone would know what I did wrong ?
I’m running python3.10 on Ubuntu 20.04, here is the config:
import logging
import sys
# root logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# terminal logger
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.CRITICAL)
logger.addHandler(stream_handler)
# file logger
file_handler = logging.FileHandler(f'logs/{__name__}.txt', 'w')
file_handler.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
I tried to pass sys.stdout as a parameter for StreamHandler() but it did not change the result.
With the above I would expect the console to only print CRITICAL but it shows all levels:
DEBUG:network:deserialized data: ['111', 'idle', 'normal']
INFO:network:ID:100 ['normal'] already exists, storing server_states[587]: (-13, 2890, 35, 69)
DEBUG:network:_entity.position.server_states={583: <rect(-17, 2713, 35, 69)>}
INFO:network:sending:100|idle['normal']|480;971;35;69|right|0|0|1000.0|3|None|0|0;0|0;0;0;0;0;0
INFO:network:received:107|idle['normal','collectable']12;2935;35;69|left|0|0|1000.0|3|None|45.1
I’m wondering if it would be related to the logger name (dynamic from module name) ?
Answers:
Your configuration should work as expected. This slightly modified script:
import logging
import sys
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# terminal logger
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.CRITICAL)
logger.addHandler(stream_handler)
# file logger
file_handler = logging.FileHandler(f'logs/{__name__}.txt', 'w')
file_handler.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
for level in (logging.DEBUG, logging.INFO, logging.WARNING,
logging.ERROR, logging.CRITICAL):
if level:
logger.log(level, "Event at %s", logging.getLevelName(level))
works as expected, as shown here:
$ python3.10 test_71641676.py > tmp.txt
$ more tmp.txt
Event at CRITICAL
which shows that sys.stdout
is being used for the StreamHandler
.
It seems it is related to the fact that I have multiple modules – each module can have a logger to console, but the main script must remain in control and have its own logger set (which I did not have).
This page solved my problem: https://docs.python.org/3/howto/logging-cookbook.html#logging-to-multiple-destinations
I’ve got – I believe – a rather standard logger config with two Handlers : file and stream. The file handler works very nicely and I can control the content of the output file with its own level, but the stream handler does not seem to do anything, all root logs are passed to stdout whether I add the StreamHandler or not. Anyone would know what I did wrong ?
I’m running python3.10 on Ubuntu 20.04, here is the config:
import logging
import sys
# root logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# terminal logger
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.CRITICAL)
logger.addHandler(stream_handler)
# file logger
file_handler = logging.FileHandler(f'logs/{__name__}.txt', 'w')
file_handler.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
I tried to pass sys.stdout as a parameter for StreamHandler() but it did not change the result.
With the above I would expect the console to only print CRITICAL but it shows all levels:
DEBUG:network:deserialized data: ['111', 'idle', 'normal']
INFO:network:ID:100 ['normal'] already exists, storing server_states[587]: (-13, 2890, 35, 69)
DEBUG:network:_entity.position.server_states={583: <rect(-17, 2713, 35, 69)>}
INFO:network:sending:100|idle['normal']|480;971;35;69|right|0|0|1000.0|3|None|0|0;0|0;0;0;0;0;0
INFO:network:received:107|idle['normal','collectable']12;2935;35;69|left|0|0|1000.0|3|None|45.1
I’m wondering if it would be related to the logger name (dynamic from module name) ?
Your configuration should work as expected. This slightly modified script:
import logging
import sys
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# terminal logger
stream_handler = logging.StreamHandler(sys.stdout)
stream_handler.setLevel(logging.CRITICAL)
logger.addHandler(stream_handler)
# file logger
file_handler = logging.FileHandler(f'logs/{__name__}.txt', 'w')
file_handler.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
for level in (logging.DEBUG, logging.INFO, logging.WARNING,
logging.ERROR, logging.CRITICAL):
if level:
logger.log(level, "Event at %s", logging.getLevelName(level))
works as expected, as shown here:
$ python3.10 test_71641676.py > tmp.txt
$ more tmp.txt
Event at CRITICAL
which shows that sys.stdout
is being used for the StreamHandler
.
It seems it is related to the fact that I have multiple modules – each module can have a logger to console, but the main script must remain in control and have its own logger set (which I did not have).
This page solved my problem: https://docs.python.org/3/howto/logging-cookbook.html#logging-to-multiple-destinations