2009-10-07 3 views
12

Ich habe das Internet durchsucht und habe einige gute Lösungen gefunden, um STDOUT an 2 verschiedene Orte abzureißen. Wie eine Protokolldatei und gleichzeitig auf dem Bildschirm. Hier ist ein Beispiel:Kann ich STDOUT und STDERR an eine Protokolldatei und auch an den Bildschirm in Win32 Perl senden?

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; 

Aber diese Lösung läßt STDERR geht nur auf den Bildschirm, und ich will STDERR gehen sowohl den Bildschirm als auch auf die gleiche Protokolldatei, die STDOUT protokolliert wird. Ist das überhaupt möglich?

Meine Aufgabe ist es, meinen Build-Prozess zu protokollieren, aber ich möchte es auch wie gewohnt auf dem Bildschirm meiner IDE sehen. Das Protokollieren der Fehlermeldungen ist genauso wichtig wie das Protokollieren der glücklichen Nachrichten. Und es ist keine gute Lösung, die Fehler in einer separaten Protokolldatei zu protokollieren.

Antwort

5

können Sie leiten stderr zu stdout an den Fenstern von Level Shell wie etwas zu tun:

perl stuff.pl 2>&1 

Siehe support article here für das offizielle Wort.

Dann könnten Sie this stackoverflow answer verwenden, um eine tee aus der Shell zu tun.

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

Das könnte den Trick machen ... obwohl ich auf eine Lösung gehofft hatte, die keine Nicht-Perl-Dienstprogramme von Drittanbietern verwendet ... noch die Kommandozeile. :-) –

+0

Hier gibt es ein Perl-T-Stück: http://www.robvanderwoude.com/tee.php das könnte helfen, Abhängigkeiten zu reduzieren :) – msandiford

+1

Ich habe es geschrieben geschrieben "vertraue niemals einem Perl-Skript Dazu gehört 'print $ _;' " –

0

Sie wollen also STDERR verhalten sich wie STDOUT, auf dem Bildschirm und die gleiche Protokolldatei gehen? Können Sie STDERR mit

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

dup nur (ich weiß nicht ohne Weiteres, ob Sie dies den Aufruf IO::tee->new vor oder nach tun würden).

+1

Ja, das dachte ich auch. Aber egal, wo im Code diese Zeile steht, die Fehlermeldungen werden nicht in die Protokolldatei geschrieben. –

13

Ich verwende Log::Log4perl für solche Dinge. Es verarbeitet die Ausgabe an mehrere Orte für Sie, einschließlich des Bildschirms, Dateien, Datenbanken oder was auch immer Sie mögen. Sobald du ein bisschen komplex geworden bist, solltest du dieses Zeug nicht alleine machen.

Anstatt auf Dateihandles zu drucken, geben Sie Log4perl einfach eine Nachricht, und der Rest wird angezeigt. Ich habe eine kurze Einführung in Mastering Perl. Es basiert auf Log4j, und die meisten Sachen, die Sie in Log4j machen können, können Sie in Log4perl machen, was auch bedeutet, dass es, sobald Sie es wissen, eine übertragbare Fertigkeit wird.

+0

Erfordert Log4Perl nicht, dass ich auf ein Dateihandle drucke? Ich brauche alle Ausgaben umgeleitet, weil ich die meisten print-Anweisungen nicht kontrolliere, die vom Module :: Build-Prozess ausgegeben werden. –

+0

Ich habe mich Log4Perl angesehen, aber es schien nicht die Mail für mich zu beantworten, da ich auf einem Dateihandle drucken musste. –

+1

Nun, wenn es Modul :: Build ist, über das Sie sprechen, lassen Sie uns das Problem lösen. Ist deine Frage wirklich "Wie erfasse ich die Ausgabe von Module :: Build?" Das ist alles, was ich in letzter Zeit mache. Sie können eine Unterklasse erstellen und die log_ * -Methoden überschreiben, um das zu tun, was Sie wollen. –

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

Obwohl ich Log::Dispatch ausgiebig nutzen, habe ich die oben für die Anmeldung, was wurde tatsächlich auf dem Bildschirm in einer Datei angezeigt.

+0

Wow. Diese Art von Arbeit. Es sieht so aus, als hätte es sowohl STDOUT als auch STDERR sowohl auf dem Bildschirm als auch in der Protokolldatei protokolliert, aber es gibt mir immer einen "perl.exe Application Error" -Dialog, der besagt, dass eine unbekannte Software-Ausnahme aufgetreten ist. –

+0

Haben Sie nicht viel praktische Erfahrung mit Windows Perl-Kompatibilität; Ich habe es nur auf Linux verwendet. Haben Sie Strawberry perl vs activestate perl probiert? Hast du Cygwin installiert? – Oesor

+0

Ich verwende ActiveState Perl und Eclipse EPIC IDE. Kein Cygwin. –

3

einfach die STDERR Dateikennung zuweisen ...

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; 

sollte erwähnen, dass ich dies auf Windows getestet, es funktioniert, aber ich benutze StrawberryPerl.

+0

hmmmm. Dies brachte die STDERR-Zeilen nicht in meine Protokolldatei. Könnte sein, dass ich ActivePerl benutze. –

+0

wirkt wie ein Zauber, auch mit 'STDERR'. Diese Lösung sollte oben imho sein. Auch positiv: 'IO :: Tee' ist für Ubuntu gepackt, hilft sehr bei der Bereitstellung auf diesen Systemen. –

0

Ich schrieb einen minimalistischen perl logger mit konfigurierbaren dynamischen Protokollieren Sie die folgende API geben:

 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__ 
2

ich das nicht eine Windows-Box haben auf testen, aber vielleicht könnte man so etwas machen, einen vertraglich gebundenen Griff tun welches auf STDOUT und ein Protokoll drucken, dann STDOUT und STDERR dorthin umleiten?

EDIT: Die einzige Angst, die ich habe, ist die Methode der Speicherung von STDOUT für die spätere Verwendung, habe ich eine zweite Möglichkeit für die Speicherung von STDOUT für die spätere Verwendung hinzugefügt, sollte die erste nicht auf Windows arbeiten. Beide arbeiten für mich unter 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

Versuch:

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}; 

Alle print-Anweisungen, die (das heißt, keine regelmäßigen Nachrichten) keine Datei-Handle angeben wird ausgegeben an die Protokolldatei senden. Alle Druckanweisungen, die die STDERR-Dateikennung verwenden (dh alle Fehler), senden die Ausgabe sowohl an die Konsole als auch an die Protokolldatei.