http://qs1969.pair.com?node_id=75420

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

So I have a log file, I know how to open it and make perl do a "tail" on said log file so that I can see the file getting updated as it gets updated. But what if I wanted to write a cgi script or mod_perl handler/script todo this, how would I go about "streaming" the data to a browser? Is it all a header trick? or is there more to it then that?


lindex
/****************************/ jason@gost.net, wh@ckz.org http://jason.gost.net /*****************************/

Edited 2001-04-05 by Ovid

Replies are listed 'Best First'.
Re: A Simple
by mrmick (Curate) on Apr 25, 2001 at 16:34 UTC
    You're on the right track....

    All you really have to do is ensure that the output is going to STDOUT and use CGI.pm to create your header/content type/html stuff. You may want to 'unbuffer' your output with $|=1; as well.

    Mick
Re: A Simple
by c-era (Curate) on Apr 25, 2001 at 16:37 UTC
    You can always use File::Tail. The only problem is figuring out how you want to signal your script to end (as it blocks until a new line is added to the file).
      Ah but thats the thing, I dont want the output from the script to end until the client request ends. i.e. a real tail, not just a snapshot.


      lindex
      /****************************/ jason@gost.net, wh@ckz.org http://jason.gost.net /*****************************/
        As far as server push things go, remember that IE doesnt really like pushing things. See (Re: Generating a 'please wait' message and push_handler and status page question.) You may be able to do something with Javascript? What about a frame that reloads every second or some-such-what-not? Every time it reloaded, it would get the latest tail info.

        I know, in theory you could flush the output ($| = 1; (see your replies above)) and the browser will display stuff as it gets it. But I know IE sometimes waits until the page is complete, then shows said content. Oh well. Just my $.02. Hope it helps.

        _14k4 - webmaster@poorheart.com (www.poorheart.com)
Re: A Simple
by perlcgi (Hermit) on Apr 25, 2001 at 18:06 UTC
    When returning output over a period of time (eg displaying unbuffered results of a slow operation in 'real' time) you may need to use NPH (No Parsed Headers) where the script undertakes to print the entire HTTP response including all necessary header fields. The HTTPD is thereby instructed not to parse the headers (as it would normally do) nor add any which are missing. If you are using Apache 1.3 or later forget about this, as it no longer buffers CGI output.

      This can easily be done with CGI.pm.

      print $q->header(-nph=>1);

      -thabenksta

      my $name = 'Ben Kittrell'; $name=~s/^(.+)\s(.).+$/\L$1$2/g; my $nick = 'tha' . $name . 'sta';
Re: A Simple "Tail" Question
by mlong (Sexton) on Apr 25, 2001 at 19:11 UTC
    You could just create a script that outputs the tail information and then does a refresh of itself. If you don't want to use CGI.pm, Try this:

    #!/usr/bin/perl
    
    print "Content-type: text/html\n\n";
    
    # Do tail stuff here
    my $tail = ...
    # Replace carriage returns with br and carriage return
    $tail =~ s/\n/<br>\n/g;
    
    # print it out
    print <<END_HTML
    <html>
    <head>
    <title>Tail Script</title>
    <META HTTP-EQUIV="REFRESH" CONTENT="2; URL=/cgi-bin/cgiscript.cgi">
    </head>
    <body>
    <h1>Tail Program</h1>
    <P>
    $tail
    </body>
    END_HTML
    
    

    Where "cgiscript.cgi" is the name of this script. (You might be able to use $0, but I haven't tried that in a CGI).

    Then the browser will refresh to your current CGI every 2 seconds or whatever interval you set in the meta tag.

    It's a hack, but it should work.

    -Matt

Re: A Simple
by Caillte (Friar) on Apr 25, 2001 at 18:56 UTC

    If I understand you correctly you want to run the equivalent of tail -f over a web link. The problem there is the CGI implementation doesnt really like things like that. Most servers time out their CGI scripts after 30-60 seconds or so (as defined by the server config) and any data sent after that will be lost.

    If you want to continuously send data to a web page you need to do one of three things. The first option is to use some sort of server push technology to keep on updating the page, however IE doesn't really like this. The second option is to put a refresh meta tag into the page you generate with your CGI script so that your page reloads itself after every n seconds, an example of this is below.

    <meta http-equiv="refresh" content="5;URL=This.html">

    This method, using the tag above, would refresh your page every 5 seconds. This method is very resources-intensive though.

    The final option is to place an applet or flash/director movie on your page and then establish a socket between that and a script on your machine. You can then maintain a permanent connection between the two. A good place to start looking into this option ould be via perlipc.

    On the other hand, I may have grasped the wrong end of the stick completely so please ignore me ;)

    $japh->{'Caillte'} = $me;

Re: A Simple . "Tail" Question
by lindex (Friar) on Apr 25, 2001 at 16:27 UTC
    Sorry, somehow the rest of the node title got lost on submit. the title of the node is supposed to be A Simple "Tail" Question


    lindex
    /****************************/ jason@gost.net, wh@ckz.org http://jason.gost.net /*****************************/