You are here: Wissensbasis Web>UtilFaqInclude>FaqTkUndPOE (2007-07-13)

Apache Logs mit Tk und POE verfolgen

AlexanderBecker hat ein Programm geschrieben, mit dem Apache Logs über ein Tk-Interface überwacht werden können. Zur Erzeugung von Parallelen Prozessen wird hier POE verwendet.

#!/Perl/bin/perl

=head1 apacheLogParser_tk.pl - ein Programm zum überwachen von Dateien

=head2 VERWENDUNG

Die zu überwachenden Dateien in @logdateien eintragen, Programm starten.

=cut

use warnings;
use strict;
use Config::Auto;
use Data::Dumper qw/Dumper/;
use File::Spec;

use vars qw($VERSION);
$VERSION = 0.2;

# Tk support is enabled if the Tk module is used before POE itself.
use Tk;
use POE qw/Wheel::FollowTail/;


# Definiere globale Variablen zum Programm
# ToDo: Konfigurationsdatei verwenden, Dialog zum hinzufügen und Entfernen der
# Dateien anlegen.
my @logdateien = (
    File::Spec->catfile(qw(c: Apache logs error.log)),
    File::Spec->catfile(qw(c: Apache logs access.log)),
);

# Konfiguration für die Anzeige der Logs.
# Wenn was zurück kommt wird das in die Einagbe geschrieben,
# wenn 0 zurück kommt nicht.
my %dateieinstellungen = (
    $logdateien[0] => {
        myfunc => sub{
            my $text  = shift; # die gelesene Text-Zeile
            my $textw = shift; # Text-Widget

            $text .= "\n";

            # Timestampd und dergleichen entfernen
            $text =~ s/^\[.+\]//;

            # Zeilen aufteilen in Fehlermeldung und Fehlerquelle, und umbrechen
            $text =~ s/\, (referer\: http\:\/\/)/\n\t$1/;

            # Fehlermeldung rot markieren.
            # Den zu markierenden roten Teil auslesen, das STück davor einfügen,
            # das gefundene Stück rot einfügen, das Stück danach einfügen.
            # AP_tiny.cgi: Can't locate CMS/ADMIN/AP_tiny.pm in @INC (@INC contains: ../../pm 
            # C:/Apache/cgi-bin/cms/admin C:/Perl/site/lib C:/Perl/lib .) at 
            # C:/Apache/cgi-bin/cms/admin/AP_tiny.cgi line 9.
            if( $text =~ m/(.+:)(.+)( at.+)/ ) {
                $textw->insert('end',$1);
                $textw->insert('end',$2,'red_text');
                $textw->insert('end',$3);
                $textw->tagConfigure('red_text', -foreground => 'red');
            }else{
                # ansonsten einfach den ganzen Text einfügen
                $textw->insert('end',$text);
            }

            return 0;
        },
    },
);

# Dubletten entfernen
my %seen = ();
@logdateien = grep { ! $seen{ $_ }++ } @logdateien;
undef %seen;

foreach( @logdateien ) {
    die "Logdatei [$_] existiert nicht!\n" unless -e $_;
}


# Create the session that will drive the user interface.

POE::Session->create
  ( inline_states =>
      { _start      => \&ui_start,
        ev_count    => \&ui_count,
        ev_clear    => \&ui_clear,
        got_line    => \&updateLog_line,
        got_error   => \&updateLog_error,
      },
      args => \@logdateien,
  );

# Run the program until it is exited.

$poe_kernel->run();
exit 0;


=head2 METHODEN

=head3 ui_start

Baut die grafische Oberfläche zusammen. Pro angegebene Log-Datei gibt es einen
Notebook-Reiter.

ToDo: Wenn die Reiter breiter sind als das Fenster sollte ein Scroll-Teil
an der Seite erscheinen, oder irgend eine andere Möglichkeit geboten werden
auf diese Reiter zuzugreifen.

Reiter scheinen sowieso irgendwie ungeeigenet zu sein, einzelne Fenster wären
wohl besser.

=cut

sub ui_start {
    my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];

    # -- Fenstergröße ungefähr anpassen
    $poe_main_window->configure(-width => 1280, -height => 480,);
    $poe_main_window->packPropagate(0);

    # -- TK-GUI erstellen
    require Tk::NoteBook;
    $heap->{notebook} = $poe_main_window->NoteBook();
    foreach my $logdatei ( @logdateien ) {
        $heap->{notebookSeiten}{$logdatei}{seite} = $heap->{notebook}->add($logdatei,
             -label => $logdatei,);
        $heap->{notebookSeiten}{$logdatei}{scr_txt} = $heap->{notebookSeiten}{$logdatei}{seite}->Scrolled(
            # keine Eigenschaften wie Höhe oder Breite, weil das Textfeld skalierbar sein soll.
            Text => -scrollbars => 'se',
        )->pack(-expand => 1, -fill => 'both',);

        # -- Buttons für Funktionen erstellen
        $heap->{notebookSeiten}{$logdatei}{btn_frame} = $heap->{notebookSeiten}{$logdatei}{seite}->Frame();
        $heap->{notebookSeiten}{$logdatei}{clear_btn} = $heap->{notebookSeiten}{$logdatei}{btn_frame}->Button(
            -text => 'Anzeige leeren',
            -command => sub{
                $heap->{notebookSeiten}{$logdatei}{scr_txt}->Subwidget('scrolled')->delete("0.0", "end");
                #print "$logdatei\n";
                #print Dumper $heap->{notebookSeiten}{$logdatei}{scr_txt}->Subwidget('scrolled'); # = undef???
            },
        )->pack(-side => 'left',);
        $heap->{notebookSeiten}{$logdatei}{btn_frame}->pack(-side => 'left',);
    }
    $heap->{notebook}->pack(-expand => 1, -fill => 'both',);


    # -- Statusbar
    #   -> für den UI-Counter
    require Tk::StatusBar;
    $heap->{statusbar} = $poe_main_window->StatusBar();
    $heap->{statusbar}->addLabel(
        -relief         => 'flat',
        -text           => "Welcome to the statusbar",
    );

    $heap->{statusbar}->addLabel(
        -text           => 'Frame:',
        -width          => '10',
        -anchor         => 'center',
    );

    $heap->{statusbar}->addLabel(
        -width          => 20,
        -anchor         => 'center',
        -textvariable   => \$heap->{counter},
        -foreground     => 'blue',
    );

    $heap->{statusbar}->addLabel(
        -width          => 10,
        -anchor         => 'center',
        -text           => "Clear",
        -foreground     => 'blue',
        -command        => $session->postback("ev_clear"),
        -event          => '<Button-1>',
    );


    # -- Wheel erstellen um die Error.log zu überwachen
    foreach( @logdateien ) {
        $heap->{wheel}->{$_} = POE::Wheel::FollowTail->new(
            Filename   => $_,
            InputEvent => 'got_line',
            ErrorEvent => 'got_error',
            SeekBack   => 1024,
        );
    }

    $heap->{first} = 0;

    # Loop starten
    $kernel->yield("ev_count");
} # /ui_start



=head3 ui_count

Handle the "ev_count" event by increasing a counter and displaying
its new value.

=cut

sub ui_count {
    $_[HEAP]->{counter}++;
    $_[KERNEL]->yield("ev_count");
} # /ui_count



=head3 ui_clear

Handle the "ev_clear" event by clearing and redisplaying the counter.

=cut

sub ui_clear {
    $_[HEAP]->{counter} = 0;
} # /ui_clear



=head3 updateLog_line

Fügt die neuen Informationen aus den zu verfolgenden Dateien im entsprechenden
Reiter an. In $_[ARG0] scheint dabei das zu stehen, was bei der gerade modifizierten
Datei angehangen wurde und in $_[ARG1] die Nummer (beginnend bei 1) der
Datei in der Liste der zu verfolgenden Dateien ( siehe args - Argument bei
POE::Session->create() ).

Ideen: Flashen der Reiter wenn ein Update erfolgt ist. Automatisches Scrollen
als Option (an|aus), umdrehen der einzelnen Datei-Abschnitte (geht z.B. bei
Apache-Logdateien) um den aktuellen Eintrage immer oben zu haben.

=cut

sub updateLog_line {
    my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ];

    my $eingabe = $_[ARG0];
    #print STDERR Dumper $_[ARG0];

    my @eingaben = split m/\\r, /, $eingabe;

    foreach my $eing ( @eingaben ) {
        # Wenn ein Filter für die Datei hinterlegt wurde wird die
        # Eingabe da durch gejagt.
        if( exists $dateieinstellungen{$logdateien[($_[ARG1]-1)]} ) {
            $eing = $dateieinstellungen{$logdateien[($_[ARG1]-1)]}->{myfunc}->(
                 $eing, 
                 $heap->{notebookSeiten}{$logdateien[($_[ARG1]-1)]}{scr_txt}
            );
            next if $eing eq 0;
        }

        $heap->{notebookSeiten}{$logdateien[($_[ARG1]-1)]}{scr_txt}->insert(
           "end", 
           "normal: $eing\n"
        ) if $heap->{first}++;
    }

} # /updateLog_line



=head3 updateLog_error

Keine Ahnung was das hier macht...

=cut

sub updateLog_error {
    warn "$_[ARG0]\n";
} # /pdateLog_error




=head2 QUELLEN

Quellen: http://poe.perl.org/?POE_Cookbook

a) POE+Tk - Rezept
http://poe.perl.org/?POE_Cookbook/Tk_Interfaces

This sample program creates a very simple Tk counter.  Its interface
consists of three widgets: A rapidly increasing counter, and a
button to reset that counter.

b) POE+Wheel::FollowTail - Rezept
http://poe.perl.org/?POE_Cookbook/Watching_Logs

The following is a standalone utility that I call 'ptail'.
It's a simple 'tail -f' that follows log rotations.
Syntax is simple: ptail /path/to/filename.


=head2 VERSION

0.2
    - Provisorisch Modifikation für Apache-Log-Dateien.


=head2 STRASSENPLAN

0.2 Dateiüberwachungswerkzeug mit der möglichkeit
    Datein zur Überwachung hinzu zu fügen oder zu entfernen
    - Dokumentation komplett auf deutsch umstellen (entweder ganz oder garnicht)
    - Lizenz aussuchen (GPL? CC?)
    - Menü hinzuügen, um dort Optionen bereit zu stellen wie:
        -> Hinzufügen anderer Dateien (zum Überwachen)
        -> Entfernen zur Zeit überwachter Dateien (aus der Ansicht)
        -> Anzeige einer kleinen Hilfe
        -> Anzeige eines "Über" - Dialogs mit Versionsnummer und dergleichen.
0.3 konfigurierbares Dateiüberwachungswerkzeug
    - use Config::Auto;
    - laden der zuletzt geöffneten Dateien bei Programmstart
        -> Hinweis, wenn Dateien nicht mehr existieren (eventuell eine kleine
            Konsole einbauen? Oder doch lieber das nervige Windows-Popup?)
    - automatische Speicherung der gerade geöffneten Dateien in der Konfiguration
    - speichern der Fensterausmaße bei Programmende
    - wiedererstellen der Fensterausmaße bei Programmstart
0.4 grafischer Schnickschnack
    - Blinken (oder andere Visualisierung) der aktualisierten Reiter
    - Scrollknöpfe an der rechten oberen Seite der Reiter, wenn die Reiter
        zusammen breiter sind als das Fenster (ansonsten werden die Scrollknöpfe
        deaktiviert)

*** Für später:
- Sprachunterstützung
- spezielle auswertungen für spezielle Logfiles (z.B. grafisch aufbereitet)
    -> entsprechende Konfigurationen... vgl LogAnal, Beobachter
- andere nützliche Funktionen für Apache-Log-Dateien wie das Makro
    "Serverdienst stoppen, Error.log leeren, Serverdienst starten"

=head2 AUTOR

Alexander Becker, asb_ehb doYouKnowWhatToInsertHere? yahoo.de



=head2 SIEHE AUCH

* TK
* POE
* http://www.perl-community.de,

Ergänzungen, Kommentare

Kommentare werden am besten in folgender Form vorgenommen, damit sie im Inhaltsverzeichnis angezeigt werden (natürlich ohne das <verbatim>):
---+++ Main.??? - 14 Jul 2003 - Betreff

UtilFaqSubForm edit

Titel Apache Logs mit Tk und POE verfolgen
Autor AlexanderBecker
Bereich FaqTK
Tags Tk, POE
Topic revision: 2007-07-13, ReneeBaecker
 
Bitte die NutzungsBedingungen beachten.
Bei Vorschlägen, Anfragen oder Problemen mit dem PerlCommunityWiki bitten wir um WebBottomBarExample">Rückmeldung.