如何在Python脚本中将ansible-playbook命令的STDOUT输出到日志文件?
问题原因
你的Logger类通过替换sys.stdout实现了Python代码中print内容的双输出,但os.system('ansible-playbook test3.yaml')执行的系统命令,其输出是直接通过系统层面的文件描述符写入终端的,不会经过Python的sys.stdout管道,因此日志文件无法捕获这部分内容。
解决方案
使用subprocess模块替换os.system,捕获命令的输出流,再通过Python的print方法输出(此时会经过Logger的拦截逻辑),同时完善Logger的flush方法避免输出缓冲。
修改后的teststout.py代码
import os import sys import subprocess class Logger(object): def __init__(self): self.terminal = sys.stdout self.log = open("odareplayout.log", "a") def write(self, message): self.terminal.write(message) self.log.write(message) def flush(self): # 同时刷新终端和日志文件的缓冲区,确保输出实时写入 self.terminal.flush() self.log.flush() sys.stdout = Logger() def main(): print('Hello World') cmd = 'ansible-playbook test3.yaml' # 用subprocess捕获命令输出,实时处理 process = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # 将stderr合并到stdout一起处理 text=True # 以文本模式读取输出,避免字节流处理 ) # 循环读取输出的每一行,直到进程结束 for line in iter(process.stdout.readline, ''): print(line, end='') # end=''避免重复换行,因为命令输出本身带换行符 # 等待进程执行完成,获取返回码 process.wait() if __name__ == '__main__': main()
代码说明
subprocess.Popen:创建子进程执行命令,通过stdout=subprocess.PIPE捕获输出流,stderr=subprocess.STDOUT将错误输出合并到标准输出,方便统一处理。iter(process.stdout.readline, ''):循环读取输出的每一行,实现实时输出,避免等待命令执行完才一次性输出。print(line, end=''):输出读取到的内容,此时会触发Logger的write方法,同时写入终端和日志文件。- 完善的
flush方法:确保输出内容实时刷新到终端和日志文件,不会因为缓冲区导致内容延迟写入。
执行修改后的代码,odareplayout.log会同时记录Hello World和ansible-playbook的所有输出内容。
内容的提问来源于stack exchange,提问作者Akash-BLR
相关产品推荐
相关产品推荐

