将CGI错误输出从STDERR重定向到文件(python和perl)
我正在把一个网站迁移到Hostmonster,想知道服务器日志在哪里,这样我就可以自动扫描CGI错误。我被告知:“很抱歉,我们没有CGI错误的日志文件供你访问。”
由于一些组织上的原因,我只能使用Hostmonster和他们这个糟糕的政策,所以我想到了一个解决办法:也许我可以修改CGI脚本,把错误信息重定向到一个自定义的日志文件里。
我有很多脚本(269个),所以我需要一种简单的方法,能够在Python和Perl中把错误信息重定向到一个自定义的日志文件。
如果能考虑到文件锁定的问题就更好了,因为如果有多个脚本同时出错,理论上它们可能会同时写入同一个共享的CGI错误日志文件。
(我想用一个共享的错误日志,这样我可以每天晚上把内容发邮件给自己,然后再归档或删除它。)
我知道可能需要修改每个文件(真让人头疼),所以我希望能找到一种优雅的解决方案,只需要几行代码。谢谢。
7 个回答
Python中有一个叫做 cgitb 的工具。在你的脚本最上面,也就是其他导入语句之前,你需要加上这段代码:
import cgitb
cgitb.enable(False, '/home/me/www/myapp/logs/errors')
(这里的‘errors’是一个目录,网络服务器的用户可以在里面写东西。)
对于Perl语言,你只需要关闭并重新打开STDERR
,这样就可以把错误信息指向你选择的文件了。
close STDERR;
open STDERR, '>>', '/path/to/your/log.txt'
or die "Couldn't redirect STDERR: $!";
warn "this will go to log.txt";
另外,你也可以考虑使用一个叫做文件句柄多路复用器的工具,比如File::Tee。
我最后选择的解决方案和下面的内容差不多,放在我所有脚本的开头:
Perl:
open(STDERR,">>","/path/to/my/cgi-error.log")
or die "Could not redirect STDERR: $OS_ERROR";
Python:
sys.stderr = open("/path/to/my/cgi-error.log", "a")
显然在Perl中,你不需要在重新打开STDERR之前先关闭它。
通常我还是会关闭它,作为一种最佳实践,但正如我在问题中提到的,我有269个脚本,想尽量减少改动。(而且,听起来虽然很糟糕,但直接重新打开已经打开的文件句柄似乎更符合Perl的风格。)
如果将来还有其他人遇到类似的情况,这里是我打算一次性更新所有脚本的方法:
Perl:
find . -type f -name "*.pl" -exec perl -pi.bak -e 's%/usr/bin/perl%/usr/bin/perl\nopen(STDERR,">>","/path/to/my/cgi-error.log")\n or die "Could not redirect STDERR: \$OS_ERROR";%' {} \;
Python:
find . -type f -name "*.py" -exec perl -pi.bak -e 's%^(import os, sys.*)%$1\nsys.stderr = open("/path/to/my/cgi-error.log", "a")%' {} \;
我发这些命令的原因是,我花了不少时间调整语法才能让这些命令正常工作(比如,把Couldn't改成Could not,把#!/usr/bin/perl改成/usr/bin/perl,这样shell就不会把!当作历史命令字符来解释,使用$OS_ERROR而不是$!等等)。
感谢所有评论的人。由于没有人同时回答Perl和Python的问题,我没法“接受”任何一个答案,但我给那些指引我走向正确方向的答案投了票。再次感谢大家!