captureWarnings set to True doesn't capture warnings

Question:

I would like to log all warnings. I thought that setting captureWarnings to True should do the trick, but it doesn’t. Code:

import logging
import warnings

from logging.handlers import RotatingFileHandler

logger_file_handler = RotatingFileHandler(u'./test.log')
logger_file_handler.setLevel(logging.DEBUG)

logging.captureWarnings(True)

logger = logging.getLogger(__name__)

logger.addHandler(logger_file_handler)
logger.setLevel(logging.DEBUG)

logger.info(u'Test')
warnings.warn(u'Warning test')

My expectation is that ‘Warning test’ should appear in test.log, but it doesn’t; only ‘Test’ is put in the log file.

How to capture all warnings and redirect them to the log file?

Asked By: LAdas

||

Answers:

logging.captureWarnings is not using your logger. It uses a logger named 'py.warnings'. You will need to configure that logger to do what you want.

Answered By: user2357112

From the logging.captureWarnings documentation:

Warnings issued by the warnings module will be redirected to the
logging system. Specifically, a warning will be formatted using
warnings.formatwarning() and the resulting string logged to a logger
named ‘py.warnings’ with a severity of WARNING
.

You probably want something like this:

import logging
import warnings

from logging.handlers import RotatingFileHandler

logger_file_handler = RotatingFileHandler(u'test.log')
logger_file_handler.setLevel(logging.DEBUG)

logging.captureWarnings(True)

logger = logging.getLogger(__name__)
warnings_logger = logging.getLogger("py.warnings")

logger.addHandler(logger_file_handler)
logger.setLevel(logging.DEBUG)
warnings_logger.addHandler(logger_file_handler)

logger.info(u'Test')
warnings.warn(u'Warning test')

Hope it helps!

Answered By: cdonts

In an application codebase, instead of explicitly configuring the py.warnings logger as other answers here suggest, you instead can – and probably want to – configure the root logger. This will:

  • Log stuff from py.warnings (the logger that the captureWarnings integration logs with)
  • Log stuff from libraries that create their own logger and log to it
  • Allow you to directly log using the logging module functions like logging.info instead of making a logger object

The following simple demo logs your warning as you want it to:

import logging
import warnings

from logging.handlers import RotatingFileHandler

logger_file_handler = RotatingFileHandler(u'./test.log')
logger_file_handler.setLevel(logging.DEBUG)

logging.captureWarnings(True)

root_logger = logging.getLogger()

root_logger.addHandler(logger_file_handler)
root_logger.setLevel(logging.DEBUG)

logging.info(u'Test')
warnings.warn(u'Warning test')
Answered By: Mark Amery

Not directly relevant for the OP, but may be useful for others winding up here based on the title:

Another reason for warnings not to show up in your logs would be if you use warnings.catch_warnings with record=True.

Here’s a minimal example:

import logging
import warnings

logging.basicConfig()  # configures the root logger

logging.captureWarnings(True)

warnings.warn('logged')

with warnings.catch_warnings():
    warnings.warn('also logged')


with warnings.catch_warnings(record=True) as warnings_caught:
    warnings.warn('not logged')

# show warnings recorded
print([w.message for w in warnings_caught])
Answered By: djvg
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.