http://qs321.pair.com?node_id=297848

msemtd has asked for the wisdom of the Perl Monks concerning the following question:

I want to capture and filter data being appended to files and display it in a Tk widget simillar to "tail --follow". And I want to work on Win32 (ouch! :) (ASPerl 5.6)

Replies are listed 'Best First'.
POE, was Re: Tk tail -f - How?
by RMGir (Prior) on Oct 09, 2003 at 10:47 UTC
    Take a look at POE, specifically POE::Wheel::FollowTail and POE's Tk integration.

    There's an example for POE::Wheel::FollowTail in the POE Cookbook, as well as a POE::Tk example.

    You mentioned filtering, though. If you're going to have a lot of lines that you need to drop, you might want to use POE::Wheel::Run instead of FollowTail, and filter the lines in a helper process, using one of the tail -f techniques in the other replies. POE fires an event for every line of input, so if you're going to discard a lot of lines, it's cheaper to do it outside of the POE framework.
    --
    Mike

    (Edit: I forgot to mention, you may want to try typing

    perldoc -q "tail -f"
    The technique described there should work on Win32 as well as anywhere else, but you'd also have to add a watch to simulate the --follow behaviour if the file is rotated.)
      Thanks all,
      I put the following together using the tips from perldoc -q "tail -f". As a POE user I was under the impression that the Tk tail would fail on Win32 due to the lack of fileevent - I haven't used it recently so it may be fixed.

      This first version hangs onto the filehandle as you say so it needs some thought to emulate --follow=name.

      #! perl use strict; use warnings; use Tk; # my $file = "C:\\openejb-0.8.3\\openejb.log"; # my $title = "Tk Tail"; my $version = "1.0"; my $mw = new MainWindow( -title => $title ); # Nicer fixed-width font... $mw->fontCreate( 'listboxfont', -family => 'courier', -size => '8' ); my $fr = $mw->Frame()->pack( -expand => 1, -fill => 'both' ); # $fr->Label( -text => "File to tail" )->pack; $fr->Entry( -textvariable => \$file, -width => '50', -font => 'listboxfont', )->pack; $fr->Button( -text => 'GO', -command => \&gopush )->pack; my $listbox = $mw->Scrolled( 'Listbox', -setgrid => '1', -height => '10', -width => '50', -font => 'listboxfont', -selectmode => 'extended', -scrollbars => 'se', -bg => 'black', -fg => 'green', ); $listbox->pack( -expand => 'yes', -fill => 'both', -pady => '3' ); my $fr_statusbar = $mw->Frame( -relief => 'sunken', -borderwidth => '1', )->pack( -fill => 'x' ); #~ $fr_statusbar->Label( -image => $smallicon )->pack(-side => 'left') +; $fr_statusbar->Label( -text => "Version: $version" )->pack( -side => ' +left' ); # sub gopush { close F; open F, '<', $file or die $!; timerstart(); } # repeating actions... my $timerid; sub timerstart { &timerstop(); $timerid = $mw->repeat( 1000, \&timerproc ); } sub timerstop { if ($timerid) { $timerid->cancel; } } sub timerproc { while (<F>) { chomp; my $text = $_; $listbox->insert( 'end', $text ); $listbox->see('end'); $mw->update(); } seek( F, 0, 1 ); } MainLoop();

        You might want to add a check for the number of lines you have in the listbox and limit it to some reasonable size.

        If your file grows quickly, you could rapidly find yourself running out of memory, and (if my limited experience of Tk is still valid) things start to slow down when widgets grow beyond a certain size.

        It would be more efficient to load the listbox using

        $listbox->insert( 'end', <F> ); $listbox->see( 'end' ); $mw->update();

        Also, you probably shouldn't be seeking to the end after you have read. If nothing has been added, it will make no difference as you will already be there. However, if something was added between the last read and the seek, you will never read it and lines (or partial lines) will be lost..


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail

        As a POE user I was under the impression that the Tk tail would fail on Win32 due to the lack of fileevent - I haven't used it recently so it may be fixed.

        It is fixed in the latest release, version 0.27. POE works around ActivePerl's Tk fileevent problems by polling internally. All the usual I/O methods (select_{read,write}, the Wheel classes, and Components) should magically start working after an upgrade.

        -- Rocco Caputo - rcaputo@pobox.com - poe.perl.org

Re: Tk tail -f - How?
by BrowserUk (Patriarch) on Oct 09, 2003 at 09:58 UTC

    This one-liner will (roughtly) tail --follow a file on Win32. It always starts at the beginning, so its more of a head --follow, but that could be worked around fairly easily.

    perl -e"open F, '<', $ARGV[0] or die $!; while( 1 ){ print <F>; Win32: +:Sleep 1 }" log

    Currently it just outputs to the console, but you can do the Tk; bit...it might get a bit more than one line then:)

    Obviously, as is you have to ^C to stop it, but with the Tk; event model, you can probably control that easily.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail

      Hey, I left this running all day, but for a file that is on a networked drive:
      perl -e"open F, $ARGV[0] or die $!; while( 1 ){ print <F>; Win32::Slee +p 1 }" f:\dev1\Logfile\Background1_08-Oct-2003-12-07-35.log
      During the day the network fouled and the drives needed to be reconnected, but the program never stopped. It just hung.

      So my question is, in this case, how would you know if the filehandle was still open and connected to the file?

      Celebrate Intellectual Diversity

        Oh! Sooo, you want your one-liner to have error recovery too:)

        I had a devil of a job trying to simulate this without a network. Eventually, I tailed (slowly) a file on a my CD drive and the opened the tray.

        Originally I had thought that using seek F, 0, 1 or die... to try and 'move' the file pointer without moving it would work but the OS noticed that the CD wasn't there and popped up a nice freindly dialogue suggesting I put it back! It might work on a network drive, it might not.

        What I came up with was using -e to check that the file is still there, which seems to work fine with my CD drive. The error is reported by perl even before the CD has stopped spinning. You'll have to tell me if this works when a networked drive becomes disconnected.

        perl -e"open F, '<', $ARGV[0] or die $!; while(1){ print <F>; -e $ARGV +[0] or die 'The file went away'; Win32::Sleep 100 }" file

        It's got a bit long for a one-liner now, but it could probably be golfed :) I keep thinking it might be possible to use <code>perl -pe"..." and defeat the eof detection, but I haven't figured out how yet.

        Any takers?


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail

Re: Tk tail -f - How?
by broquaint (Abbot) on Oct 09, 2003 at 08:40 UTC
    Sounds like File::Tail is the ticket, and I quote from the docs
    File::Tail - Perl extension for reading from continously updated files
    HTH

    _________
    broquaint

      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.

      --
      I'm Not Just Another Perl Hacker
      Hmm, thanks but I've tried that - the ActiveState package has no Win32 version and the CPAN tarball has 100% failure upon make test (the former because of the latter no doubt). The crux _is_ "Win32 operation required" :)
Re: Tk tail -f - How?
by thunders (Priest) on Oct 09, 2003 at 15:20 UTC
A reply falls below the community's threshold of quality. You may see it by logging in.