Frage

Hier ist ein Szenario. Sie haben eine große Menge von Legacy-Skripte, die alle eine gemeinsame Bibliothek. Sagte Skripte die ‚Druck‘ Anweisung für Diagnoseausgang verwenden. Es werden keine Änderungen an den Skripten erlaubt -. sie weit und breit reichen, ihre Zulassungen haben, und haben längst die fruchtbaren Täler der Aufsicht und Kontrolle links

Nun wird ein neues Bedürfnis ist da: Protokollierung muss nun in die Bibliothek aufgenommen werden. Dies muss automatisch und transparent durchgeführt werden, ohne dass der Anwender der Standard-Bibliothek benötigen, um ihre Skripte zu ändern. Gemeinsame Bibliothek Methoden können nur Anrufe Protokollierung hinzugefügt zu ihnen; das ist der einfache Teil. Der schwierige Teil besteht darin, dass Diagnoseausgang aus diesen Skripten immer angezeigt wurde mit der ‚Druck‘ Aussage. Dieser Diagnoseausgang muss gespeichert werden, aber genauso wichtig ist, verarbeitet.

Als Beispiel dieser Verarbeitung, die Bibliothek sollte nur die gedruckten Zeilen aufnehmen, die die Worte ‚Warnung‘ enthalten, ‚Fehler‘, ‚Mitteilung‘ oder ‚Aufmerksamkeit‘. Der unten Extrem Trivial und konstruiertes Beispiel-Code (tm) würde einige des Ausgangs aufzunehmen:

sub CheckPrintOutput
{
    my @output = @_; # args passed to print eventually find their way here.
    foreach my $value (@output) {
         Log->log($value) if $value =~ /warning|error|notice|attention/i;
    }
}

(Ich möchte solche Probleme vermeiden, wie ‚was tatsächlich protokolliert werden sollen‘, ‚Druck sollte für die Diagnose nicht verwendet werden‘, ‚perl saugt‘ oder ‚dieses Beispiel hat die Mängel xy und z‘ .. .Dies ist der Kürze und Klarheit stark vereinfacht.)

Das grundlegende Problem kommt auf der Erfassung und Verarbeitung von übergebenen Daten (oder jede Perl builtin, entlang dieser Argumentationslinien) zu drucken. Ist es möglich? Gibt es eine Möglichkeit, es sauber zu tun? Gibt es Logging-Module, die Haken haben, lassen Sie es tun? Oder ist es etwas, das wie die Pest vermieden werden sollte, und ich sollte immer die Erfassung und Verarbeitung der gedruckten Ausgabe verzichten?

Zusätzlich: Das muss laufen plattformübergreifende - Fenster und * nichts gleichermaßen. Der Prozess der Skripte laufen muss gleich bleiben, wie muss die Ausgabe des Skripts.

Weiterer Zusatz: Ein interessanter Vorschlag in den Kommentaren der codelogic Antwort aus:

  

Sie können die Unterklasse http://perldoc.perl.org/IO/Handle.html und erstellen Sie Ihre     eigene Datei-Handle, das die Protokollierung der Arbeit tun. - Kamil Kisiel

Dies könnte es tun, mit zwei Einschränkungen:

1) Ich würde einen Weg benötigen diese Funktionalität zu jedermann zu exportieren, die die gemeinsame Bibliothek verwendet. Es würde automatisch auf STDOUT anwenden müssen und wahrscheinlich StdErr zu.

2) der IO Dokumentation Griff :: sagt, dass Sie es nicht Unterklasse kann und meine bisherigen Versuche haben fruchtlos gewesen. Ist es etwas Besonderes, erforderlich machen sublclassing IO Arbeit Griff ::? Der Standard ‚Verwendung base‚IO :: Handle‘und überschreibt dann die neuen / print Methoden scheinen nichts zu tun.

Schluss edit: Sieht aus wie IO :: Handle ist eine Sackgasse, aber Tie :: Griff kann es tun. Vielen Dank für alle Anregungen; sie sind alle wirklich gut. Ich werde die Tie :: Handle Route einen Versuch geben. Wenn es Probleme verursacht werde ich wieder!

Nachtrag: Beachten Sie, dass mit diesem ein wenig nach der Arbeit, ich fand, dass Tie :: Handle wird funktionieren, wenn Sie tun nichts schwierig. Wenn Sie eine der Funktionen von IO verwenden :: mit Ihrem gebunden STDOUT oder STDERR Griff, es ist im Grunde ein crapshoot, um sie arbeiten zuverlässig - ich nicht einen Weg finden, könnte die Autoflushing Methode von IO bekommen :: Handle auf meinem gebunden zu arbeiten Griff. Wenn ich aktiviert Autoflushing, bevor ich den Griff gebunden würde es funktionieren. Wenn das für Sie arbeitet, kann die Tie :: Handle Route akzeptabel sein.

War es hilfreich?

Lösung

Es gibt eine Reihe von Einbauten, die Sie (siehe perlsub ). Allerdings ist print eine der Einbauten, die nicht auf diese Weise funktionieren. Die Schwierigkeiten bei der print überschrieben werden in diesem perlmonk Thread .

Allerdings Sie können

  1. Erstellen Sie ein Paket
  2. Binden Sie einen Griff
  3. Sie diesen Griff wählen.

Nun haben ein paar Leute die Rahmenbedingungen gegeben, aber es funktioniert Art wie folgt aus:

package IO::Override;
use base qw<Tie::Handle>;
use Symbol qw<geniosym>;

sub TIEHANDLE { return bless geniosym, __PACKAGE__ }

sub PRINT { 
    shift;
    # You can do pretty much anything you want here. 
    # And it's printing to what was STDOUT at the start.
    # 
    print $OLD_STDOUT join( '', 'NOTICE: ', @_ );
}

tie *PRINTOUT, 'IO::Override';
our $OLD_STDOUT = select( *PRINTOUT );

Sie können printf auf die gleiche Art und Weise außer Kraft setzen:

sub PRINTF { 
    shift;
    # You can do pretty much anything you want here. 
    # And it's printing to what was STDOUT at the start.
    # 
    my $format = shift;
    print $OLD_STDOUT join( '', 'NOTICE: ', sprintf( $format, @_ ));
}

Siehe Tie :: Griff für das, was alles, was Sie von Verhalten STDOUT außer Kraft setzen können .

Andere Tipps

Sie können Perl wählen STDOUT umzuleiten.

open my $fh, ">log.txt";
print "test1\n";
my $current_fh = select $fh;
print "test2\n";
select $current_fh;
print "test3\n";

Die Datei-Handle kann alles, sogar ein Rohr zu einem anderen Prozess sein, die Prozesse der Logdaten schreiben.

PerlIO :: tee die PerlIO :: Util Modul scheint ermöglicht es Ihnen, ‚T-Stück‘ der Ausgabe eines Datei-Handle an mehrere Ziele (zB Log-Prozessor und STDOUT).

gibt eine große Auswahl. Verwenden Sie select (), um die Dateikennung zu ändern, die Standardeinstellungen zu drucken. Oder binden STDOUT. Oder öffnen Sie es erneut. Oder wenden eine IO-Schicht zu.

Dies ist nicht die Antwort auf Ihre Frage, aber Sie sollten die Logik für den eigenen Gebrauch adoptieren können. Wenn nicht, wird vielleicht jemand anderes es nützlich finden.

Fangen malformed Header, bevor sie geschehen ...

package PsychicSTDOUT;
use strict;

my $c = 0;
my $malformed_header = 0;
open(TRUE_STDOUT, '>', '/dev/stdout');
tie *STDOUT, __PACKAGE__, (*STDOUT);

sub TIEHANDLE {
    my $class = shift;
    my $handles = [@_];
    bless $handles, $class;
    return $handles;
}

sub PRINT {
    my $class = shift;
    if (!$c++ && @_[0] !~ /^content-type/i) {
        my (undef, $file, $line) = caller;
        print STDERR "Missing content-type in $file at line $line!!\n";
        $malformed_header = 1;
    }
    return 0 if ($malformed_header);
    return print TRUE_STDOUT @_;
}
1;

Nutzung:

use PsychicSTDOUT;
print "content-type: text/html\n\n"; #try commenting out this line
print "<html>\n";
print "</html>\n";

Sie können das Skript von einem Wrapper-Skript ausgeführt, dass das ursprüngliche Skript stdout und schreibt die Ausgabe irgendwo sinnvoll einfängt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top