问题描述
在自己的云服务器上用python开了一个HTTP服务,便于下载各种实用工具,下载日志重定向到http.log文件中。执行命令如下:
nohup python -m SimpleHTTPServer 2>&1 >/home/ubuntu/download/http.log &
但是,突然发现http.log是空的。多次重启服务、删除http.log再重启服务,都无济于事,http.log依然是空的。
问题分析
1. 查看重定向
查看进程打开的文件描述符,排查重定向是否有问题:
root@VM-0-15-ubuntu:~/download# ps -ef | grep python
root 729 1 0 10:57 ? 00:00:00 python -m SimpleHTTPServer
root 875 1 0 Apr05 ? 00:00:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggers
root 927 1 0 Apr05 ? 00:00:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
root 6298 4327 0 11:27 pts/7 00:00:00 grep --color=auto python
root@VM-0-15-ubuntu:~/download#
root@VM-0-15-ubuntu:~/download# ls /proc/729/fd -lh
total 0
lr-x------ 1 root root 64 Apr 17 11:28 0 -> /dev/null
l-wx------ 1 root root 64 Apr 17 11:28 1 -> /home/ubuntu/download/http.log
lrwx------ 1 root root 64 Apr 17 11:28 2 -> '/tmp/#409843 (deleted)'
lrwx------ 1 root root 64 Apr 17 11:28 3 -> 'socket:[15759028]'
lr-x------ 1 root root 64 Apr 17 11:28 7 -> /dev/urandom
1 -> /home/ubuntu/download/http.log 表示标准输出重定向到文件/home/ubuntu/download/http.log。看来,重定向没问题。
2. 查看python输出
上网查阅资料发现:
python的标准输入和标准输出写到了缓冲中,如果日志为空,说明输出没有被刷新(flush)到文件中。
执行python程序时,添加 -u选项 或者 指定 PYTHONUNBUFFERED=x,可以指定输出不写到缓存。
root@VM-0-15-ubuntu:~# python --help
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-b : issue warnings about comparing bytearray with unicode
(-bb: issue errors)
-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
-c cmd : program passed in as string (terminates option list)
-d : debug output from parser; also PYTHONDEBUG=x
-E : ignore PYTHON* environment variables (such as PYTHONPATH)
-h : print this help message and exit (also --help)
-i : inspect interactively after running script; forces a prompt even
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
-m mod : run library module as a script (terminates option list)
-O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x
-OO : remove doc-strings in addition to the -O optimizations
-R : use a pseudo-random salt to make hash() values of various types be
unpredictable between separate invocations of the interpreter, as
a defense against denial-of-service attacks
-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew
-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE
-S : don't imply 'import site' on initialization
-t : issue warnings about inconsistent tab usage (-tt: issue errors)
-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
see man page for details on internal buffering relating to '-u'
-v : verbose (trace import statements); also PYTHONVERBOSE=x
can be supplied multiple times to increase verbosity
-V : print the Python version number and exit (also --version)
-W arg : warning control; arg is action:message:category:module:lineno
also PYTHONWARNINGS=arg
-x : skip first line of source, allowing use of non-Unix forms of #!cmd
-3 : warn about Python 3.x incompatibilities that 2to3 cannot trivially fix
file : program read from script file
- : program read from stdin (default; interactive mode if a tty)
arg ...: arguments passed to program in sys.argv[1:]
Other environment variables:
PYTHONSTARTUP: file executed on interactive startup (no default)
PYTHONPATH : ':'-separated list of directories prefixed to the
default module search path. The result is sys.path.
PYTHONHOME : alternate <prefix> directory (or <prefix>:<exec_prefix>).
The default module search path uses <prefix>/pythonX.X.
PYTHONCASEOK : ignore case in 'import' statements (Windows).
PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.
PYTHONHASHSEED: if this variable is set to 'random', the effect is the same
as specifying the -R option: a random value is used to seed the hashes of
str, bytes and datetime objects. It can also be set to an integer
in the range [0,4294967295] to get hash values with a predictable seed.
root@VM-0-15-ubuntu:~#
于是,我添加了 -u选项:
nohup python -u -m SimpleHTTPServer 2>&1 >/home/ubuntu/download/http.log &
这次,http.log里有日志了:
Serving HTTP on 0.0.0.0 port 8000 ...
但是,日志只打了这一句,后面通过浏览器下载文件,日志都不再更新。。。
最后,改变重定向方式,使用 &> 重定向:
nohup python -u -m SimpleHTTPServer &> /home/ubuntu/download/http.log &
如此,日志打印就正常了:
root@VM-0-15-ubuntu:~/download# tail -f http.log
Serving HTTP on 0.0.0.0 port 8000 ...
61.48.208.128 - - [17/Apr/2022 12:27:26] "GET / HTTP/1.1" 200 -
61.48.208.128 - - [17/Apr/2022 12:27:27] "GET / HTTP/1.1" 200 -
61.48.208.128 - - [17/Apr/2022 12:27:40] "GET /SecureCRT%206.5.0.zip HTTP/1.1" 200 -
&> 重启服务后日志会清空,改成 &>> 日志就能追加了:
nohup python -u -m SimpleHTTPServer &>> /home/ubuntu/download/http.log &
(完)