Подтвердить что ты не робот

Могу ли я отправлять STDOUT и STDERR в файл журнала, а также на экран в Win32 Perl?

Я искал Интернет и нашел несколько хороших решений для teeing 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, как обычно. И протоколирование сообщений об ошибках столь же важно, как ведение журнала счастливых сообщений. И получение ошибок, регистрируемых в отдельном файле журнала, не является хорошим решением.

4b9b3361

Ответ 1

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

perl stuff.pl 2>&1

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

Затем вы можете использовать fooobar.com/questions/26267/..., чтобы сделать tee из оболочки.

perl stuff.pl 2>&1 | tee stuff.txt

Ответ 2

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

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

Ответ 3

use PerlIO::Util;
*STDOUT->push_layer(tee => ">>/dir/dir/file");
*STDERR->push_layer(tee => ">>/dir/dir/file");

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

Ответ 4

Просто переназначьте дескриптор файла 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.

Ответ 5

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

EDIT: Единственный страх, который у меня есть, это метод хранения 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 @_;
}

Ответ 6

попробуйте:

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 (то есть все ошибки), будут отправлять выходные данные на консоль и файл журнала.

Ответ 7

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

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

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

Ответ 8

Я написал минималистичный 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__