In my code I use logging.info(...
and before that I configure with logging.basicConfig(filename=...
. Is it possible to keep the logging lines in the code without them doing anything?

- 305
- 1
- 4
- 14

- 3,439
- 12
- 51
- 75
-
Does this answer your question? [How to disable logging on the standard error stream?](https://stackoverflow.com/questions/2266646/how-to-disable-logging-on-the-standard-error-stream) – Géry Ogam Oct 09 '21 at 21:48
4 Answers
You can use:
logging.disable(logging.CRITICAL)
to disable all logging calls which are at level CRITICAL or below. Effectively this disables all logging calls.
You can enable the logging for all loggers again (at their own logging levels) by doing:
logging.disable(logging.NOTSET)

- 11,722
- 5
- 72
- 103

- 118,920
- 18
- 185
- 180
Logging has the following structure:
- loggers are arranged according to a namespace hierarchy with dot separators;
- each logger has a level (
logging.WARNING
by default for the root logger andlogging.NOTSET
by default for non-root loggers) and an effective level (the effective level of the parent logger for non-root loggers with a levellogging.NOTSET
and the level of the logger otherwise); - each logger has a list of filters;
- each logger has a list of handlers;
- each handler has a level (
logging.NOTSET
by default); - each handler has a list of filters.
Logging has the following process (represented by a flowchart):
Therefore to disable a particular logger you can adopt one of the following strategies:
Set the level of the logger to
logging.CRITICAL + 1
.Using the main API:
import logging logger = logging.getLogger("foo") logger.setLevel(logging.CRITICAL + 1)
Using the config API:
import logging.config logging.config.dictConfig({ "version": 1, "loggers": { "foo": { "level": logging.CRITICAL + 1 } } })
Add a filter
lambda record: False
to the logger.Using the main API:
import logging logger = logging.getLogger("foo") logger.addFilter(lambda record: False)
Using the config API:
import logging.config logging.config.dictConfig({ "version": 1, "filters": { "all": { "()": lambda: (lambda record: False) } }, "loggers": { "foo": { "filters": ["all"] } } })
Remove the existing handlers of the logger, add a handler
logging.NullHandler()
to the logger (to prevent events from being handled by the handlerlogging.lastResort
which is alogging.StreamHandler
using the current streamsys.stderr
and a levellogging.WARNING
) and set the attributepropagate
of the logger toFalse
(to prevent events from being handled by the handlers of the ancestor loggers of the logger).Using the main API:
import logging logger = logging.getLogger("foo") for handler in logger.handlers.copy(): try: logger.removeHandler(handler) except ValueError: # in case another thread has already removed it pass logger.addHandler(logging.NullHandler()) logger.propagate = False
Using the config API:
import logging.config logging.config.dictConfig({ "version": 1, "handlers": { "null": { "class": "logging.NullHandler" } }, "loggers": { "foo": { "handlers": ["null"], "propagate": False } } })
Warning. — Contrary to strategies 1 and 2 which only prevent events logged by the logger from being emitted by the handlers of the logger and its ancestor loggers, strategy 3 also prevents events logged by the descendant loggers of the logger (e.g. logging.getLogger("foo.bar")
) to be emitted by the handlers of the logger and its ancestor loggers.
Note. — Setting the attribute disabled
of the logger to True
is not yet another strategy, as it is not part of the public API (cf. https://github.com/python/cpython/issues/80499):
import logging
logger = logging.getLogger("foo")
logger.disabled = True # DO NOT DO THIS
-
It should be noted that the `filter()` method has one small caveat. It doesn't propagate like handlers and levels do: https://www.saltycrane.com/blog/2014/02/python-logging-filters-do-not-propagate-like-handlers-and-levels-do/ So if you want to filter everything you need to walk through all handlers. – Wolph Mar 28 '19 at 14:10
-
Note that adding a `NullHandler()` will only work if there's no existing handler. Otherwise it's completely futile. – Wolph Mar 28 '19 at 14:11
-
_Levels_ and _handlers_ do not "propagate": logger's _effective level_ is inherited from parent loggers' level if not specified, and _log records_ propagate to handlers of parent loggers. But that is a good point: if you want to filter everything, you need to walk through, more precisely, all _child loggers_ (if you attach filters to loggers, like here) or all _parent handlers_ (if you attach filters to handlers, like in your blog example). I have updated my answer, thanks. – Géry Ogam Mar 28 '19 at 18:16
-
How about if I want to re-activate logging, once it has been disabled using the main api? I have a flask server and I want to activate / deactivate logging on a per request basis. – Leevi L Apr 20 '20 at 20:59
-
@LeeviL I would say just do the converse operation: if you enabled logging with the 1st solution, remove the `logging.NullHandler()` and set the `propagate` attribute to `True`; if you enabled logging with the 2nd solution, remove the `lambda record: False` filter. – Géry Ogam Apr 20 '20 at 22:18
EDIT: it seems that disabled
is not supposed to be meant for public use. Look at Maggyero's answer for alternative solutions.
Just disable the log handler and it won't write to anything anymore.
logging.getLogger().disabled = True
Do note that every logger can have handlers so there might be more.
-
1Your 2nd solution disabling the logger is a good solution. However your 1st solution setting an empty list of handlers is wrong. Firstly because it is not thread safe (you should use the `removeHandler` method which uses a `threading.RLock()` instance to accomplish that). Secondly because the `logging.lastResort` handler will be used in the absence of handlers. Instead you should have added a `logging.NullHandler()` instance (to avoid the `logging.lastResort` handler) and set `propagate` to `False` to avoid log record propagation to parent loggers' handlers. – Géry Ogam Mar 16 '19 at 16:29
-
The `lastResort` handler didn't exist in Python 2 (it was added in 3.2) so when writing this 5 years ago I wasn't aware of it ;) https://docs.python.org/3.2/library/logging.html#logging.lastResort As for thread safety, that's completely irrelevant here. Replacing a variable has no lock safety issues. I'll remove the first solution though, with the `lastResort` handler it's not a good solution anymore. – Wolph Mar 16 '19 at 20:12
-
Even if the `lastResort` handler did not exist, the message ["No handlers could be found for logger X"](https://docs.python.org/3/howto/logging.html#what-happens-if-no-configuration-is-provided) would be printed on `sys.stderr`, which is not what can be called "fully disabled logging". – Géry Ogam Mar 16 '19 at 21:39
-
That's (for Python 2) only the case when `raiseExceptions` is set which is not recommended on production systems. So the message would have been swallowed by the system. – Wolph Mar 16 '19 at 22:27
-
Finally using the `disabled` attribute is not a good idea as it is actually not part of the public API (see [my discussion](https://bugs.python.org/issue36318) with Vinay Sajip, the author of the `logging` library). So the correct solution is to either use a `lambda record: False` filter or a `logging.NullHandler()` handler without propagation. – Géry Ogam Mar 28 '19 at 10:49
-
I wasn't aware of that. It seems there's a `disable()` too: https://docs.python.org/3/library/logging.html#logging.disable Now I'm wondering how that will behave. – Wolph Mar 28 '19 at 14:07
-
Calling `logging.disable(level)` is like calling `logging.getLogger(logger).setLevel(level + 1)` on _all_ loggers. So if you want to disable logging for _all_ levels and for _all_ loggers, you can call `logging.disable(logging.CRITICAL)` or equivalently `logging.disable()`. But with this approach you cannot disable logging only for a specific logger. And if for some loggers you have defined a custom logging level higher than `logging.CRITICAL`—which is not recommended—, logging for these loggers will not be disabled (unless you specified that level in `logging.disable(level)`). – Géry Ogam Mar 28 '19 at 16:20
If you want full disable logs first should in logging.basicConfig() set levevl equal logging.NOTSET because is zero level and then logging.getLogger().disabled set True or False. https://docs.python.org/2/library/logging.html
Example for full disable:
import logging
if __name__ == '__main__':
logging.disable(logging.NOTSET)
logging.basicConfig(
format="%(levelname) -10s %(asctime)s %(filename)s:%(lineno)s %(message)s",
level=logging.NOTSET)
logging.getLogger().disabled = True # True, False
logging.critical("Critical")
logging.error("Error")
logging.warning("Warning")
logging.info("Info")
logging.debug("Debug")

- 128
- 2
- 12