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

I've started playing with POE::Wheel::FollowTail to monitor many logfiles and create a new logfile of the stuff I was interested in. Optionally, I would backquote execute other scripts when I run across specific things I was interested in. For the most part, all this is working fine.

My list of what files to look at, a list of strings to look for in each log file, and an optional script-name to run, are all contained in a configuration file that gets read when my FollowTail script starts up.

Without stopping my FollowTail script, how could I detect whether my configuration file changed so I could re-read it and update my list of files/strings to monitor?

Another question: I want to allow other applications to grab (read, delete, rename) my consolidated logfile at any time. So I'm opening for append/writing/closing through a file handle each time I add stuff. Is this the most efficient way? It'd be faster if I could just leave my logfile open for append, but then no one can grab the file at any time.

Finally, I have a Unix (maybe Perl) question that's not really related, but kinda is. There is a VxWorks system that I can only telnet into, and once in, that system is continually spewing out stuff that my FollowTail script would monitor if only the stuff was going to a log file. The developers of the other system do not want to write the stuff to a log file and make it accessible to me via NFS mount (it "puts too much of a load on the cpu"). And there's no rsh or ssh allowed into their system. With that, I assume they won't want to do any sockets with me.

I was just wondering, since I can telnet in and see everything dumped to the screen, could I intercept that stream? Sort of a telnet pipe out?

Thanks.

Replies are listed 'Best First'.
Re: POE::Wheel questions
by Tanktalus (Canon) on Sep 30, 2005 at 23:09 UTC

    Normally, most programs that allow reload of configurations have a SIGHUP signal handler (or SIGUSR1) which causes the reload. The reason for this is simple: you don't want to reload an incomplete file - if the sysadmin is in the middle of saving when you notice the file changed, you could interrupt the save process, read half a file, and get something that didn't make sense. Or maybe the sysadmin was saving progress as they went because they were worried about losing changes - e.g., working via dial-up, and worried that their connection would drop at any minute now that their teenaged daughter just got home from school and would mindlessly pick up the phone to call her friends who she just left not more then 20 minutes ago at school, but had to call them right now! In that case, you don't want to pick up the changes until the user explicitly told you to. And the popular way, as I said, is to run "kill 1 `cat /var/pid/yourprogram.pid`". Or something to similar effect. (1 is SIGHUP on most systems.)

    Efficient means you need to keep the filehandle open - opening for append on each line can get expensive for large files. More efficient may be to log to a database and let the database handle the conflicts.

    Final question: yes - you could telnet in via Net::Telnet and do whatever you want with the incoming data.

      Great advice on questions 1 and 3, Tanktalus.

      I'll look into signals for my first problem (seeing when the configuration file finished being changed).

      For the 3rd problem, the remote system is out of my control: I telnet to it without a userid/password and I'm in. The remote system (running VxWorks) offers few commands and immediately dumps stuff, I presume, to stderr. So I was going to use $telnet->getline, but I can't get past $telnet->login because that statement requires username and password.

      On the 2nd question, my app is a middleman ... I let people define what logfiles (and search string and optional run-if-match command) to look for and then I generate a single new logfile that must be in a specific format. Another existing app will look at my new logfile and it can grab that data at any time and rotate it out (rename it) into a backup file. That's the reason I'm doing the inefficient open/write/close each time. So I'm not sure how I can use a database since I'm not privy to the app reading my output logfile. I had hoped opening in append mode would not lock it so the other app could grab it, but alas that didn't work. One other less efficient choice is a system call to cat to append things.

      UPDATE ON Net::Telnet

      Played some more and discovered that the Net::Telnet->new() made the connection to the id-less/psw-less system and I didn't need to do a $telnet->login. Since the remote system is forever dumping data (as far as I was concerned), I planned to looped forever:

      my $line; while ($line = $telnet->getline) { print $line; }
      But since it dumps data at different times, I ran into a "read timed-out" problem. Is there a way to disable the timeout? Setting to 0 didn't work, so I set it to a high value (one day):
      my $line; while ( $line = $telnet->getline(Timeout=>86400000) ) { print $line; }

        Log file: Sorry, I don't have any suggestions if you can't control your consumers. In that case, there's no point in calling the system 'cat' command - it will just do the same thing: open the file in append (well, the shell will do that), which automatically seeks to the end, write out, and close the filehandle. That would be even more inefficient.

        Mind you, if the rotation happens before the files get too large, the inefficiencies will be reduced. Each time you open a file and seek to the end, you won't seek very far, which will limit the ugliness. Note that it may still be an O(n) operation to seek to the end, but we're keeping n from getting too large.

        As for your timeout, I don't see any way to disable it. Better, then, may be simply to handle it by retrying. Set the errmode to 'return', and test to see if getline returns undef. Check the timed_out method to see if the undef is because of a timeout (then redo) or not (then last to end the loop - you're disconnected, most likely).

        $telnet->errmode('return'); while (my $line = $telnet->getline(Timeout => 3600)) { if (not defined $line and $telnet->timed_out()) { # print LOGFILE "It's been an hour since the last text... still wa +iting.\n"; redo; } print $line; }

        Hope that helps,