python程序的stdout并未输出到supervisor的log中

用supervisor管理运行的python程序,将stdout配置到指定log文件,supervisor配置节点示例如下:

[program:web]
command = /var/www/env/bin/python run.py --port=808%(process_num)01d --address=127.0.0.1
autostart = true
startsecs = 5
user = root
redirect_stderr = true
directory = /var/www/
numprocs=4
process_name=%(program_name)s_%(process_num)02d
stdout_logfile = /var/log/supervisor/www.log

结果发现supervisor输出的日志文件 www.log 跟程序输出的不一致,少了很多日志输出。

比如同一秒并发了5个请求,www.log却只有一行日志,这样我配置好的fail2ban通过www.log日志文件的匹配规则来定位,当然就不能正确地计算出访问数量。

有想到是stdout的buffer导致的,在网上google后找到了答案:

If you are also using Supervisor to monitor and heal your long running Python projects and observed that output of your program is not being logged to stdout_logfile, it is because Python print statement does not automatically flush output to STDOUT.

One solution is using sys.stdout.flush() frequently to flush the output or if you are using Python 3.3, print(msg, flush=True) is another solution. However, a better solution is to run python with -u parameter (unbuffered mode).

较好的解决办法是修改supervisor配置,在启动python进程的cmd中添加-u参数,如:

[program:web]
command = /var/www/env/bin/python run.py -u --port=808%(process_num)01d --address=127.0.0.1

参考:

https://stackoverflow.com/questions/15453234/why-does-stdout-not-flush-when-connecting-to-a-process-that-is-run-with-supervis

https://ahmet.im/blog/redirecting-output-of-python-programs-supervisor/