I’m developing a new application where I want to use the facilities from logging
and warning
.
Reading the docs, it seems as simple as calling logging.captureWarnings(True)
. But it is not that simple.
To begin with, my app is using its own logger. It leverages coloredlogs to have nice output by default, but that’s just a commodity that helps seeing the issue:
from logging import getLogger, captureWarnings
import warnings
import coloredlogs
logger = getLogger("myapp")
coloredlogs.install(logger=logger)
# Combine with warnings
warnings_logger = getLogger("py.warnings")
coloredlogs.install(logger=warnings_logger)
captureWarnings(True)
class MyAppWarning(Warning):
pass
logger.warning("Logging a warning message")
warnings.warn("A warning object", MyAppWarning)
Now, run myapp.py
and see:
Nice, now you can see some problems:
- The warnings stop coming from the
myapp
logger, and they start being logged in thepy.warnings
logger instead. -
py.warnings
is a global logger, so when combining this library in other app, it will alter that other app warnings style. - The warning message when using
warnings.warn()
shows a lot more information that (for my use case) is useless.
So, the easiest way to workaround this problem would be to just use logger.warning
instead, which fixes all those problems. But then I cannot have all the extra nice tools that I get while using the warnings
module (for instance, being able to convert those to exceptions while testing, and assert them).
This is very confusing. Some questions arise, like “why am I forced to use the py.warnings
logger?”
My proposal is that Python adds a supported simple way to wire a logger and a warning class:
from logging import getLogger
logger = getLogger("myapp")
logger.captureWarnings(MyAppWarning, ...)
As simple as that, then when calling warnings.warn("Message", MyAppWarning)
, the warnings
module knows that warning has to be logged in the myapp
logger, not in the py.warnings
logger. Also, it will log it using the default output format configured in the logger
.
Warnings from any other class that doesn’t inherit from MyAppWarning
would behave as normal.
The result would be that the logging output would be exactly the same as when using logger.warning()
, but I’d be able to leverage all other tools from the warnings
module. Also, a program can declare its own warning classes and configure how and where they are logged.