STDERR umleiten, aber wie flock einsetzen?
opi
- perl
Guten Abend zusammen,
wie kann man Fehlermeldungen über STDERR optimal umleiten? Ich habe
eine Vielzahl von Perlskripts, die in dieselbe Logdatei Fehler-
meldungen schreiben sollen. Die Skripts laufen vorwiegend parallel.
Wenn ich also zu Begin jedes Skripts folgendes ausführen möchte
sysopen STDERR,"$log",O_WRONLY | O_APPEND | O_CREAT or die $!;
dann kann ich leider die Logdatei nicht Locken, da sonste jedes
Skript auf die Freigabe des anderen warten würde. Nun möchte ich
nicht, dass sich zwei Skripts beim Schreiben stören.
Kann ich die Fehlermeldung von STDERR auch an ein beliebiges
selbstgestricktes Modul weiterleiten? Mein Wunsch ist es, Datum
und Uhrzeit sowie ein paar andere Dinge an die Fehlermeldung zu
hängen, die mir wichtig sind und wiederrum für Auswertungen genutzt
werden.
Greez,
opi
Hi,
Wenn ich also zu Begin jedes Skripts folgendes ausführen möchte
sysopen STDERR,"$log",O_WRONLY | O_APPEND | O_CREAT or die $!;
dann kann ich leider die Logdatei nicht Locken, da sonste jedes
Skript auf die Freigabe des anderen warten würde. Nun möchte ich
nicht, dass sich zwei Skripts beim Schreiben stören.
für Schreiben beim Append musst Du kein Lock verwenden, da der gesamte Block eines Append geschrieben wird, bevor der nächste Append stattfinden kann. Allerdings darfst Du dann auch ausschließlich Append verwenden, und nicht zwischendurch noch andere Operationen durchführst.
LG
Chris
Hallo Chris,
Hi,
Wenn ich also zu Begin jedes Skripts folgendes ausführen möchte
sysopen STDERR,"$log",O_WRONLY | O_APPEND | O_CREAT or die $!;
dann kann ich leider die Logdatei nicht Locken, da sonste jedes
Skript auf die Freigabe des anderen warten würde. Nun möchte ich
nicht, dass sich zwei Skripts beim Schreiben stören.für Schreiben beim Append musst Du kein Lock verwenden, da der gesamte Block eines Append geschrieben wird, bevor der nächste Append stattfinden kann. Allerdings darfst Du dann auch ausschließlich Append verwenden, und nicht zwischendurch noch andere Operationen durchführst.
und genau das ist nicht möglich. Wenn die Datei eine bestimmte
Größe erreicht hat, soll sie gezippt werden. Deshalb suche ich nach
einer Möglichkeit, STDERR einem Modul zu übergeben. Ist sowas
möglich?
Greez,
opi
Hallo,
nur mal so am Rande..
Hast Du Dir schonmal Log4Perl angeschaut? Ich kennen zwar nur
Log4J (Java), muss allerdings sagen, dass der Logger absolut
überzeugt. Was den Komfort, so wie die Skalierbarkeit angeht.
Vielleicht solltest Du Dir den mal anschauen?!
Freundliche Grüße
Dieter
Hallo Dieter,
kennst du denn eine Möglichkeit, STDERR an ein Modul zu übergeben?
Beispiel des Moduls:
sub doSTDOUT {
my $msg = shift;
my $tm = [ localtime(time) ];
$tm->[5] += 1900;
$tm->[4]++;
foreach (@$tm) { $_ = "0$_" if $_ < 10; }
sysopen LOGFILE, "./logfile", O_WRONLY | O_APPEND | O_CREAT or die $!;
flock(LOGFILE, LOCK_SH);
print LOGFILE "$tm->[5]-$tm->[4]-$tm->[3] $tm->[2]:$tm->[1]:$tm->[0] $msg\n";
close LOGFILE;
}
Wie kann ich jetzt STDERR übergeben bzw. umleiten?
Greez,
opi
Hallo Siechfred,
Vielleicht ist CGI::Carp was für dich. Ansonsten wühle dich mal durch perlipc.
also fatalsToBrowser nutze ich standardmäßig in all meinen Skripts.
Nur leider werden keine "warnings" abgefangen. Die landen dann in
der Logdatei des Webservers, in meinem Fall Apache.
Ich schau mir das Modul nochmal an. Danke.
Greez,
opi
Vielleicht ist CGI::Carp was für dich. Ansonsten wühle dich mal durch perlipc.
also fatalsToBrowser nutze ich standardmäßig in all meinen Skripts.
Nur leider werden keine "warnings" abgefangen. Die landen dann in
der Logdatei des Webservers, in meinem Fall Apache.
Du kannst die Warnungen auch selber abfangen, ich hatte ja schon von meinem Debug Modul erzählt dort wende ich dies an:
$SIG{__WARN__} = sub warn_{ push @warn, @_;}
Das Array wird dann am Ende ausgegeben.
Struppi.
Hallo Struppi,
Du kannst die Warnungen auch selber abfangen
wie? Genau danach suche ich. Zum Beispiel fängt Carp fatalsToBrowser
die-Meldungen ab. Ich habe mal in das Modul reingesehen, aber leider
nicht verstanden wie es funktioniert. Ich versuche schon so gut wie
es nur geht alle möglichen Fehler, die auftreten könnten, abzufangen.
fatalsToBrowser dient dann für den Rest. Aber wie grundlegend die
und warn Meldungen abfangen kann, weiß ich leider nicht.
ich hatte ja schon von meinem Debug Modul erzählt dort wende ich dies an:
$SIG{__WARN__} = sub warn_{ push @warn, @_;}
Die Zeile sagt mir genauso wenig :-) mennoh!
Greez,
opi
Tag opi.
$SIG{__WARN__} = sub warn_{ push @warn, @_;}
Die Zeile sagt mir genauso wenig :-) mennoh!
Nana, wer wird denn verzweifeln, den Link zu perlipc hatte ich dir schon gepostet. Darüber hinaus findest du eine recht ausführliche Beschreibung unter http://dev.perl.org/perl6/rfc/236.html.
Siechfred
Hallo Siechfred,
Nana, wer wird denn verzweifeln, den Link zu perlipc hatte ich dir schon gepostet. Darüber hinaus findest du eine recht ausführliche Beschreibung unter http://dev.perl.org/perl6/rfc/236.html.
ich habe mich durch die Doku gelesen.
use strict;
use warnings;
my $warn = [];
my $die = [];
$SIG{__WARN__} = sub { push @$warn, @_; };
$SIG{__DIE__} = sub { push @$die, @_; };
warn "WARNUNG\n";
die "STERBEN\n";
print @$warn;
print @$die;
print "WENN DIESE ZEILE AUSGEGEBEN WIRD, HAT ALLES FUNKTIONIERT\n";
Leider funktioniert das nicht wie gewünscht. Das Skript endet bei
der Ausgabe von "STERBEN".
Wenn ich allerdings die Zeile
die "STERBEN\n";
auskommentiere, dann klappt es. Was mache ich hier noch falsch?
Greez,
opi
ich habe mich durch die Doku gelesen.
use strict;
use warnings;my $warn = [];
my $die = [];$SIG{WARN} = sub { push @$warn, @; };
$SIG{DIE} = sub { push @$die, @; };warn "WARNUNG\n";
die "STERBEN\n";print @$warn;
print @$die;print "WENN DIESE ZEILE AUSGEGEBEN WIRD, HAT ALLES FUNKTIONIERT\n";
>
> Leider funktioniert das nicht wie gewünscht. Das Skript endet bei
> der Ausgabe von "STERBEN".
>
Naja, du musst die Arrays aus ausgeben, bzw. dein Ansatz "stirbt" andauernd in einer Endlosschleife die Perl unterbricht.
Du musst bei die irgendetwas ausgeben, da danach das Programm zuende ist.
Struppi.
--
[Javascript ist toll](http://javascript.jstruebig.de/)
Hallo Struppi,
erfolgt die Ausgabe nicht mit
print @$warn;
print @$die;
»»
? Dann habe ich es noch immer nicht verstanden. Ich lese mir nochmal
die Doku durch.
Greez,
opi
erfolgt die Ausgabe nicht mit
print @$warn;
print @$die;
»»? Dann habe ich es noch immer nicht verstanden. Ich lese mir nochmal
die Doku durch.
Nein. Denn dein Programm stirbt ja und bleibt dort. Der Mechanismus von die ist dir nicht klar.
Struppi.
Hallo Struppi,
Nein. Denn dein Programm stirbt ja und bleibt dort. Der Mechanismus von die ist dir nicht klar.
Doch. Vielleicht war da bei mir ein Gedankenfehler. Mit "die" stirbt
der Prozess und führt nachfolgenden Code nicht mehr aus.
Wenn ein "warn" oder ein "die" ausgelöst wird, dann wird die
Subfunktion ausgeführt, die hinter dem Signalhändler angegeben ist.
use strict;
use warnings;
my $warn = [];
my $die = [];
$SIG{__WARN__} = sub { push @$warn, @_; };
$SIG{__DIE__} = sub { print "DIE AUSGABE VON \"DIE\" ist -> ", @_; };
warn "WARNUNG\n";
print @$warn;
print @$die;
die "STERBEN\n";
print "DIE LETZTE PRINT ANWEISUNG WIRD NATUERLICH NICHT AUSGEGEBEN\n";
Aber warum erhalte ich nun die Ausgabe:
WARNUNG
DIE AUSGABE VON "DIE" ist -> STERBEN
STERBEN
"STERBEN" wird zwei mal ausgegeben. Warum das?
Greez,
opi
Hallo,
print @$die;
die Zeile ist überflüssig. Sorry.
Greez,
opi
Nein. Denn dein Programm stirbt ja und bleibt dort. Der Mechanismus von die ist dir nicht klar.
Doch. Vielleicht war da bei mir ein Gedankenfehler. Mit "die" stirbt
der Prozess und führt nachfolgenden Code nicht mehr aus.
jop.
Wenn ein "warn" oder ein "die" ausgelöst wird, dann wird die
Subfunktion ausgeführt, die hinter dem Signalhändler angegeben ist.
jop.
Aber warum erhalte ich nun die Ausgabe:
WARNUNG
DIE AUSGABE VON "DIE" ist -> STERBEN
STERBEN"STERBEN" wird zwei mal ausgegeben. Warum das?
Einmal fängst du die ab und dann stribt das Programm. Mit exit erhälst du die 2 Meldung nicht mehr.
$SIG{__DIE__} = sub { print "DIE AUSGABE VON "DIE" ist -> @_" ; exit;};
Struppi.
Hallo Struppi,
Einmal fängst du die ab und dann stribt das Programm. Mit exit erhälst du die 2 Meldung nicht mehr.
$SIG{__DIE__} = sub { print "DIE AUSGABE VON "DIE" ist -> @_" ; exit;};
jetzt habe ich es verstanden. Hat lange gedauert! Kommt vielleicht
daher, weil ich schon viereckige Augen habe :-)
Ich gebe mit
print "DIE AUSGABE VON "DIE" ist -> @_"
einmal "STERBEN" aus und danach gibt der Signalhändler das gleiche
nochmal aus...
Magst du dein Modul mal zuschicken? Oder unterliegt es einem strengen
Copyright? :-)
Greez,
opi
Magst du dein Modul mal zuschicken? Oder unterliegt es einem strengen
Copyright? :-)
Nö, es ist eigentlich auch ganze simpel
package debug;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(DEBUG);
$VERSION = 1;
use strict;
use Data::Dumper;
use CGI;
#################################################
# Globals #
#################################################
my $DEBUG = 0;
my @debug_msg = ();
my @warn = ();
my $died = 0;
sub start_debug
{
$DEBUG = shift;
$SIG{__WARN__} = \&warn_handler;
$SIG{__DIE__} = \&die_handler;
}
#======================================================================
# DEBUG
#
# Aufruf im Programm:
#
# DEBUG DEBUG_LEVEL, "text:", Variabel;
#
# Loggen von Werten
#======================================================================
sub DEBUG
{
my($level, $msg, $var) = @_;
return '' unless $DEBUG;
return '' if defined $level && $level > $DEBUG;
# Ausgabe
return CGI::Dump() . "<hr>Warnungen:<br><pre>@warn</pre><hr>DEBUG $DEBUG:<br><pre>@debug_msg</pre>"
if !defined $level;
# Speichern
$Data::Dumper::Indent = 2;
my @c = caller;
push @debug_msg, "<b>$msg</b>-<br>$c[1]:$c[2]". (defined $var ? "\n".Dumper($var) : '') ."\n";
}
sub warn_handler
{
push @warn, @_;
}
sub die_handler
{
return if $died++;
print "Content-Type: text/html\n\n<html><body>",
"<h1>GESTORBEN</H1>",
"<pre>Grund: @_</pre><br>",
"Fehler: *$!* <br>",
"<br>Caller:<br>"
;
foreach(caller)
{
print "$_<br>";
}
print "$@",
DEBUG(),
"ENDE.<hr></body></html>"
;
}
1;
Im Orginal ist noch eine einfache Mail Routine im die Handler.
angewendet wird es einfach durch
BEGIN
{
use debug;
debug::start_debug( ... Level .. );
}
und dann überall wo du Variabeln überwachen willst:
DEBUG 1, "text", $var;
die Ausgabe
print DEBUG();
DEBUG
Struppi.
Hallo Struppi,
sub die_handler
{
return if $died++;print "Content-Type: text/html\n\n<html><body>",
"<h1>GESTORBEN</H1>",
"<pre>Grund: @_</pre><br>",
"Fehler: *$!* <br>",
"<br>Caller:<br>"
;
foreach(caller)
{
print "$_<br>";
}
print "$@",
DEBUG(),
"ENDE.<hr></body></html>"
;}
diese Funktion macht doch eigentlich das Gleiche wie fatalsToBrowser,
nur etwas eleganter oder? Selbstgestricktes ist doch manchmal um
einiges besser ... ;-)
Ich hab es mir mal kopiert ... danke !!
Greez,
opi
sub die_handler
{
return if $died++;print "Content-Type: text/html\n\n<html><body>",
"<h1>GESTORBEN</H1>",
"<pre>Grund: @_</pre><br>",
"Fehler: *$!* <br>",
"<br>Caller:<br>"
;
foreach(caller)
{
print "$_<br>";
}
print "$@",
DEBUG(),
"ENDE.<hr></body></html>"
;}
diese Funktion macht doch eigentlich das Gleiche wie fatalsToBrowser,
nur etwas eleganter oder? Selbstgestricktes ist doch manchmal um
einiges besser ... ;-)
Eleganter weiß ich nicht, aber im Prinzip dürfte es auf das Gleiche hinauslaufen. Ich lasse mir halt noch einige Variabeln mitausgeben, die aber nicht immer nötig oder evtl. sogar gefährlich sein können wenn sie jeder sieht. wobei man das aber auch umgehen könnte.
Aber ich hab mir das zusammengeschustert weil fatalsToBrowser mir nicht die Informationen gibt die ich gebraucht habe.
Struppi.