为什么在使用supervisord运行的进程中stdout不刷新?
我正在使用Supervisor(一个用Python写的进程管理工具)来启动和控制我的网页服务器及相关服务。有时候我需要进入pdb(其实是ipdb)来调试正在运行的服务器,但通过Supervisor实现这一点有点困难。
Supervisor通过一个叫做supervisord的守护进程来启动和控制进程,并通过一个叫做supervisorctl的客户端提供访问。这个客户端允许你用'fg'命令连接到一个已经启动的前台进程。比如这样:
supervisor> fg webserver
所有的日志数据都会发送到终端。但是我没有从pdb调试器那里收到任何文本。虽然它能接受我的输入,所以标准输入(stdin)似乎是正常工作的。
在我的调查过程中,我确认了print
和raw_input
都没有发送任何文本出去;不过在raw_input
的情况下,标准输入确实是正常的。
我还确认了这个是可以工作的:
sys.stdout.write('message')
sys.flush()
我原以为当我发出fg
命令时,就像是在标准终端中运行进程一样……但看起来supervisorctl做了一些额外的事情。例如,普通的打印输出并没有被刷新。有什么想法吗?
我该如何在使用supervisorctl的fg
命令连接到前台终端时,让pdb、标准打印等正常工作?
(可能有用的参考链接:http://supervisord.org/subprocess.html#nondaemonizing-of-subprocesses)
2 个回答
可能你的网络服务器把自己的输出(也就是它内部的日志信息)直接转到一个日志文件里了,也就是说它不管 supervisord 是怎么处理输出的,这样就导致 supervisord 无法控制输出的去向。
你可以用 tail -f
命令来查看这个日志,看看你在终端里期待看到的输出是不是出现在那里。
如果确实是这样,试着找找有没有办法配置你的网络服务器,让它不要这样做。要是实在找不到办法,可以考虑用两个终端来操作……一个用来输入,另一个用来查看输出。
原来,Python 默认会对它的输出进行缓冲处理。在某些情况下(比如这个例子),这会导致输出被延迟显示。
有一些方法可以解决这个问题:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
可以强制将缓冲区设置为零。
但我觉得更好的办法是,在启动 Python 程序时使用 -u
这个选项,这样就可以让它在不进行缓冲的状态下运行。在 supervisord.conf 文件中,只需要这样写:
command=python -u script.py
参考链接:http://docs.python.org/2/using/cmdline.html#envvar-PYTHONUNBUFFERED
另外要注意,这样做会让你的日志文件变得杂乱,特别是如果你使用了像 ipdb 这样的工具并且启用了 ANSI 颜色。不过因为这是开发环境,所以这可能并不重要。
如果这成为一个问题,另一种解决办法是先在 supervisorctl 中停止需要调试的进程,然后在另一个终端中临时运行这个进程进行调试。这样可以保持日志文件的整洁,如果你需要的话。