I don't think that File::Tail will cope with a Tk MainLoop, and Tk's way of doing everything through callbacks. But, I would be interested if anyone has made File::Tail work with Tk.
I have home-grown something similar, albeit on a Unix platform. Here is an excerpt from my process monitoring application (which has the ability to open up windows with log file tails in them). Note the "freeze frame" button - a useful feature on a log tailing window. I also limit the number of lines to display in the window to be $logMax.
#######################################################
# log_window('/apps/foobar/var/logs/MainLogFile.20030921','Main Log Fi
+le');
#
# Create window for viewing/tailing log file
# Recognise file as compressed if it ends in .Z
sub log_window {
my ($file,$title) = @_;
my $compressed = $file =~ /.Z$/;
my $freeze = 0;
# Create new window
my $newwin = $mainw->Toplevel( -title => $title );
# Frame for buttons
my $buttbox = $newwin->Frame->pack( -side => 'top');
# Read only textbox for log file text
my $txt = $newwin->Scrolled('ROText',
-scrollbars => 'oe',
-height => 20,
-setgrid => 'true',
) ->pack( -expand => 1,
-fill => 'both');
# Set up closure to handle tailing
my $logger = make_logger($file, $txt, \$freeze); # closure
# Buttons...
$buttbox->Button( -text => 'Close',
-command => [$newwin, 'destroy'])
->pack( -side => 'left');
$buttbox->Button( -text => 'Top',
-command => [$txt, 'see', '0.0'])
->pack( -side => 'right');
$buttbox->Button( -text => 'Bottom',
-command => [$txt, 'see', 'end'])
->pack( -side => 'right');
if ($compressed) {
# Log is compressed, so expand it. No need for tail as it's not growin
+g
$txt->insert('end' => `zcat $file`);
$txt->see('end');
} else {
# Log is not compressed. add checkbox for freeze frame and set up tail
+ing
$buttbox->Checkbutton( -text => 'Freeze frame',
-variable => \$freeze,
-indicatoron => 0,
-selectcolor => 'white',
) ->pack( -side => 'left', -ipady => 4);
$newwin->repeat( $myconf->param('logfile_poll'), $logger);
&$logger;
}
}
##########################################
# make_logger('/apps/foobar/var/logs/MainLogFile.20030921',$txt,\$free
+ze)
#
# closure factory for loggers. Generates private copy of $size to keep
+ track of end of file.
sub make_logger {
my ($log,$box,$reffrz) = @_;
my $size = 0;
sub { log_to_window($log,$box,$reffrz,\$size); }
}
##########################################
# log_to_window('/app/foobar/var/logs/MainLogFile.20030921',$txt,\$fre
+eze,\$size)
#
# This is the code which is called back (as a closure) on a timer to t
+ail log files.
# It is also called to initially populate the window.
sub log_to_window {
my ($log,$box,$reffrz,$refsize) = @_;
print "log_to_window called: $log\n" if $debug;
return if $$reffrz; # Freeze frame: do nothing
return if $$refsize == (-s $log); # Log size has not changed: d
+o nothing
my $logMax = $myconf->param('logfile_max_lines');
open LOG,$log or return; # Wot no log file?
seek LOG,$$refsize,0 if $$refsize; # Position at last EOF
my @logtext;
while (<LOG>) { # slurp from log file
push @logtext,$_;
shift @logtext if @logtext >= $logMax; #Drop lines after li
+ne count reaches logMax
}
$box->insert(end => join('',@logtext));
$box->delete('1.0', "end - $logMax lines");
$box->see('end'); # Position window to end as new text
+has appeared
$$refsize = tell LOG;
close LOG;
}