Can I send STDOUT and STDERR to a log file and als

2019-01-24 05:30发布

I've searched the Internet and have found some good solutions for teeing STDOUT to 2 different places. Like to a log file and also to the screen at the same time. Here's one example:

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;

But this solution leaves STDERR going only to the screen and I want STDERR go to both the screen and also to the same log file that STDOUT is being logged to. Is that even possible?

My task is to get my build process logged, but I also want to see it on my IDE's screen as usual. And logging the error messages is just as important as logging the happy messages. And getting the errors logged to a separate log file is not a good solution.

8条回答
放荡不羁爱自由
2楼-- · 2019-01-24 05:35

Simply reassign the STDERR filehandle ...

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;

Should mention that I tested this on Windows, it works, however I use StrawberryPerl.

查看更多
别忘想泡老子
3楼-- · 2019-01-24 05:35

So you want STDERR to behave like STDOUT, going to both the screen and the same log file? Can you just dup STDERR with

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

(I don't know offhand whether you would do this before or after the call to IO::tee->new).

查看更多
Melony?
4楼-- · 2019-01-24 05:45
use PerlIO::Util;
*STDOUT->push_layer(tee => ">>/dir/dir/file");
*STDERR->push_layer(tee => ">>/dir/dir/file");

Though I use Log::Dispatch extensively, I've used the above to log what actually got displayed to the screen to a file.

查看更多
我想做一个坏孩纸
5楼-- · 2019-01-24 05:46

I wrote a minimalistic perl logger with configurable dynamic logging giving you the following 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__
查看更多
We Are One
6楼-- · 2019-01-24 05:53

You can redirect stderr to stdout at the windows shell level by doing something like:

perl stuff.pl 2>&1

See support article here for the official word.

Then you could use this stackoverflow answer to do a tee from the shell.

perl stuff.pl 2>&1 | tee stuff.txt
查看更多
Viruses.
7楼-- · 2019-01-24 05:56

I don't have a windows box to test this on, but perhaps you could do something like making a tied handle which will print to both STDOUT and a log, then redirecting STDOUT and STDERR to it?

EDIT: The only fear I have is the method of storing STDOUT for later use, I have added a second possibility for storing STDOUT for later use should the first not work on Windows. They both work for me on 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 @_;
}
查看更多
登录 后发表回答