后台进程的日志输出到文件

Posted

技术标签:

【中文标题】后台进程的日志输出到文件【英文标题】:Log output of background process to a file 【发布时间】:2020-09-04 13:19:27 【问题描述】:

我有耗时的 SNMP walk 任务来执行,我使用 Popen 命令作为后台进程运行。如何在日志文件中捕获此后台任务的输出。在下面的代码中,我尝试对 ip_list 中的每个 IP 进行 snampwalk,并将所有结果记录到 abc.txt。但是,我看到生成的文件 abc.txt 是空的。

下面是我的示例代码 -

import subprocess
import sys

f = open('abc.txt', 'a+')

ip_list = ["192.163.1.104", "192.163.1.103", "192.163.1.101"]

for ip in ip_list:
    cmd = "snmpwalk.exe -t 1 -v2c -c public "
    cmd = cmd + ip
    print(cmd)
    p = subprocess.Popen(cmd, shell=True, stdout=f)
    p.wait()
f.close()

print("File output - " + open('abc.txt', 'r').read())

对于每个 IP,命令的示例输出可以是这样的 -

sysDescr.0 = STRING: Software: Whistler Version 5.1 Service Pack 2 (Build 2600)
sysObjectID.0 = OID: win32
sysUpTimeInstance = Timeticks: (15535) 0:02:35.35
sysContact.0 = STRING: unknown
sysName.0 = STRING: UDLDEV
sysLocation.0 = STRING: unknown
sysServices.0 = INTEGER: 72
sysORID.4 = OID: snmpMPDCompliance 

我已经尝试过 Popen。但如果这是一个耗时的后台进程,它不会将输出记录到文件中。但是,当我尝试运行 ls/dir 之类的后台进程时,它可以工作。任何帮助表示赞赏。

【问题讨论】:

您可以根据需要将Popen 输出重定向到一个文件Popen(..., stdout=..) 导入子进程 import sys f = open('abc.txt', 'w') cmd = "snmpwalk.exe -t 1 -v2c -c public 192.168.34.3" p = subprocess.Popen( cmd, shell=True, stdout=f) sys.stdout.flush() f.close() @Torxed,我尝试将文件对象传递给标准输出。但它不会将输出写入文件 你也可以不时阅读handle.stdout.read()? :) @Torxed 我也试过了,但是 stout.read 在很长的后台进程中没有打印任何东西。所以,这并不能解决问题 【参考方案1】:

这里的主要问题是对 Popen 所做的事情的期望以及我假设的工作方式。 p.wait() 这里将等待进程完成,然后再继续,这就是为什么 ls 例如可以工作,但更耗时的任务却不能。在您调用 p.stdout.flush() 之前,不会自动刷新输出。

您的设置方式更适用于:

    执行命令 等待退出 捕捉输出

然后使用它。对于您的用例,您最好使用替代库使用stdout=subprocess.PIPE 并自己捕捉它。这将意味着以下内容:

import subprocess
import sys

ip_list = ["192.163.1.104", "192.163.1.103", "192.163.1.101"]
with open('abc.txt', 'a+') as output:
    for ip in ip_list:
        print(cmd := f"snmpwalk.exe -t 1 -v2c -c public ip")
        process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) # Be wary of shell=True
        while process.poll() is None:
            for c in iter(lambda: process.stdout.read(1), ''):
                if c != '':
                    output.write(c)

with open('abc.txt', 'r') as log:
    print("File output: " + log.read())

这里要带走的关键内容是process.poll(),它检查进程是否完成,如果没有,我们将尝试使用process.stdout.read(1) 捕获输出以一次读取一个字节。如果您知道有新的线路即将推出,您可以将这三行切换为 output.write(process.stdout.readline()),一切就绪。

【讨论】:

感谢您的解释。但是,这并不能解决问题。文件中没有捕获任何内容。是空的 如果是这种情况,那么该命令确实没有输出。您能否编辑您的问题以向我们提供命令的示例输出? 我在问题中添加了示例输出供您参考。另外,当我在 cmd 中手动尝试命令时,它工作正常,我在控制台上看到了输出 @shivamgupta 我很难理解那些对你不起作用的东西。这是 SNMP 服务器侦听的详细视频(底部)、abc.txt 文件的尾部,因为我运行上面的代码(中间窗口)和此答案中的代码(顶部窗口):youtu.be/2uBrYWcmjrM - 如您所见,abc.txt 的输出几乎是瞬时的,我不太确定“文件中没有捕获任何内容”是什么意思,因为它显然确实如此。我在 Linux 机器上运行它,因为我找不到 net-snmp 的 windows 二进制文件。也许你编译的很奇怪?输出到stderr? 我在关注你。但是没有任何东西打印到日志文件中。会不会是 Windows 问题,因为我在 Windows 机器上

以上是关于后台进程的日志输出到文件的主要内容,如果未能解决你的问题,请参考以下文章

Linux后台运行python程序并输出到日志文件

多进程log4j日志混乱问题分析

shell脚本在后台运行以及日志重定向输出

linux后台自动执行命令nohup与日志查看

log4j.properties中怎样配置才能在输出的日志信息中输出进程号和线程号?

springboot 打成jar,后端进程方式日志输出到指定文件中