English 中文(简体)
Redirecting CGI error output from STDERR to a file (python AND perl)
原标题:

I m moving a website to Hostmonster and asked where the server log is located so I can automatically scan it for CGI errors. I was told, "We re sorry, but we do not have cgi errors go to any files that you have access to."

For organizational reasons I m stuck with Hostmonster and this awful policy, so as a workaround I thought maybe I d modify the CGI scripts to redirect STDERR to a custom log file.

I have a lot of scripts (269) so I need an easy way in both Python and Perl to redirect STDERR to a custom log file.

Something that accounts for file locking either explicitly or implicitly would be great, since a shared CGI error log file could theoretically be written to by more than one script at once if more than one script fails at the same time.

(I want to use a shared error log so I can email its contents to myself nightly and then archive or delete it.)

I know I may have to modify each file (grrr), that s why I m looking for something elegant that will only be a few lines of code. Thanks.

最佳回答

The solution I finally went with was similar to the following, near the top of all my scripts:

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")

Apparently in Perl you don t need to close the STDERR handle before reopening it.

Normally I would close it anyway as a best practice, but as I said in the question, I have 269 scripts and I m trying to minimize the changes. (Plus it seems more Perlish to just re-open the open filehandle, as awful as that sounds.)

In case anyone else has something similar in the future, here s what I m going to do for updating all my scripts at once:

Perl:

find . -type f -name "*.pl" -exec perl -pi.bak -e  s%/usr/bin/perl%/usr/bin/perl
open(STDERR,">>","/path/to/my/cgi-error.log")
    or die "Could not redirect STDERR: $OS_ERROR";%  {} ;

Python:

find . -type f -name "*.py" -exec perl -pi.bak -e  s%^(import os, sys.*)%$1
sys.stderr = open("/path/to/my/cgi-error.log", "a")%  {} ;

The reason I m posting these commands is that it took me quite a lot of syntactical massaging to get those commands to work (e.g., changing Couldn t to Could not, changing #!/usr/bin/perl to just /usr/bin/perl so the shell wouldn t interpret ! as a history character, using $OS_ERROR instead of $!, etc.)

Thanks to everyone who commented. Since no one answered for both Perl and Python I couldn t really "accept" any of the given answers, but I did give votes to the ones which led me in the right direction. Thanks again!

问题回答

For Perl, just close and re-open STDERR to point to a file of your choice.

close STDERR;
open STDERR,  >> ,  /path/to/your/log.txt  
  or die "Couldn t redirect STDERR: $!";

warn "this will go to log.txt";

Alternatively, you could look into a filehandle multiplexer like File::Tee.

Python: cgitb. At the top of your script, before other imports:

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

(‘errors’ being a directory the web server user has write-access to.)

In Perl try CGI::Carp

BEGIN { 
use CGI::Carp qw(carpout); 
use diagnostics;
open(LOG, ">errors.txt"); 
carpout(LOG);
close(LOG);
}

use CGI::Carp qw(fatalsToBrowser);

python:

import sys

sys.stderr = open( file_path_with_write_permission/filename ,  a )

Python has the sys.stderr module that you might want to look into.

>>>help(sys.__stderr__.read)
Help on built-in function read:

read(...)
    read([size]) -> read at most size bytes, returned as a string.

    If the size argument is negative or omitted, read until EOF is reached.
    Notice that when in non-blocking mode, less data than what was requested
    may be returned, even if no size parameter was given.

You can store the output of this in a string and write that string to a file.

Hope this helps

In my Perl CGI programs, I usually have

BEGIN {
  open(STDERR, >> , stderr.log );
}

right after shebang line and "use strict;use warnings;". If you want, you may append $0 to file name. But this will not solve multiple programs problem, as several copies of one programs may be run simultaneously. I usually just have several output files, for every program group.





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签