15

我搜索了互联网并找到了一些很好的解决方案,可以将 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 屏幕上看到它。记录错误消息与记录快乐消息一样重要。并且将错误记录到单独的日志文件中并不是一个好的解决方案。

4

8 回答 8

13

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

无需打印到文件句柄,您只需给 Log4perl 一条消息,它就会计算出其余部分。我在Mastering Perl中有一个简短的介绍。它基于 Log4j,而您在 Log4j 中可以做的大部分事情都可以在 Log4perl 中完成,这也意味着一旦您了解了它,它就变成了一种可转移的技能。

于 2009-10-07T16:22:15.993 回答
8
use PerlIO::Util;
*STDOUT->push_layer(tee => ">>/dir/dir/file");
*STDERR->push_layer(tee => ">>/dir/dir/file");

尽管我广泛使用Log::Dispatch,但我已经使用上面的方法将实际显示在屏幕上的内容记录到文件中。

于 2009-10-07T18:16:07.867 回答
5

您可以通过执行以下操作重定向stderrstdoutWindows shell 级别:

perl stuff.pl 2>&1

请参阅此处的支持文章以获取官方用语。

然后你可以使用这个 stackoverflow 答案tee从 shell中执行。

perl stuff.pl 2>&1 | tee stuff.txt
于 2010-03-24T22:07:23.390 回答
3

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

于 2010-03-25T08:53:23.703 回答
2

我没有一个 windows 框来测试这个,但也许你可以做一些事情,比如制作一个绑定句柄,它将打印到 STDOUT 和日志,然后将 STDOUT 和 STDERR 重定向到它?

编辑:我唯一担心的是存储 STDOUT 以供以后使用的方法,如果第一种在 Windows 上不起作用,我添加了第二种可能性来存储 STDOUT 以供以后使用。他们都在 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 @_;
}
于 2011-04-22T03:55:16.087 回答
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 文件句柄的打印语句(即所有错误)都将输出发送到控制台和日志文件。

于 2011-06-16T20:37:43.887 回答
0

所以你想STDERR表现得像STDOUT,去屏幕和同一个日志文件?你能不能STDERR

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

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

于 2009-10-07T16:19:57.163 回答
0

我写了一个简约的perl 记录器,带有可配置的动态日志记录,为您提供以下 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__
于 2011-04-21T20:35:42.433 回答