Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I asynchronously monitor a file in Perl?

I am wondering if it is possible, and if so how, one could create a perl script that constantly monitors a file/db, and then call a subroutine to perform text processing if the file is changed. I'm pretty sure this would be possible using sockets, but this needs to be used for a webchat application on a site running on a shared host, and I'm not so sure sockets would be allowed on it.

The basic idea is:

  • create a listener for a chat file/database
  • when the file is updated with a new message, call a subroutine
  • the called subroutine will send the new message back to the browser to be displayed

Thanks in advance.

like image 907
Hussain Avatar asked Apr 15 '10 22:04

Hussain


3 Answers

Many operating systems run a service that allows applications to register a request to be notified when a file or path has been updated. This is generally called a File Alteration Monitor. See the linked wikipedia page for some systems available. Recent linux systems use Inotify, previously Dnotify or gamin were used. OS X uses FSEvents. Windows has a similar system. I don't know of any module or mechanism that works cross platform for all these systems, but there are specific modules available on CPAN, such as SGI::FAM and File::Tail::FAM.

like image 80
kbenson Avatar answered Oct 23 '22 09:10

kbenson


I'd do this with a cron job and a Makefile that invoked a Perl script. The handy thing is that you get the Perl script's atime automatically as the timestamp to compare against, since the script's atime is updated when it is invoked.

like image 30
Ether Avatar answered Oct 23 '22 10:10

Ether


use POE qw(Wheel::FollowTail);
POE::Session->create(
    inline_states => {
      _start => sub {
        $_[HEAP]{tailor} = POE::Wheel::FollowTail->new(
          Filename => "/var/log/thttpd.log",
          InputEvent => "got_log_line",
          ResetEvent => "got_log_rollover",
        );
      },
      got_log_line => sub {
        #print "Log: $_[ARG0]\n";
        parseline($_[ARG0]);
      },
      got_log_rollover => sub {
        #print "Log rolled over.\n";
      },
    }
  );

POE::Kernel->run();
exit;

#parseline()...etc.
like image 1
superkuh Avatar answered Oct 23 '22 10:10

superkuh