opi: STDERR umleiten, aber wie flock einsetzen?

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

--
Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
  1. 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

    1. 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

      --
      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
  2. 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

    1. 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

      --
      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
      1. Tag opi.

        Wie kann ich jetzt STDERR übergeben bzw. umleiten?

        Vielleicht ist CGI::Carp was für dich. Ansonsten wühle dich mal durch perlipc.

        Siechfred

        1. 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

          --
          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
          1. 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.

            1. 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

              --
              Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
              1. 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

                1. 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

                  --
                  Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                  1. 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/)
                    
                    1. 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

                      --
                      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                      1. 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.

                        1. 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

                          --
                          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                          1. Hallo,

                            print @$die;

                            die Zeile ist überflüssig. Sorry.

                            Greez,
                            opi

                            --
                            Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                          2. 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.

                            1. 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

                              --
                              Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                              1. 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.

                                1. 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

                                  --
                                  Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                                  1. 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.