Perl script logging via Shell script

Hello

I wrote a nice Perl script that is intended to find and copy some files when getting a TERM signal. Now I wanted to make a shell script that starts/restarts the Perl script if it crashes/ends because of errors and make a log of all output the Perl Script gives. The problem is that it won't write any output to my logfile :frowning:
Here is my Shell script:

#!/bin/sh

pidcheck=`pidof perl | grep -c [0-9][0-9][0-9][0-9]`
while [ $pidcheck -ne 0 ]
do
        kill -9 `pidof perl`
done
echo "\n------------------------------\n" >> log.txt
date >> log.txt
echo "\n------------------------------\n" >> log.txt
while [ 1 -eq 1 ]
do
        `perl handler.pl >> log.txt`
        echo "Perl-Script crashed, restarting..." >> log.txt
done

I think it would write if I don't put the `` around `perl handler.pl >> log.txt`, but then I can't send any signals to my perl script :confused:

Can (maybe) someone help me? ^^' thanks in advance and sorry for my bad english :rolleyes:

doesn't anyone have an idea? :frowning:
pleaaase I need the code within the next 3 days and I really don't know how to get it working (neither does google) :confused:

just joined the forum. and this thread is very old as well.

but would like to make a comment if some searcher can get this helpful.

you can schedule your script in cron to run every minute
and in your perl script check at the starting if another instance of script is running.
if so ...quit. else continue..

dont tell me that you need a code as well for this.. its pretty simple and wont take more then 3 lines..

Thank you for your reply but that wasn't my problem...
My problem was that I couldn't log anything :stuck_out_tongue:

And I asked for help to finish my code, not for the code itself :wink:
And btw I don't see why cron should help in my case? I needed a script making something when I send a TERM signal, not a script making something at a specific date/time...

okay, so you were actually looking for a graceful shutdown or termination.
or technically saying a interrupt handler..

you probably could use
$SIG{'INT'} = 'interrupt_handler';

sub 'interrupt_handler {
print("Script got a termination signal, shutting down...!\n");
exit; # or may be you want to continue ignoring the signal then dont use exit.
}

I hope that would help.

Not really shutdown - more a sighandler.
I didn't wanted to end my script but to make something (f.e. write "hello" into a text file).

[edit]: yeah I used that in my script but there was a problem that my script wouldn't catch any signals when I'm logging it via the script I posted... I'm sorry it's a bit complicated to explain >< ...
I'm sorry I can't test your solution because I don't have the script anymore >
>
But it's nice that you answered for anyone finding this when searching for it! :slight_smile:

Maybe this is partly about logging on a buffered fd/FILE* like stdout, not unbuffered stderr, and no periodic flush(), with lost output when the script hangs and has to be killed? Logging through a pipe chain has a similar latency problem with potential lost output. One workaround for infrequent logging is to log by

system("echo 'Message' >>log_file")

or

system("date '+%Y-%m-%d %H:%M:%S Message' >>log_file")

or equivalent calls in perl using ``.

From my understanding your perl script should run all the time and if its gets killed your shell script should start it.

If above understanding is right then, i have some comments

#!/bin/sh

# Try to find PID of thing which starts with perl , check the count 
# if count is greater than 0 then kill whatever is running... 

# Bit risky unless you are 100% sure anything running with perl is 
# your script, too generic.

pidcheck=`pidof perl | grep -c [0-9][0-9][0-9][0-9]`
while [ $pidcheck -ne 0 ]
do
        kill -9 `pidof perl`
done
echo "\n------------------------------\n" >> log.txt
date >> log.txt
echo "\n------------------------------\n" >> log.txt

# i am not sure why are you running this script 
# without checking if script is running or not .. if that logic in the perl script
# then really bad coding to start another process every time , there is not 
# even sleep of 1-2 sec 

while [ 1 -eq 1 ]
# if you want to run while loop in infinite loop 
# use "while :" 
do
        # in perl to execute system command you use backticks 
        # where as in shell script you run directly 
        # like perl handler.pl >> log.txt
        # to get date did you do `date >> log.txt` ? 
        `perl handler.pl >> log.txt`
        echo "Perl-Script crashed, restarting..." >> log.txt
done

Here are my script 1 shell wrapper & 1 perl script both works fine i dont have *nix terminal @ my place so its on cygwin ..it works there so shouldnt be a problem on *nix

# cat a.sh
#! /bin/bash
echo "------------------\n">> /tmp/log.txt
date >>/tmp/log.txt
echo "------------------\n">> /tmp/log.txt

while :
do
    echo "Running perl script again ..."
    perl a.pl >> /tmp/log.txt 2>&1
    echo "Running Perl script for fun ...\n" >> /tmp/log.txt
done

# cat a.pl
#! /bin/env perl
  print "Fun Perl Script ....\n" ;
  sleep 10 ;
exit ;

# bash a.sh
Running perl script again ...
Running perl script again ...
Running perl script again ...

# cat /tmp/log.txt
------------------\n
Sun Nov 21 13:29:01 IST 2010
------------------\n
Fun Perl Script ....
Running Perl script for fun ...\n
------------------\n
Sun Nov 21 13:37:32 IST 2010
------------------\n
Fun Perl Script ....
Running Perl script for fun ...\n
Fun Perl Script ....
Running Perl script for fun ...\n

To the original poster - you are doing some strange stuff here.

Normally to make sure your perl script always ran, you would run it like this:

while true; do perl myscript.pl ; echo restarting; done > out.log

Add a & to run it in the background.

The "pidof perl" is dangerous since you might have many perl scripts running on the system. You'd be better off with something like this in your perl script:

open(pidfile,">$0.pid") && print pidfile $$;close pidfile;

Yeah I know I didn't knew much about perl and shell scripts thats why I had a weird way to solve it, but now I know much more about shell that's why I'm not using this script anymore.
And I don't think there where any other Perl scripts running in the background, since the system doesn't have any perl scripts to run and it's an embedded system...

Be careful! Some system scripts rely on perl for various tasks, such as logrotation, file indexing, etc.

You can fuser the app's log before attaching to it, to see if you are already running, without additional files and fuss. I am not much of a perl jocey, but maybe you can do the sam check inside PERL; in ksh, it might look like this:

 
ps -fp $(fuser $logfile 2>/dev/null) | grep -c my_app | read ct

---------- Post updated at 10:48 AM ---------- Previous update was at 10:31 AM ----------

The pid file is popular, but you still need to ps -fp | grep or the like to ensure the pid in use is your app.

A tcp socket listener makes a nice mutex. You could assign a thread to providing a simple html status report within the app.

Using 'fuser' or the PERL equivalent on the app log file has several advantages and challenges:

  1. You find any children still running. You might want to purge them and restart if the main app is not running.
  2. No extra pid file.
  3. subshells make the count go up.
  4. users browsing the log may look like the app or like children, especially as the log path often contains the app name. (Maybe capitalize part of the app name in the log name?)