首页 文章

我可以将STDOUT和STDERR发送到日志文件,也可以发送到Win32 Perl中的屏幕吗?

提问于
浏览
12

我搜索过互联网并找到了一些很好的解决方案,可以将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 回答

  • 5

    您可以通过执行以下操作,在Windows shell级别将 stderr 重定向到 stdout

    perl stuff.pl 2>&1
    

    有关官方字词,请参阅support article here .

    然后你可以使用this stackoverflow answer从shell做 tee .

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

    我使用Log::Log4perl来做这样的事情 . 它可以为您处理向多个位置发送输出,包括屏幕,文件,数据库或您喜欢的任何其他内容 . 一旦你变得有点复杂,你就不应该自己做这些事情 .

    您只需向Log4perl发送一条消息,而不是打印到文件句柄,它会计算出其余部分 . 我在Mastering Perl对它进行了简短的介绍 . 它基于Log4j,你可以在Log4j中做的大部分工作都可以在Log4perl中完成,这也意味着一旦你知道它,它就变成了一种可转移的技能 .

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

    虽然我广泛使用Log::Dispatch,但我已经使用上面的内容将实际显示在屏幕上的内容记录到文件中 .

  • 8

    只需重新分配 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

    我没有一个Windows框来测试它,但也许你可以做一些事情,比如制作一个将打印到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

    尝试:

    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文件句柄的print语句(即所有错误)都会将输出发送到控制台和日志文件 .

  • 0

    所以你希望 STDERR 表现得像 STDOUT ,同时转到屏幕和同一个日志文件?你可以复制 STDERR 吗?

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

    (我不知道你是否会在致电 IO::tee->new 之前或之后这样做) .

  • 3

    我用可配置的动态日志编写了一个简约的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__
    

相关问题