Domanda

Ecco uno scenario. Si dispone di una grande quantità di script legacy, il tutto utilizzando una libreria comune. Tali script utilizzano l'affermazione 'print' per l'uscita di diagnosi. Non sono consentite modifiche agli script -. Si va lungo e in largo, hanno le loro approvazioni, e hanno da tempo lasciato le valli fertili di supervisione e di controllo

Ora una nuova esigenza è arrivato: la registrazione deve ora essere aggiunto alla libreria. Questo deve essere fatto automatico e trasparente, senza che gli utenti della libreria standard che hanno bisogno di cambiare i loro script. metodi Common Library possono semplicemente avere chiamate di registrazione aggiunti a loro; questa è la parte facile. La parte più difficile sta nel fatto che l'uscita di diagnosi da questi script sono stati sempre visualizzato utilizzando l'istruzione 'di stampa'. Questa uscita di diagnosi deve essere immagazzinato, ma altrettanto importante, elaborato.

Come esempio di questa elaborazione, la biblioteca dovrebbe registrare solo le righe stampate che contengono le parole 'warning', 'l'errore', 'comunicazione', o 'attenzione'. Il sotto estremamente banale e Escogitato Esempio di codice (tm) registrerebbe alcune di dette uscita:

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

(vorrei evitare tali questioni come 'ciò che dovrebbe in realtà essere registrato', 'di stampa non deve essere utilizzato per la diagnosi', 'perl fa schifo', o 'questo esempio ha i difetti xy e z' .. .questo è notevolmente semplificato per brevità e chiarezza.)

Il problema di fondo si riduce a catturare ed elaborazione dei dati passati a stampare (o qualsiasi interno a Perl, lungo quelle linee di ragionamento). È possibile? Esiste un modo per farlo in modo pulito? Ci sono dei moduli di registrazione che hanno ganci per lasciare lo fai? O è qualcosa che dovrebbe essere evitato come la peste, e dovrei rinunciare a mai catturare ed elaborare le stampe?

Ulteriori: Questo deve eseguire cross-platform - Windows e * nix simili. Il processo di esecuzione degli script deve rimanere lo stesso, così come l'uscita dallo script.

Ulteriori supplementare: Una proposta interessante fatta nei commenti di risposta di codelogic:

  

È possibile creare una sottoclasse http://perldoc.perl.org/IO/Handle.html e creare il tuo     proprio handle di file, che farà il lavoro di registrazione. - Kamil Kisiel

Questo potrebbe farlo, con due accorgimenti:

1) avrei bisogno di un modo per esportare questa funzionalità a chi utilizza la libreria comune. Avrebbe dovuto applicare automaticamente a STDOUT e STDERR probabilmente troppo.

2) IO :: Handle documentazione dice che non si può sottoclasse esso , ed i miei tentativi finora sono stati infruttuosi. C'è qualcosa di speciale necessaria per rendere sublclassing IO :: Handle lavoro? Lo standard 'base' uso 'IO :: Handle' e quindi sovrascrivendo i nuovi metodi / stampa sembra di non fare nulla.

modifica finale: Sembra che IO :: Handle è un vicolo cieco, ma Tie :: Handle può farlo. Grazie per tutti i suggerimenti; sono tutti veramente bene. Ho intenzione di dare il Tie :: Handle percorso una prova. Se causa problemi Torno!

Addendum: Si noti che dopo aver lavorato con questo un po ', ho trovato che Tie :: Handle funzionerà, se non fai niente difficile. Se si utilizza una qualsiasi delle caratteristiche di IO :: Handle con lo STDOUT legato o STDERR, è fondamentalmente un crapshoot per farli funzionare in modo affidabile - non riuscivo a trovare un modo per ottenere il metodo autoflush di IO :: Handle a lavorare sul mio legato maniglia. Se ho attivato autoflush prima ho legato la maniglia che avrebbe funzionato. Se funziona per voi, il percorso Tie :: Handle può essere accettabile.

È stato utile?

Soluzione

Ci sono una serie di built-in che è possibile ignorare (vedi perlsub ). Tuttavia, print è uno dei built-in che non funziona in questo modo. Le difficoltà di rilevante print sono dettagliate a questo di perlmonk filo .

Tuttavia, è possono

  1. Creare un pacchetto
  2. Legare una maniglia
  3. Seleziona questa maniglia.

Ora, un paio di persone hanno dato il quadro di base, ma funziona fuori un po 'come questo:

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

È possibile ignorare printf nello stesso modo:

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, @_ ));
}

Tie :: Handle per quello che tutto è possibile ignorare del comportamento di STDOUT .

Altri suggerimenti

È possibile utilizzare Perl selezionare per reindirizzare STDOUT.

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

L'handle di file potrebbe essere qualsiasi cosa, anche un tubo a un altro processo che inviare i processi i messaggi di log.

PerlIO :: tee PerlIO :: Util modulo sembra ti permette di 'T' la uscita di un handle di file a destinazioni multiple (ad esempio processori di registro e STDOUT).

Un sacco di scelte. Utilizzare select () per cambiare il filehandle che stampare default. O legare STDOUT. O riaprirlo. O applicare uno strato di IO ad esso.

Questa non è la risposta al vostro problema, ma si dovrebbe essere in grado di adottare la logica per uso personale. Se non, forse qualcun altro lo troverà utile.

Facendo header malformati prima che accadano ...

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;

utilizzo:

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

È possibile eseguire lo script da uno script wrapper che cattura stdout dello script originale e scrive l'output da qualche parte sensibile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top