Question

Voici un scénario. Vous avez une grande quantité de scripts existants, en utilisant toutes une bibliothèque commune. scripts utilisent l'instruction dit « d'impression » pour la sortie de diagnostic. Aucun changement ne sont autorisés aux scripts -. Ils vont loin, leurs approbations, et ont depuis longtemps quitté les vallées fécondes de surveillance et de contrôle

Maintenant, un nouveau besoin est arrivé: l'exploitation forestière doit maintenant être ajoutée à la bibliothèque. Cela doit se faire automatiquement et de façon transparente, sans que les utilisateurs de la bibliothèque standard qui ont besoin de changer leurs scripts. méthodes de bibliothèque commune peuvent tout simplement avoir des appels de journalisation ajoutés à eux; c'est la partie facile. La partie la plus difficile réside dans le fait que la sortie de diagnostic de ces scripts ont été toujours affiché en utilisant l'instruction « d'impression ». Cette sortie de diagnostic doit être stocké, mais tout aussi important, traité.

A titre d'exemple de ce traitement, la bibliothèque devrait enregistrer uniquement les lignes imprimées qui contiennent les mots de l'avertissement », « erreur », « avis » ou « attention ». Le dessous extrêmement Trivial et Contrived Exemple de code (tm) enregistrerait une partie de ladite sortie:

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

(je voudrais éviter des questions telles que « ce qui devrait effectivement être connecté », « impression ne doit pas être utilisé pour le diagnostic », « perl sucks » ou « cet exemple a les défauts xy et z » .. .Cet est grandement simplifiée par souci de concision et de clarté.)

Le problème fondamental se résume à la saisie et le traitement des données transmises à imprimer (ou tout builtin Perl, le long de ces lignes de raisonnement). C'est possible? Est-il possible de le faire proprement? Y a-t-il des modules d'exploitation forestière qui ont des crochets pour vous permettre de le faire? Ou est-ce quelque chose qui devrait être évité comme la peste, et je renoncer à jamais la capture et le traitement de la sortie imprimée?

supplémentaire: Cela doit exécuter multiplateforme - Windows et * nix semblables. Le processus d'exécution des scripts doit rester la même, de même que la sortie du script.

supplémentaire supplémentaire: Une suggestion intéressante faite dans les commentaires de la réponse de codelogic:

  

Vous pouvez sous-classe http://perldoc.perl.org/IO/Handle.html et créez votre     propre descripteur de fichier qui fera le travail de l'exploitation forestière. - Kamil Kisiel

Cela peut le faire, avec deux mises en garde:

1) Je besoin d'un moyen d'exporter cette fonctionnalité à toute personne qui utilise la bibliothèque commune. Il devrait appliquer automatiquement STDOUT et probablement Stderr aussi.

2) IO :: Handle la documentation dit que vous ne pouvez pas sous-classer et mes tentatives ont été jusqu'ici infructueuses. Y at-il quelque chose de spécial nécessaire pour faire sublclassing IO :: Handle travail? La « base d'utilisation « standard IO :: Handle » et les nouvelles méthodes remplaçant / d'impression semblent ne rien faire.

modifier final: On dirait que IO :: Handle est une impasse, mais Tie :: poignée peut le faire. Merci pour toutes les suggestions; ils sont tous vraiment bon. Je vais donner le Tie :: route poignée d'essayer. Si cela cause des problèmes que je serai de retour!

Addendum: Notez que, après avoir travaillé avec cela un peu, je trouve que Tie :: poignée fonctionnera, si vous ne faites rien délicat. Si vous utilisez l'une des caractéristiques de IO :: Handle avec votre attaché STDOUT ou STDERR, il est essentiellement un coup de dés pour les faire travailler de manière fiable - je ne pouvais pas trouver un moyen d'obtenir la méthode autoflush de IO :: Handle pour travailler sur mon attaché manipuler. Si je autoflush permis avant la poignée attaché, il travaillerait. Si cela fonctionne pour vous, la route Tie :: poignée peut être acceptable.

Était-ce utile?

La solution

Il y a un certain nombre de Encastrements que vous pouvez remplacer (voir perlsub ). Cependant, print est l'un des Encastrements qui ne fonctionne pas de cette façon. Les difficultés de passer outre print sont détaillées à ce fil de perlmonk .

Cependant, vous peut

  1. Créer un package
  2. Attachez une poignée
  3. Sélectionnez cette poignée.

Maintenant, deux personnes ont donné le cadre de base, mais il fonctionne un peu comme ceci:

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

Vous pouvez remplacer printf de la même manière:

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

Voir Tie :: Poignée pour ce que tout ce que vous pouvez remplacer le comportement de STDOUT .

Autres conseils

Vous pouvez utiliser sélectionnez pour rediriger STDOUT.

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

Le descripteur de fichier pourrait être quelque chose, même un tuyau à un autre processus qui Processus après vos messages journaux.

PerlIO :: tee PerlIO :: Util le module semble vous permet de 'tee' la sortie d'un descripteur de fichier vers des destinations multiples (par exemple des processeurs de journal et stdout).

Beaucoup de choix. Utilisez select () pour modifier le descripteur de fichier qui imprime par défaut. Ou attacher STDOUT. Ou rouvrir. Ou appliquer une couche IO lui.

Ce n'est pas la réponse à votre question, mais vous devriez être en mesure d'adopter la logique pour votre propre usage. Sinon, peut-être quelqu'un d'autre trouvera utile.

Attraper les en-têtes difformes avant qu'ils ne surviennent ...

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;

utilisation:

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

Vous pouvez exécuter le script à partir d'un script d'emballage qui capture le stdout du script original et écrit la sortie quelque part sensible.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top