Hi! I just notices that I replied to one person only. Maybe there is someone on the list who can help me further. I'm still stuck with the problem :-(
The term "to run locally" matches my script. Please find the script below. (NB: The script is intended for the German Perl Community, so there were german comments and variable names only. I translated most of them, but there surely are some left.) Basically, a Tk main window is created with a menu, a notebook with tabs for each watched file and a giant textarea for each file. Using the menu, you can remove and add files. I'm using ActiveState Perl and it's Tk. If you are using another Tk, I think you have to adjust this line: use POE qw( Loop::TkActiveState Wheel::FollowTail ); I don't know exactly how, I think you can simply omit the Loop::TkActiveState. Best regards, Alex [code] #!perl =head1 NAME apacheLogParser_tk.pl - a programm to watch files =head1 DESCRIPTION Somewhere in this code, you can specify a list of files to be watched. Search for "my $logdateien". =cut use strict; use warnings; use Config::Auto; use Data::Dumper qw/Dumper/; use File::Spec; use utf8; use vars qw($VERSION); $VERSION = 0.3; # Tk support is enabled if the Tk module is used before POE itself. use Tk; use Tk::ToolBar; use Tk::StatusBar; # except when it isn't... # # ActiveState does something funky such that if you don't include # Loop::TkActiveState here Loop::Tk won't be detected. The good news # is that it does not appear to be necessary to special case this for # other platforms. # # Are you using a non-ActiveState Perl? Then you have to adjust this line! use POE qw( Loop::TkActiveState Wheel::FollowTail ); my $logdateien = [ File::Spec->catfile(qw(c: Apache logs error.log)), #File::Spec->catfile(qw(c: Apache logs access.log)), ]; # 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; sub add_file_to_watchlist { my ($heap, $logdatei) = @_; $heap->{notebookSeiten}{$logdatei}{seite} = $heap->{notebook}->add($logdatei, -label => $logdatei,); $heap->{notebookSeiten}{$logdatei}{scr_txt} = $heap->{notebookSeiten}{$logdatei}{seite}->Scrolled( Text => -scrollbars => 'se', )->pack(-expand => 1, -fill => 'both',); # -- Buttons $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"); }, )->pack(-side => 'left',); $heap->{notebookSeiten}{$logdatei}{btn_frame}->pack(-side => 'left',); # -- create Wheel $heap->{wheel}->{$logdatei} = POE::Wheel::FollowTail->new( Filename => $logdatei, InputEvent => 'got_line', ErrorEvent => 'got_error', SeekBack => 1024, ); return; } # /add_file_to_watchlist =head2 METHODEN =head3 ui_start Populate the GUI. For each file in \@logdateien, we create a new tab. =cut sub ui_start { my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ]; # -- adjust window size die "could not create a main Tk window" unless defined $poe_main_window; $poe_main_window->configure(-width => 1280, -height => 480,); $poe_main_window->packPropagate(0); $poe_main_window->gridPropagate(0); # -- create Tk GUI require Tk::NoteBook; $heap->{notebook} = $poe_main_window->NoteBook(); foreach my $logdatei ( @{$logdateien} ) { add_file_to_watchlist( $heap, $logdatei ); } $heap->{notebook}->pack(-expand => 1, -fill => 'both',); # -- Statusbar # -> for the UI-Counter $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>', ); $heap->{first} = 0; # -- Menu erstellen $poe_main_window->update(); my $log_file_types = [ ['Log Files', ['.log', '.txt']], ['All Files', '*', ], ]; my $menuitems = [ [Cascade => "~File", -menuitems => [ [Button => "~Add file", -command => sub{ my $file = $poe_main_window->getOpenFile(-filetypes => $log_file_types); if( $file ) { # Eine Datei wurde ausgewählt. Diese soll nun auch geloggt werden. push @{$logdateien}, $file; add_file_to_watchlist( $heap, $file ); print Dumper $heap->{wheel}->{$file}; } return 1; }], [Button => "~Remove file", -command => sub{ my $aktuelle_seite = $heap->{notebook}->raised(); if( $aktuelle_seite ) { $heap->{notebook}->delete($aktuelle_seite); delete $heap->{notebookSeiten}{$aktuelle_seite}; delete $heap->{wheel}->{$aktuelle_seite}; #die('doesn\'t work yet ;-('); } return 1; }], [Separator => ""], [Button => "~Beenden", -command => sub{ exit(0); return 1; }], ], ], ]; my $menu = $poe_main_window->Menu(-menuitems => $menuitems); $poe_main_window->configure(-menu => $menu); # 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 Inserts the new lines from the watched file into the textare on the related notebook tab. =cut sub updateLog_line { my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ]; my $eingabe = $_[ARG0]; my @eingaben = split m/\\r, /, $eingabe; foreach my $eing ( @eingaben ) { $heap->{notebookSeiten}{$logdateien->[($_[ARG1]-1)]}{scr_txt}->insert("end", "normal: $eing\n") if $heap->{first}++; } } # /updateLog_line =head3 updateLog_error No idea what this is about =cut sub updateLog_error { warn "$_[ARG0]\n"; } # /pdateLog_error [/code] -----Ursprüngliche Nachricht----- Von: Rocco Caputo [mailto:rcap...@pobox.com] Gesendet: Mittwoch, 13. Juni 2012 22:24 An: POE Mailing List Betreff: Re: Q: add and remove wheels dynamically Can you reduce the program to something I can run locally to see what's going on? The parts you've quoted aren't enough context for me to answer your question. What you want to do should work fine. So the best answer I have (with the information you've given) is "you're doing... something... wrong." -- Rocco Caputo <rcap...@pobox.com> On Jun 12, 2012, at 16:10, Alex wrote: > Hi! > > I have written a small Tk GUI that follows some log files. I would > like to add the possibility to add and remove files on-the-fly. > To do this, I added a menu where a user is provided with two menu > items for > this: > > [snip] > my $logfiles = [ ... ]; # my personal list of files > > my $log_file_types = [ > ['Log Files', ['.log', '.txt']], > ['All Files', '*', ], > ]; > > my $menuitems = [ > [Cascade => "~Datei", -menuitems => > [ > [Button => "~Add file", -command => sub{ > my $file = $poe_main_window->getOpenFile(-filetypes > => $log_file_types); > if( $file ) { > # A file has been selected to be followed > push @{$logfiles}, $file; > add_file_to_watchlist( $heap, $file ); > } > return 1; > }], > [Button => "~Remove file", -command => sub{ > my $ident = magic_way_to_get_this(); > delete $heap->{wheel}->{$ident}; > } > return 1; > }], > [Separator => ""], > [Button => "~Exit program", -command => sub{ exit(0); > return 1; }], > ], > ], > ]; > my $menu = $poe_main_window->Menu(-menuitems => $menuitems); > $poe_main_window->configure(-menu => $menu); > > sub add_file_to_watchlist { > my ($heap, $logfile) = @_; > > # this ethod is called during the initial set-up, too. > # some stuff here... > > # -- create new wheel > $heap->{wheel}->{$logdatei} = POE::Wheel::FollowTail->new( > Filename => $ logfile, > InputEvent => 'got_line', > ErrorEvent => 'got_error', > SeekBack => 1024, > ); > > return; > } # /add_file_to_watchlist > [/snip] > > However, when I remove a file and add it again, it's not followed. If > I add another file, it's not followed either. > How do I do this? Is it possible? > > The code (the uncut version) works fine when the program starts up. > Only adding files after the event loop has started doesn't work. Why? > > What is the proper way of saying: "hey Perl, stop following that file" > and "hey Perl, start following this file" while the POE event loop is running? > > Best regards, > Alex > ----- E-Mail ist virenfrei. Von AVG überprüft - www.avg.de Version: 2012.0.2180 / Virendatenbank: 2433/5067 - Ausgabedatum: 13.06.2012
#!perl =head1 NAME apacheLogParser_tk.pl - a programm to watch files =head1 DESCRIPTION Somewhere in this code, you can specify a list of files to be watched. Search for "my $logdateien". =cut use strict; use warnings; use Config::Auto; use Data::Dumper qw/Dumper/; use File::Spec; use utf8; use vars qw($VERSION); $VERSION = 0.3; # Tk support is enabled if the Tk module is used before POE itself. use Tk; use Tk::ToolBar; use Tk::StatusBar; # except when it isn't... # # ActiveState does something funky such that if you don't include # Loop::TkActiveState here Loop::Tk won't be detected. The good news # is that it does not appear to be necessary to special case this for # other platforms. # # Are you using a non-ActiveState Perl? Then you have to adjust this line! use POE qw( Loop::TkActiveState Wheel::FollowTail ); my $logdateien = [ File::Spec->catfile(qw(c: Apache logs error.log)), #File::Spec->catfile(qw(c: Apache logs access.log)), ]; # 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; sub add_file_to_watchlist { my ($heap, $logdatei) = @_; $heap->{notebookSeiten}{$logdatei}{seite} = $heap->{notebook}->add($logdatei, -label => $logdatei,); $heap->{notebookSeiten}{$logdatei}{scr_txt} = $heap->{notebookSeiten}{$logdatei}{seite}->Scrolled( Text => -scrollbars => 'se', )->pack(-expand => 1, -fill => 'both',); # -- Buttons $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"); }, )->pack(-side => 'left',); $heap->{notebookSeiten}{$logdatei}{btn_frame}->pack(-side => 'left',); # -- create Wheel $heap->{wheel}->{$logdatei} = POE::Wheel::FollowTail->new( Filename => $logdatei, InputEvent => 'got_line', ErrorEvent => 'got_error', SeekBack => 1024, ); return; } # /add_file_to_watchlist =head2 METHODEN =head3 ui_start Populate the GUI. For each file in \@logdateien, we create a new tab. =cut sub ui_start { my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ]; # -- adjust window size die "could not create a main Tk window" unless defined $poe_main_window; $poe_main_window->configure(-width => 1280, -height => 480,); $poe_main_window->packPropagate(0); $poe_main_window->gridPropagate(0); # -- create Tk GUI require Tk::NoteBook; $heap->{notebook} = $poe_main_window->NoteBook(); foreach my $logdatei ( @{$logdateien} ) { add_file_to_watchlist( $heap, $logdatei ); } $heap->{notebook}->pack(-expand => 1, -fill => 'both',); # -- Statusbar # -> for the UI-Counter $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>', ); $heap->{first} = 0; # -- Menu erstellen $poe_main_window->update(); my $log_file_types = [ ['Log Files', ['.log', '.txt']], ['All Files', '*', ], ]; my $menuitems = [ [Cascade => "~File", -menuitems => [ [Button => "~Add file", -command => sub{ my $file = $poe_main_window->getOpenFile(-filetypes => $log_file_types); if( $file ) { # Eine Datei wurde ausgewählt. Diese soll nun auch geloggt werden. push @{$logdateien}, $file; add_file_to_watchlist( $heap, $file ); print Dumper $heap->{wheel}->{$file}; } return 1; }], [Button => "~Remove file", -command => sub{ my $aktuelle_seite = $heap->{notebook}->raised(); if( $aktuelle_seite ) { $heap->{notebook}->delete($aktuelle_seite); delete $heap->{notebookSeiten}{$aktuelle_seite}; delete $heap->{wheel}->{$aktuelle_seite}; #die('doesn\'t work yet ;-('); } return 1; }], [Separator => ""], [Button => "~Beenden", -command => sub{ exit(0); return 1; }], ], ], ]; my $menu = $poe_main_window->Menu(-menuitems => $menuitems); $poe_main_window->configure(-menu => $menu); # 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 Inserts the new lines from the watched file into the textare on the related notebook tab. =cut sub updateLog_line { my ( $kernel, $session, $heap ) = @_[ KERNEL, SESSION, HEAP ]; my $eingabe = $_[ARG0]; my @eingaben = split m/\\r, /, $eingabe; foreach my $eing ( @eingaben ) { $heap->{notebookSeiten}{$logdateien->[($_[ARG1]-1)]}{scr_txt}->insert("end", "normal: $eing\n") if $heap->{first}++; } } # /updateLog_line =head3 updateLog_error No idea what this is about =cut sub updateLog_error { warn "$_[ARG0]\n"; } # /pdateLog_error