将CGI错误输出从STDERR重定向到文件(python和perl)

5 投票
7 回答
6893 浏览
提问于 2025-04-15 16:16

我正在把一个网站迁移到Hostmonster,想知道服务器日志在哪里,这样我就可以自动扫描CGI错误。我被告知:“很抱歉,我们没有CGI错误的日志文件供你访问。”

由于一些组织上的原因,我只能使用Hostmonster和他们这个糟糕的政策,所以我想到了一个解决办法:也许我可以修改CGI脚本,把错误信息重定向到一个自定义的日志文件里。

我有很多脚本(269个),所以我需要一种简单的方法,能够在Python和Perl中把错误信息重定向到一个自定义的日志文件。

如果能考虑到文件锁定的问题就更好了,因为如果有多个脚本同时出错,理论上它们可能会同时写入同一个共享的CGI错误日志文件。

(我想用一个共享的错误日志,这样我可以每天晚上把内容发邮件给自己,然后再归档或删除它。)

我知道可能需要修改每个文件(真让人头疼),所以我希望能找到一种优雅的解决方案,只需要几行代码。谢谢。

7 个回答

3

Python中有一个叫做 cgitb 的工具。在你的脚本最上面,也就是其他导入语句之前,你需要加上这段代码:

import cgitb
cgitb.enable(False, '/home/me/www/myapp/logs/errors')

(这里的‘errors’是一个目录,网络服务器的用户可以在里面写东西。)

4

对于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

3

我最后选择的解决方案和下面的内容差不多,放在我所有脚本的开头:

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的问题,我没法“接受”任何一个答案,但我给那些指引我走向正确方向的答案投了票。再次感谢大家!

撰写回答