Explain Codes LogoExplain Codes Logo

How to disable logging on the standard error stream?

python
logging
context-manager
error-handling
Anton ShumikhinbyAnton Shumikhin·Feb 17, 2025
TLDR

Stop Python logs from reaching stderr by using NullHandler:

import logging # Silence is golden logging.getLogger().addHandler(logging.NullHandler())

Or keep stderr clean by redirecting it to a file or os.devnull:

import logging, os # Banishing logs to the shadow realm logging.basicConfig(handlers=[logging.StreamHandler(open(os.devnull, 'w'))])

These methods prevent any log output in your console. Use the NullHandler to entirely ignore logs or divert them to os.devnull to toss away those pesky unwanted messages.

Stop the bubble up: handle logger propagation

Understanding logger propagation

Learning to manage logging behavior requires a solid grasp of logger propagation. The logger.propagate attribute determines if a log message should be passed on to the logger's parent:

logger = logging.getLogger('my_logger') logger.propagate = False # Gandalf mode: no passing to the parent logger

By setting propagate to False, you can stop alarm bells from ringing at the root logger and, incidentally, on the stderr console.

Target specific handlers

If you need to fine-tune your logging, you can disable specific handlers without affecting the others:

for handler in logger.handlers: if isinstance(handler, logging.StreamHandler): logger.removeHandler(handler) # Adios, stream handler

This method allows you to keep other handler functionality, such as logging to a file, up and running.

One ring to rule them all: Advanced control and temporary logger management

Master the art of context managers

When you need to gain control over your logging for a brief period of time, make a power move with a context manager. This approach allows detailed control over a logger within specific code blocks:

import contextlib @contextlib.contextmanager def pause_logging(logger): original_handlers = logger.handlers logger.handlers = [logging.NullHandler()] try: yield finally: logger.handlers = original_handlers with pause_logging(logging.getLogger()): # Code within this block enjoys a logging-free existence

How to beat the default handler re-addition

Heads up! The logging module can be a sneaky fellow, re-adding default handlers if none are present. Outwit this by ensuring your logger always has at least one handler in its arsenal.

Untangling the noise level: customizing the logging level

Handy-dandy level settings

Break out the handler levels to control logging with surgical precision. The message processing level for every handler can be individually set:

console_handler = logging.StreamHandler() console_handler.setLevel(logging.WARN) # Only the serious warnings get past this gatekeeper logger.addHandler(console_handler)

Setting the level to logging.WARN lets only WARNING, ERROR, and CRITICAL messages pass.

Shutting down the logging world

For those who like to pull big levers, here's the code to globally disable logging:

logging.disable(logging.CRITICAL) # I want it all... gone!

In case you miss the logging noise, you can wake up your loggers by setting the disable level to logging.NOTSET:

logging.disable(logging.NOTSET) # Back to the grind!

Mastery over chaos: solid error proofing for logging configurations

Safety first when dealing with default Handlers

Whenever you plan to alter the stream of the default handler, always make sure it exists. Unexpectedly running into a non-existent handler can cause a messy IndexError:

if logger.handlers: logger.handlers[0].stream = None # Check yourself before you wreck yourself

Order in the court! File handlers before stdout

Avoid errors like IndexOutOfBound by showing some love for order. Add a file handler before you reckon with the stdout handler:

file_handler = logging.FileHandler('logfile.log') logger.addHandler(file_handler) # File handler politely steps in before the stdout handler

Once you ensured a handler other than StreamHandler is hanging around, you can put the stdout handler in its place.

Bulletproof your context manager with exception handling

Make your context manager a master of survival by handling exceptions in the __exit__ method:

@contextlib.contextmanager def bulletproof_pause_logging(logger): original_handlers = logger.handlers logger.handlers = [logging.NullHandler()] try: yield finally: try: # Restore handlers, the old guard is back logger.handlers = original_handlers except Exception as e: # Swallow exceptions like a champ logger.error("Failed to restore logger handlers. Too bad!", exc_info=e)

With this code, your context manager becomes an unstoppable force, executing even in the face of adversity.