captureWarnings set to True doesn't capture warnings
Asked Answered
F

4

17

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?

Face answered 22/7, 2016 at 16:57 Comment(0)
B
17

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!

Barley answered 22/7, 2016 at 17:7 Comment(0)
J
5

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')
Jethro answered 13/1, 2020 at 15:52 Comment(0)
U
4

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.

Ulland answered 22/7, 2016 at 17:5 Comment(0)
M
0

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])
Mccullers answered 15/12, 2022 at 13:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.