Python日志记录和子流程输出及错误流
我想启动一个python进程,并将子进程错误消息记录到父脚本的日志对象中。理想情况下,我希望将日志流统一到一个文件中。我可以访问日志类的输出流吗?我知道的一个解决方案是使用proc log进行日志记录。如下面的回答所述,我可以从proc.stdin和stderr中读取,但是我会有重复的日志头。我想知道是否有办法将日志类的底层文件描述符直接传递给子流程Python日志记录和子流程输出及错误流,python,logging,Python,Logging,我想启动一个python进程,并将子进程错误消息记录到父脚本的日志对象中。理想情况下,我希望将日志流统一到一个文件中。我可以访问日志类的输出流吗?我知道的一个解决方案是使用proc log进行日志记录。如下面的回答所述,我可以从proc.stdin和stderr中读取,但是我会有重复的日志头。我想知道是否有办法将日志类的底层文件描述符直接传递给子流程 logging.basicConfig(filename="test.log",level=logging.DEBUG) logging.info
logging.basicConfig(filename="test.log",level=logging.DEBUG)
logging.info("Started")
procLog = open(os.path.expanduser("subproc.log"), 'w')
proc = subprocess.Popen(cmdStr, shell=True, stderr=procLog, stdout=procLog)
proc.wait()
procLog.flush()
基于此,你可以
select。选择进行阻止,直到有要读取的输出
proc.stdout
或proc.stderr
/tmp/test.log
并运行命令ls-laR/tmp
。改变以适应你的需要
(PS:通常/tmp包含普通用户无法读取的目录,因此运行ls-laR/tmp
会产生到stdout和stderr的输出。下面的代码会在生成这两个流时正确地交错。)
编辑: 您可以将
stdout
和stderr
重定向到logfile=open('/tmp/test.log','a')
。
但是,这样做的一个小困难是,任何同时写入/tmp/test.log
的记录器处理程序都不会知道子进程正在写入什么,因此日志文件可能会被篡改
如果在子流程执行其业务时不进行日志记录调用,那么唯一的问题是日志记录器处理程序在子流程完成后在文件中的位置错误。这可以通过打电话来解决
handler.stream.seek(0, 2)
因此,处理程序将在文件末尾继续写入
这是可行的,但我试图附加到日志文件的输出是来自另一个程序的记录器流。所以,如果我这样做了,我会得到每行两个时间戳(如果不清楚,请告诉我)。那么,有没有一种方法可以直接写入未加密的日志文件描述符。。。绕过日志前缀?您可以临时将日志格式更改为
'%(message)s'
。我已经在上面添加了一些代码来实现这一点。嗯,是的,这是可行的,但是如果我可以将文件描述符传递到流程中,不是会更优雅吗?那真的不行吗?我认为你最初的解决方案是最简单的。我现在看到了主要使用记录器的优势。。。更好地格式化和控制流。。。甚至可以将流“tee”到控制台。谢谢。好的,我会把我的原始解决方案添加到帖子中。
handler.stream.seek(0, 2)
import logging
import subprocess
import contextlib
import shlex
logger = logging.getLogger(__name__)
@contextlib.contextmanager
def suspended_logger():
root = logging.getLogger()
handler = root.handlers[0]
yield
handler.stream.seek(0, 2)
def main():
logging.basicConfig(filename = '/tmp/test.log', filemode = 'w',
level = logging.DEBUG)
logger.info("Started")
with suspended_logger():
cmdStr = 'test2.py 1>>/tmp/test.log 2>&1'
logfile = open('/tmp/test.log', 'a')
proc = subprocess.Popen(shlex.split(cmdStr),
stdout = logfile,
stderr = logfile)
proc.communicate()
logger.info("Done")
if __name__ == '__main__':
main()