繁体   English   中英

如何在python扩展上隐藏stdout/stderr

[英]How to hide stdout/stderr on python extension

我想在 python 脚本中隐藏 stdout/stderr但是当 python 模块需要一个时,打印不是在 python 脚本本身中完成,而是在底层 .c 扩展中完成。

netsnmp python模块就是这种情况,它需要编译,问题是有一些'printf'直接进入我想捕获和隐藏的C(client_intf.c)代码中:

from netsnmp import *
import sys,os
devnull = open(os.devnull, 'w')
sys.stdout, sys.stderr = devnull, devnull
session = Session(DestHost='myhostthatdoesnotexisttogenerateerror',Version=2,Community='demopublic')

当我运行它时,我仍然有一些痕迹:

python test.py
getaddrinfo: myhostthatdoesnotexisttogenerateerror nodename nor servname provided, or not known
error:snmp_new_session: Couldn't open SNMP session

如何摆脱 stdout/stderr 上的这些消息? 这很重要,因为我正在开发 Nagios 插件,而且我可以负担得起这样的输出(尽管如此,我想捕获它们以引发自定义异常)

Eric 的回答非常好,但它有一个重要的缺点:如果您已经使用sys.stderr来初始化一些东西,它将变得毫无用处。 例如:如果您使用sys.stderr创建了一个自定义错误记录器,它将停止工作。

这是一个修改后的版本:

import os
from contextlib import contextmanager

@contextmanager
def hide_stderr():
    """ Low level stderr supression. """
    newstderr = os.dup(2)
    devnull = os.open('/dev/null', os.O_WRONLY)
    os.dup2(devnull, 2)
    os.close(devnull)
    yield
    os.dup2(newstderr, 2)


@contextmanager
def hide_stdout():
    """ Low level stdout supression. """
    newstderr = os.dup(1)
    devnull = os.open('/dev/null', os.O_WRONLY)
    os.dup2(devnull, 1)
    os.close(devnull)
    yield
    os.dup2(newstderr, 1)


import sys

my_stderr = sys.stderr
print("Test 1: no stderr, no stdout")
with hide_stderr():
    with hide_stdout():
        print("1 stdout")
        print("2 stderr", file=my_stderr)
print("Test 2: no stderr, but stdout")
with hide_stderr():
    print("1 stdout")
    print("2 stderr", file=my_stderr)
print("Test 3: stderr, no stdout")
with hide_stdout():
    print("1 stdout")
    print("2 stderr", file=my_stderr)
print("Test 4: stderr and stdout")
print("1 stdout")
print("2 stderr", file=my_stderr)

请注意,主要区别在于最后使用了os.dup2 我们从我们所做的副本中恢复文件描述符,我们不会弄乱sys.stderr

根据您的操作系统(似乎至少适用于 Windows 和 Linux),以下内容将通过替换(低级)文件描述符完全关闭 fx stdout

nulf = os.open(os.devnull, os.O_WRONLY)
os.dup2(nulf, stdout.fileno())
os.close(nulf)

stderr相同,在交互模式下似乎效果不佳(我猜 python 解释器试图将它的内容写入 stderr)。

此解决方案将具有相同的效果,即在启动解释器时重定向到/dev/null或等效项(除非它稍后生效),包括以本机代码制作的任何打印输出(当然还有您的脚本尝试执行的任何打印输出) . 如果您想进行任何日志记录,您必须为此打开一个文件(如果您想将stdout重定向到文件,您也可以首先打开os.devnull以外的文件)。

请注意,通常程序不会检查打印输出的结果,在这种情况下,可以简单地关闭描述符(即os.close(stdout.fileno()) ),但如果扩展程序实际检查结果并采取行动,则会失败基于此不同。

这是临时阻止 stdout 和 stderr 的代码:

from netsnmp import *
import sys,os

newstdout = os.dup(1)
newstderr = os.dup(2)
devnull = os.open('/dev/null', os.O_WRONLY)
os.dup2(devnull, 1)
os.dup2(devnull, 2)
os.close(devnull)
# stdout/stderr are blocked here
print "I will be back but nobody will know it"
session = Session(DestHost='myhostthatdoesnotexisttogenerateerror',Version=2,Community='demopublic')
sys.stdout = os.fdopen(newstdout, 'w')
sys.stderr = os.fdopen(newstderr, 'w')
# stdout/stderr are unblocked here
print "I'm back"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM