如何禁用标准错误流上的日志记录?
如何在Python中的标准错误流上禁用日志记录?这不起作用:
import logging
logger = logging.getLogger()
logger.removeHandler(sys.stderr)
logger.warning('foobar') # emits 'foobar' on sys.stderr
How to disable logging on the standard error stream in Python? This does not work:
import logging
logger = logging.getLogger()
logger.removeHandler(sys.stderr)
logger.warning('foobar') # emits 'foobar' on sys.stderr
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
我找到了一个解决方案:
这将阻止日志记录发送到包含控制台日志记录的上层记录器。
I found a solution for this:
This will prevent logging from being sent to the upper logger that includes the console logging.
我用:
I use:
您可以使用:
其中 your_level 是其中之一:
因此,如果您将 your_level 设置为 logging.CRITICAL,您将只收到发送的关键消息通过:
将 your_level 设置为 logging.DEBUG 将显示所有级别的日志记录。
有关更多详细信息,请查看日志记录示例。
以相同的方式更改每个处理程序的级别,使用 处理程序.setLevel() 函数。
You can use:
where your_level is one of those:
So, if you set your_level to logging.CRITICAL, you will get only critical messages sent by:
Setting your_level to logging.DEBUG will show all levels of logging.
For more details, please take a look at logging examples.
In the same manner to change level for each Handler use Handler.setLevel() function.
使用上下文管理器 - [最简单]
使用示例:
如果您需要[更复杂]细粒度的解决方案,您可以查看高级记录器
Using Context manager - [ most simple ]
Example of use:
If you need a [more COMPLEX] fine-grained solution you can look at AdvancedLogger
(长久以来的死问题,但对于未来的搜索者)
更接近原始海报的代码/意图,这在 python 2.6 下对我有用
我必须解决的问题是在添加新的之后删除 stdout 处理程序一;如果不存在处理程序,记录器代码似乎会自动重新添加标准输出。
IndexOutOfBound 修复: 如果在实例化 lhStdout 时遇到 IndexOutOfBound 错误,请将实例化移至添加文件处理程序之后,即
(long dead question, but for future searchers)
Closer to the original poster's code/intent, this works for me under python 2.6
The gotcha I had to work out was to remove the stdout handler after adding a new one; the logger code appears to automatically re-add the stdout if no handlers are present.
IndexOutOfBound Fix: If you get a IndexOutOfBound Error while instantiating lhStdout, move the instantiation to after adding your file handler i.e.
完全禁用日志记录:
启用日志记录:
其他答案提供了不能完全解决问题的解决方法,例如
和,对于某些
n
大于 50,第一个解决方案的问题是它仅适用于根记录器。使用logging.getLogger(__name__)创建的其他记录器不会被此方法禁用。
第二种解决方案确实影响所有日志。 通过使用大于 50 的级别进行日志记录来覆盖它。
但它将输出限制为高于给定级别的级别,因此可以
据我所知(在查看 source) 是完全禁用日志记录的唯一方法。
To fully disable logging:
To enable logging:
Other answers provide work arounds which don't fully solve the problem, such as
and, for some
n
greater than 50,The problem with the first solution is that it only works for the root logger. Other loggers created using, say,
logging.getLogger(__name__)
are not disabled by this method.The second solution does affect all logs. But it limits output to levels above that given, so one could override it by logging with a level greater than 50.
That can be prevented by
which as far as I can tell (after reviewing the source) is the only way to fully disable logging.
这里有一些非常好的答案,但显然最简单的答案没有得到太多考虑(仅来自无穷大)。
这将禁用根记录器,从而禁用所有其他记录器。
我还没有真正测试过,但它应该也是最快的。
从 python 2.7 中的日志记录代码中我看到这
意味着当它被禁用时不会调用任何处理程序,并且它应该比过滤到非常高的值或设置无操作处理程序更有效。
There are some really nice answers here, but apparently the simplest is not taken too much in consideration (only from infinito).
This disables the root logger, and thus all the other loggers.
I haven't really tested but it should be also the fastest.
From the logging code in python 2.7 I see this
Which means that when it's disabled no handler is called, and it should be more efficient that filtering to a very high value or setting a no-op handler for example.
日志记录具有以下结构:
logging.WARNING
,非根记录器默认为logging.NOTSET
)和一个有效级别(记录器的第一个级别及其祖先不同于logging.NOTSET
,否则为logging.NOTSET
);logging.NOTSET
);日志记录有以下过程(用流程图表示):
因此,要禁用特定记录器,您可以采用以下策略之一:
将记录器的级别设置为
logging.CRITICAL + 1
。使用主要 API:
使用配置 API:
向记录器添加过滤器
lambda record: False
。使用主要 API:
使用配置 API:
删除记录器的现有处理程序,向记录器添加一个
logging.NullHandler()
处理程序(以防止记录传递到logging.lastResort
处理程序 当在记录器及其中找不到处理程序时祖先,它是一个logging.StreamHandler
处理程序,具有发送到sys.stderr
流的logging.WARNING
级别)和 将记录器的propagate
属性设置为False
(防止记录被传递给记录器祖先的处理程序)。使用主要 API:
使用配置 API:
警告。 - 与策略 1 和 2 相反,策略 1 和 2 仅阻止记录器记录记录(例如
logging.getLogger("foo")< /code>)避免由记录器及其祖先的处理程序发出,策略 3 还可以防止记录器的后代记录记录(例如
logging.getLogger("foo.bar" )
) 由记录器及其祖先的处理程序发出。注意 - 将记录器的
disabled
属性设置为True
并不是另一种策略,因为它不是公共 API 的一部分(参见.https://bugs.python.org/issue36318):Logging has the following structure:
logging.WARNING
by default for the root logger andlogging.NOTSET
by default for non-root loggers) and an effective level (the first level of the logger and its ancestors different fromlogging.NOTSET
,logging.NOTSET
otherwise);logging.NOTSET
by default);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:
Using the config API:
Add a filter
lambda record: False
to the logger.Using the main API:
Using the config API:
Remove the existing handlers of the logger, add a
logging.NullHandler()
handler to the logger (to prevent records from being passed to thelogging.lastResort
handler when no handler is found in the logger and its ancestors, which is alogging.StreamHandler
handler with alogging.WARNING
level that emits to thesys.stderr
stream) and set thepropagate
attribute of the logger toFalse
(to prevent records from being passed to the handlers of the logger’s ancestors).Using the main API:
Using the config API:
Warning. — Contrary to strategies 1 and 2 which only prevent records logged by the logger (e.g.
logging.getLogger("foo")
) from being emitted by the handlers of the logger and its ancestors, strategy 3 also prevents records logged by the descendants of the logger (e.g.logging.getLogger("foo.bar")
) to be emitted by the handlers of the logger and its ancestors.Note. — Setting the
disabled
attribute of the logger toTrue
is not yet another strategy, as it is not part of the public API (cf. https://bugs.python.org/issue36318):无需转移标准输出。这是更好的方法:
更简单的方法是:
No need to divert stdout. Here is better way to do it:
An even simpler way is:
这里的答案很混乱。 OP 再清楚不过了:他想停止给定记录器的控制台输出。在他的示例中,这实际上是根记录器,但对于大多数用途而言,情况并非如此。这不是关于禁用处理程序或其他什么。也不涉及从
stderr
更改为stdout
。令人困惑的事实是,具有零处理程序的非根记录器(其中根记录器也具有零处理程序)仍将输出到控制台(
stderr
而不是stdout
)。试试这个:我查看了源代码*。当框架发现 Logger 没有处理程序时,它会以一种有趣的方式表现。在这种情况下,
logging
框架将简单地对任何发现没有处理程序的记录器(包括来自其父级或更高级别记录器的任何记录器)使用lastResort
处理程序。lastResort.stream()
输出到sys.stderr
。因此,第一个解决方案是为您的非根记录器提供一个非控制台处理程序,例如
FileHandler
(注意,并非所有StreamHandler
都必须输出到控制台!)...第二个解决方案(对于上面的简单示例)是通过为根记录器提供一个不会输出到的处理程序来停止此
lastResort
输出安慰。在这种情况下,无需停止传播,my_logger.propagate = False
。当然,如果记录器存在复杂的层次结构,您可能必须遵循向上的传播路径来识别具有输出到控制台的处理程序的任何记录器。第三种解决方案是替换
logging.lastResort
:同样,在复杂的层次结构中,更高的记录器中可能有处理程序输出到控制台。
注意仅仅设置
my_logger.propagate = False
是不够的:在这种情况下,框架将看到my_logger
没有处理程序,并调用< code>lastResort:在上面的代码片段中尝试一下。NB2 如果您确实想抑制根记录器的控制台输出,解决方案 2) 或 3) 可以使用。但它们不一定会抑制其他记录器的控制台输出。 (注意,通常他们会这样做,因为
parent
...parent
...parent
几乎总是导致根记录器。但可以想象,您可能想要将记录器的parent
设置为None
)。有必要了解其机制,然后进行合理化。一旦你理解了这个机制,事情就非常简单了。
* 源代码(注意 Python 3.10)实际上并不难理解。如果您查看方法
Logger._log
(发送所有消息的地方),该方法以self.handle(record)
结尾,该方法调用self.callHandlers(record)
计算找到的处理程序的数量,包括使用 Logger.parent 向上爬,检查祖先记录器的处理程序......然后:这个
lastResort
是它本身是一个StreamHandler
,它输出到stream
方法中的sys.stderr
。The answers here are confused. The OP could hardly be clearer: he wants to stop output to the console for a given logger. In his example, this is actually the root logger, but for most purposes this won't be the case. This is not about disabling handlers, or whatever. Nor about changing from
stderr
tostdout
.The confusing truth is that a non-root logger with ZERO handlers where the root logger also has ZERO handlers will still output to console (
stderr
rather thanstdout
). Try this:I looked at the source code*. When the framework discovers that a
Logger
has no handlers it behaves in a funny way. In this case thelogging
framework will simply use alastResort
handler with any logger where it is found to have no handlers (including any from its parent or higher loggers).lastResort.stream()
outputs tosys.stderr
.A first solution, therefore, is to give your non-root logger a non-console handler such as
FileHandler
(NB not allStreamHandler
s necessarily output to console!)...A second solution (for the simple example above) is to stop this
lastResort
output by giving your root logger a handler which does not output to console. In this case it is not necessary to stop propagation,my_logger.propagate = False
. If there is a complex hierarchy of loggers, of course, you may have to follow the path of propagation upwards to identify any loggers with handlers outputting to console.A third solution would be to substitute
logging.lastResort
:Again, in a complex hierarchy, there may be handlers in higher loggers outputting to console.
NB just setting
my_logger.propagate = False
is NOT sufficient: in that case the framework will see thatmy_logger
has no handlers, and call uponlastResort
: try it in the above snippet.NB2 if you did want to suppress console output for the root logger, solutions 2) or 3) would work. But they wouldn't suppress console output for other loggers, necessarily. (NB usually they would because
parent
...parent
...parent
almost always leads to the root logger. But conceivably you might want to set a logger'sparent
toNone
).It's necessary to understand the mechanism, and then to rationalise. Once you understand the mechanism it's really quite easy.
* Source code (NB Python 3.10) is not in fact that difficult to follow. If you look at method
Logger._log
(where all messages get sent) this ends withself.handle(record)
, which callsself.callHandlers(record)
which counts the number of handlers found, including by climbing upwards usingLogger.parent
, examining the handlers of ancestor loggers ... and then:This
lastResort
is itself aStreamHandler
, which outputs tosys.stderr
in methodstream
.这将阻止来自第三个库的所有日志记录,如此处所述
https://docs.python.org/ 3/howto/logging.html#configuring-logging-for-a-library
This will prevent all logging from a third library which it used as decribed here
https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library
考虑到您已经创建了自己的处理程序,那么在将它们添加到记录器之前,您可以执行以下操作:
这将删除默认的 StreamHandler。
在遇到不需要的日志发送到 stderr 后,这在 Python 3.8 上对我有用,而这些日志应该只记录到文件中。
Considering you have created your own handlers, then right before you add them to the logger, you can do:
Which will remove the default StreamHandler.
This worked for me on Python 3.8 after encountering unwanted emitting of logs to stderr, when they should have been only recorded onto a file.
这不是 100% 的解决方案,但这里的答案都没有解决我的问题。我有自定义日志记录模块,它根据严重性输出彩色文本。我需要禁用标准输出输出,因为它复制了我的日志。我同意将关键日志输出到控制台,因为我几乎不使用它。我没有测试它的 stderr,因为我不在日志记录中使用它,但应该与 stdout 一样工作。它将 CRITICAL 设置为标准输出(如果需要,则为标准错误)的最低严重性。
It is not 100% solution, but none of the answers here solved my issue. I have custom logging module which outputs colored text according to severity. I needed to disable stdout output since it was duplicating my logs. I'm OK with critical logs being outputted to console since I almost don't use it. I didn't test it for stderr since I don't use it in my logging, but should work same way as stdout. It sets CRITICAL as minimal severity just for stdout (stderr if requested).
控制台输出:
test.log文件内容:
Console output:
test.log file content:
原因是您创建的所有记录器都
将父字段/属性设置为根记录器(这是您使用的记录器:
当您调用时,
它将调用记录器的所有处理程序,以及父记录器的处理程序因此,简而言之,它将调用将在 std.err 中打印的根记录器。您如何解决这个问题?全局:
我的首选解决方案是静音根记录器。仅适用于我的记录器:
这是当您调用 .info、.debug 等时调用的代码:
https://github.com/python/cpython/ blob/44bd3fe570da9115bec67694404b8da26716a1d7/Lib/logging/init.py#L1758
请注意它如何遍历记录器的所有处理程序以及父记录器。第 1766 行它使用父级。
The reason is all loggers you create with
have a parent field/attribute set to the root logger (which is the logger you get with:
when you call
It will call all the handlers of your logger, and also, the handlers of the parent logger of your logger (in a recursive manner). And so, in few words it will call the root logger which will print in the std.err. How do you solve it? two solutions, global:
My preferred solution is to mute root logger only for my logger:
This is the code that gets called when you call .info, .debug, etc:
https://github.com/python/cpython/blob/44bd3fe570da9115bec67694404b8da26716a1d7/Lib/logging/init.py#L1758
notice how it goes through all handlers of your logger, and parents loggers too. Line 1766 it uses the parent.
我不太了解日志记录模块,但我以通常只想禁用调试(或信息)消息的方式使用它。您可以使用 Handler.setLevel() 将日志记录级别设置为 CRITICAL 或更高。
另外,您可以将 sys.stderr 和 sys.stdout 替换为打开用于写入的文件。请参阅 http://docs.python.org/library/sys.html#sys .标准输出。但我不建议这样做。
I don't know the logging module very well, but I'm using it in the way that I usually want to disable only debug (or info) messages. You can use
Handler.setLevel()
to set the logging level to CRITICAL or higher.Also, you could replace sys.stderr and sys.stdout by a file open for writing. See http://docs.python.org/library/sys.html#sys.stdout. But I wouldn't recommend that.
您还可以:
You could also:
通过更改“logging.config.dictConfig”中的一个级别,您将能够将整个日志记录级别提升到一个新级别。
})
By changing one level in the "logging.config.dictConfig" you'll be able to take the whole logging level to a new level.
})
使用装饰器找到了一个优雅的解决方案,它解决了以下问题:如果您正在编写一个具有多个函数的模块,每个函数都有多个调试消息,并且您希望禁用除您目前正在关注的一个?
您可以使用装饰器来做到这一点:
然后,您可以这样做:
即使您从
function_being_focused
中调用function_already_debugged
,来自function_already_debugged
的调试消息也不会被展示。这可确保您只能看到您所关注的函数的调试消息。
希望有帮助!
Found an elegant solution using decorators, which addresses the following problem: what if you are writing a module with several functions, each of them with several debugging messages, and you want to disable logging in all functions but the one you are currently focusing on?
You can do it using decorators:
Then, you can do:
Even if you call
function_already_debugged
from withinfunction_being_focused
, debug messages fromfunction_already_debugged
won't be showed.This ensures you will see only the debug messages from the function you are focusing on.
Hope it helps!
您可以更改特定处理程序的调试模式级别,而不是完全禁用它。
因此,如果您有这样的情况,您只想停止控制台的调试模式,但仍然需要保留其他级别,例如错误。你可以像下面这样做
You can change the level of debug mode for specific handler instead of completely disable it.
So if you have a case you want to stop the debug mode for console only but you still need to keep the other levels like the Error. you can do this like the following
执行此操作的另一种方法(至少在 Python 3 中,我没有检查 Python 2)是首先创建 FileHandler,然后调用 basicConfig 方法,如下所示:
Yet another way of doing this (at least in Python 3, I didn't check Python 2), is to first create your FileHandler and then call the basicConfig method, like this:
对您希望能够暂时禁用的处理程序进行子类化:
按名称查找处理程序非常容易:
一旦找到:
subclass the handler you want to be able to disable temporarily:
finding the handler by name is quite easy:
once found: