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:[email protected]]
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 <[email protected]>
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