Могу ли я отправить STDOUT и STDERR в файл журнала, а также на экран в Win32 Perl? - PullRequest
13 голосов
/ 07 октября 2009

Я искал в Интернете и нашел несколько хороших решений для распространения STDOUT в 2 разных местах. Как в файл журнала, а также на экран в то же время. Вот один пример:

use IO::Tee;
my $log_filename = "log.txt";
my $log_filehandle;
open( $log_filehandle, '>>', $log_filename )
  or die("Can't open $log_filename for append: $!");
my $tee = IO::Tee->new( $log_filehandle, \*STDOUT );
select $tee;

Но это решение оставляет STDERR доступным только к экрану, и я хочу, чтобы STDERR переходил как на экран, так и в тот же файл журнала, в который STDOUT регистрируется. Это вообще возможно?

Моя задача - зарегистрировать процесс сборки, но я также хочу видеть его на экране моей IDE как обычно. И регистрация сообщений об ошибках так же важна, как регистрация счастливых сообщений. И регистрация ошибок в отдельном файле журнала не является хорошим решением.

Ответы [ 8 ]

13 голосов
/ 07 октября 2009

Я использую Log :: Log4perl для подобных вещей. Он обрабатывает отправку вывода в несколько мест для вас, в том числе экран, файлы, базы данных или что-то еще, что вам нравится. Как только вы станете немного сложнее, вы не должны делать это самостоятельно.

Вместо того, чтобы печатать на файловые дескрипторы, вы просто посылаете Log4perl сообщение, и оно выясняет все остальное. У меня есть краткое введение в Мастеринг Perl . Он основан на Log4j, и большинство вещей, которые вы можете делать в Log4j, вы можете делать в Log4perl, что также означает, что как только вы его узнаете, он становится переносимым навыком.

8 голосов
/ 07 октября 2009
use PerlIO::Util;
*STDOUT->push_layer(tee => ">>/dir/dir/file");
*STDERR->push_layer(tee => ">>/dir/dir/file");

Несмотря на то, что я широко использую Log :: Dispatch , я использовал вышеописанное для записи в файл того, что фактически отображалось на экране.

5 голосов
/ 25 марта 2010

Вы можете перенаправить stderr на stdout на уровне оболочки Windows, выполнив что-то вроде:

perl stuff.pl 2>&1

См. статью поддержки здесь для официального слова.

Тогда вы могли бы использовать этот ответ стекопотока , чтобы сделать tee из оболочки.

perl stuff.pl 2>&1 | tee stuff.txt
3 голосов
/ 25 марта 2010

Просто переназначить STDERR дескриптор файла ...

use IO::Tee;
my $log_filename = "log.txt";
my $log_filehandle;
open( $log_filehandle, '>>', $log_filename )
  or die("Can't open $log_filename for append: $!");
my $tee = IO::Tee->new( $log_filehandle, \*STDOUT );
*STDERR = *$tee{IO};
select $tee;

Следует отметить, что я протестировал это на Windows, оно работает, однако я использую StrawberryPerl.

2 голосов
/ 22 апреля 2011

У меня нет окна для проверки этого, но, возможно, вы могли бы сделать что-то вроде создания привязанного дескриптора, который будет печатать как в STDOUT, так и в журнал, а затем перенаправить STDOUT и STDERR на него?

РЕДАКТИРОВАТЬ: Единственный страх, который у меня есть, это метод хранения STDOUT для последующего использования, я добавил вторую возможность для хранения STDOUT для последующего использования, если первый не работает в Windows. Они оба работают на меня в Linux.

#!/usr/bin/perl

use strict;
use warnings;

tie *NEWOUT, 'MyHandle', 'test.log';
*STDOUT = *NEWOUT;
*STDERR = *NEWOUT;

print "Print\n";
warn "Warn\n";

package MyHandle;

sub TIEHANDLE {
  my $class = shift;
  my $filename = shift;

  open my $fh, '>', $filename or die "Could not open file $filename";

  ## Use one of these next two lines to store STDOUT for later use.
  ## Both work for me on Linux, if one does not work on Windows try the other.
  open(OLDSTDOUT, '>&STDOUT') or die "Could not store STDOUT";
  #*OLDSTDOUT = *STDOUT;

  my $self = {
    loghandle => $fh,
    logfilename => $filename,
    stdout => \*OLDSTDOUT,
  };

  bless $self, $class;

  return $self;
}

sub PRINT {
  my $self = shift;
  my $log = $self->{loghandle};
  my $stdout = $self->{stdout};
  print $log @_;
  print $stdout @_;
}
1 голос
/ 17 июня 2011

попробуй:

my logfh;
my $logfn = "some/path/to/file.log";
open ($logfh, '>',$logfn ) or die "Error opening logfile $logfn\n";
my $tee = IO::Tee->new( $logfh);
my $tee2 = IO::Tee->new( $logfh, \*STDOUT );
# all naked print statements will send output to log file
select($tee);
# all STDERR print statements will send output to console
*STDERR = *$tee2{IO};

Все операторы печати, которые не указывают дескриптор файла (то есть обычные сообщения), будут отправлять выходные данные в файл журнала. Все операторы печати, использующие дескриптор файла STDERR (то есть все ошибки), будут отправлять вывод как на консоль, так и в файл журнала.

0 голосов
/ 22 апреля 2011

Я написал минималистичный perl logger с настраиваемой динамической регистрацией, предоставляющий вам следующий API:

        use strict ; use warnings ; use Exporter;
        use Configurator ; 
        use Logger ; 


        #   anonymous hash !!!
        our $confHolder = () ; 

        sub main {

                # strip the remote path and keep the bare name
                $0=~m/^(.*)(\\|\/)(.*)\.([a-z]*)/; 
                my $MyBareName = $3; 
                my $RunDir= $1 ; 

                # create the configurator object 
                my $objConfigurator = new Configurator($RunDir , $MyBareName ); 
                # get the hash having the vars 
                $confHolder = $objConfigurator ->getConfHolder () ; 
                # pring the hash vars 
                print $objConfigurator->dumpIni();  

                my $objLogger = new Logger (\$confHolder) ; 
                $objLogger->LogMsg  (   " START MAIN " ) ;  

                $objLogger->LogMsg  (   "my \$RunDir is $RunDir" ) ; 
                $objLogger->LogMsg  (   "this is a simple message" ) ; 
                $objLogger->LogErrorMsg (   "This is an error message " ) ; 
                $objLogger->LogWarningMsg   (   "This is a warning message " ) ; 
                $objLogger->LogInfoMsg  (   "This is a info message " ) ; 
                $objLogger->LogDebugMsg (   "This is a debug message " ) ; 
                $objLogger->LogTraceMsg (   "This is a trace message " ) ; 
                $objLogger->LogMsg  (   "using the following log file " .  "$confHolder->{'LogFile'}" ) ; 
                $objLogger->LogMsg  (   " STOP MAIN \n\n" ) ; 

        } #eof main 



        #Action !!!
        main(); 

        1 ; 

        __END__
0 голосов
/ 07 октября 2009

То есть вы хотите, чтобы STDERR вел себя как STDOUT, переходя как на экран, так и в один и тот же файл журнала? Вы можете просто дублировать STDERR с

open(STDERR, ">&STDOUT") or warn "failed to dup STDOUT:$!";

(Я не знаю, на месте, сделаете ли вы это до или после звонка на IO::tee->new).

...