How to monitor a directory with time and file using inotifywait? - linux

I need to listen a directory, I can listen if a file is created in this directory and it works
inotifywait -m -r -e moved_to -e create "$DIR" --format "%f" | while read f
do
if [[ $f = *.csv ]] ; then
do something
fi
done
But, if this file not created, I need to send emails at 12:00 and 19:00 (at 19:00) I need to kill the process.
So, how can I monitor file and system time using inotifywait? I tried using double conditions in while, but doesn't work

Use incrontab(5) with incrond(8). Of course you should install it and combine with test(1).
My opinion is that scripting languages like Guile, Python, Lua are better suited for such tasks. You'll find extensions to them related to inotify(7).
I need to send emails at 12:00 and 19:00 (at 19:00)
That is more a job for crontab(5)

Related

How would you make a shell script to monitor mounts and log issues?

I am looking for a good way monitor and log mounts on a CentOS 6.5 box. Since I am new to Linux shell scripting I am somewhat at a loss as to if there is something that is already around and proven which I could just plug in or is there a good method I should direct my research toward to build my own.
In the end what I am hoping to have running is a check of each of the 9 mounts on the server to confirm they are up and working. If there is an issue I would like to log the information to a file, possibly email out the info, and check the next mount. 5-10 minutes later I would like to run it again. I know that probably this isn't needed but we are trying to gather evidence if there is an issue or show to a vendor that what they are saying is the issue is not a problem.
This shell script will test each mountpoint and send mail to root if any of them is not mounted:
#!/bin/bash
while sleep 10m;
do
status=$(for mnt in /mnt/disk1 /mnt/disk2 /mnt/disk3; do mountpoint -q "$mnt" || echo "$mnt missing"; done)
[ "$status" ] && echo "$status" | mail root -s "Missing mount"
done
My intention here is not to give a complete turn-key solution but, instead, to give you a starting point for your research.
To make this fit your precise needs, you will need to learn about bash and shell scripts, cron jobs, and other of Unix's very useful tools.
How it works
#!/bin/bash
This announces that this is a bash script.
while sleep 10m; do
This repeats the commands in the loop once every 10 minutes.
status=$(for mnt in /mnt/disk1 /mnt/disk2 /mnt/disk3; do mountpoint -q "$mnt" || echo "$mnt missing"; done)
This cycles through mount points /mnt/disk1, /mnt/disk2, and /mnt/disk3 and tests that each one is mounted. If it isn't, a message is created and stored in the shell variable status.
You will want to replace /mnt/disk1 /mnt/disk2 /mnt/disk3 with your list of mount points, whatever they are.
This uses the command mountpoint which is standard on modern linux versions. It is part of the util-linux package. It might be missing on old installations.
[ "$status" ] && echo "$status" | mail root -s "Missing mount"
If status contains any messages, they will be mailed to root with the subject line Missing mount.
There are a few different versions of the mail command. You may need to adjust the argument list to work with the version on your system.
done
This marks the end of the while loop.
Notes
The above script uses a while loop that runs the tests every ten minutes. If you are familiar with the cron system, you may want to use that to run the commands every 10 minutes instead of the while loop.

How to kill a process on no output for some period of time

I've written a program that is suppose to run for a long time and it outputs the progress to stdout, however, under some circumstances it begins to hang and the easiest thing to do is to restart it.
My question is: Is there a way to do something that would kill the process only if it had no output for a specific number of seconds?
I have started thinking about it, and the only thing that comes to mind is something like this:
./application > output.log &
tail -f output.log
then create script which would look at the date and time of the last modification on output.log and restart the whole thing.
But it looks very tedious, and i would hate to go through all that if there were an existing command for that.
As far as I know, there isn't a standard utility to do it, but a good start for a one-liner would be:
timeout=10; if [ -z "`find output.log -newermt #$[$(date +%s)-${timeout}]`" ]; then killall -TERM application; fi
At least, this will avoid the tedious part of coding a more complex script.
Some hints:
Using the find utility to compare the last modification date of the output.log file against a time reference.
The time reference is returned by date utility as the current time in seconds (+%s) since EPOCH (1970-01-01 UTC).
Using bash $[] operation to subtract the $timeout value (10 seconds on the example)
If no output is returned from the above find, then the file wasn't changed for more than 10 seconds. This will trigger a true in the if condition and the killall command will be executed.
You can also set an alias for that, using:
alias kill_application='timeout=10; if [ -z "`find output.log -newermt #$[$(date +%s)-${timeout}]`" ]; then killall -TERM application; fi';
And then use it whenever you want by just issuing the command kill_application
If you want to automatically restart the application without human intervention, you can install a crontab entry to run every minute or so and also issue the application restart command after the killall (Probably you may also want to change the -TERM to -KILL, just in case the application becomes unresponsive to handleable signals).
The inotifywait could help here, it efficiently waits for changes to files. The exit status can be checked to identify if the event (modify) occurred in the specified interval of time.
$ inotifywait -e modify -t 10 output.log
Setting up watches.
Watches established.
$ echo $?
2
Some related info from man:
OPTIONS
-e <event>, --event <event>
Listen for specific event(s) only.
-t <seconds>, --timeout <seconds>
Exit if an appropriate event has not occurred within <seconds> seconds.
EXIT STATUS
2 The -t option was used and an event did not occur in the specified interval of time.
EVENTS
modify A watched file or a file within a watched directory was written to.

A script to test for traffic from a streaming server?

I have an instrument that streams data out a tcp port, and I'd like to use standard tools in a script to determine if the stream is available.
Manually I use ncat, which promptly exits if the data stream isn't available.
Here's my initial bash script:
#!/bin/bash
ncat somehost 1234 >/dev/null &
pid=$!
sleep 1
if [ -d /proc/$pid/ ]; then
kill -KILL $pid
echo "It's alive, ALIVE\!"
# Launch clients
else
echo "He's dead, Jim."
# Perform resurrection
fi
It works, but I'm wondering if there is a simpler or better way to accomplish this that doesn't rely on job control or procfs or even ncat. I'd also like to know how much data was sent before a timeout exires.
And, yes, in bash ncat host port can be replaced by cat </dev/tcp/host/port, but I'd also like to avoid bash-isms (so it can work under busybox).
Another approach would be to use wc to count the lines/chars output by ncat, since it outputs only one line and exits if the connection can't be made. But I can't wait forever for termination if the stream is up, so I'd need to use something like timeout, which has its own complications when trying to access the output of a command.
Is there a "plain" approach that works with minimal dependencies?
Or should I write a simple tool instead? It would return the number of bytes read if a connection was made to host/port, a negative errno otherwise, and would support a wait time and protocol spec (tcp/udp). A return value of 0 would mean the connection was made, but no data arrived before the wait time expired (a good thing to know).
Or maybe patch ncat to do the above?
I use netcat in FreeBSD, which has a -z option that simply checks whether a port is open. This eliminates the background and sleep you're using in your script.
-z Specifies that nc should just scan for listening daemons, without
sending any data to them.
The option exists in netcat on an old Ubuntu box here, so that might be an option for you.
$ nc -z somehost 1234 && echo "It's alive, ALIVE!"
I don't see an equivalent option in ncat. You may be able to compile netcat into busybox; it's much smaller than ncat, at least on my systems:
Linux:
$ ls -lH `which nc ncat`
-rwxr-xr-x 1 root root 31296 2010-02-21 01:32 /bin/nc
-rwxr-xr-x 1 root root 130448 2009-11-06 04:39 /usr/bin/ncat
FreeBSD:
ls -l `which nc ncat`
-r-xr-xr-x 1 root wheel 28112 Jan 15 14:53 /usr/bin/nc
-rwxr-xr-x 1 root wheel 182775 Mar 19 2012 /usr/local/bin/ncat
Of course, this doesn't help you check the amount of traffic that has come through the stream, or to analyse its content. For that, I think your solution is innovative and reasonable, though the challenge you've presented may not be resolvable easily.
You can use ps to avoid the procfs dependency, and you can store things in a temp file for analysis rather. Note that busybox should include a mktemp, but you should probably check the options. I haven't tested this:
#!/bin/sh
TMPFILE=`mktemp /tmp/str.XXXX`
trap "rm -f $TMPFILE" 0 1 2 3 15
nc somehost 1234 > $TMPFILE &
pid=$!
sleep 1
if ps $pid >/dev/null; then
kill -KILL $pid
echo -n "It's alive, "
if [ -s $TMPFILE ]; then
echo "ALIVE!"
else
echo "but unresponsive."
fi
else
echo "He's dead, Jim."
fi
That's all I've got. And it's not much different from what you already have.
Another option might be to build a custom tool that you might be able to compile into your own busybox, but that'll be a c question rather than a shell question. :-)

Storing application logs for a day

I have an application running in Production. Where we create the logs file. The maximum count of log file is set to 10 and maximum debug write is set to some value such that when a log file becomes of 6MB a new log file is created..
So, we have logs rolling over with file names like :-
<file_name>.log
<file_name>.log.1
<file_name>.log.2
...
<file_name>.log.10
What my problem is that only logs for 15 minutes can be found in these 10 log files.
I know I can update my code base to use DailyRollingFileAppender. But what I'm looking for is a short term solution to store logs for a day such that it can be done without any code changes or minimal code/configuartion changes. For exmaple may be I can acheive this via some cron job or linux command.. etc.
Note:- I'm running this application on Linux OS in production.
Any quick help is highly appreciated.
~Thanks
You may do this create a shell script and adding it to cron jobs.
NOW_DATE=$(date +"%m-%d-%Y-%H-%M")
cd /var/log/OLD_LOGS
mkdir /var/log/OLD_LOGS/$NOW_DATE
cd /var/log/
mv server.log.* /var/log/OLD_LOGS/$NOW_DATE/
mv *.zip /var/log/OLD_LOGS/$NOW_DATE/
cp server.log /var/log/OLD_LOGS/$NOW_DATE/
cd /var/log/OLD_LOGS/$NOW_DATE
x=$(ls -l |wc -l)
if [ $x -le 1 ] then
SUBJECT="There is an issue with generating server log - less number of files"
EMAIL="support#abc.com"
EMAILMESSAGE="/tmp/errormsg.txt"
/bin/mail -s "$SUBJECT" "$EMAIL" < $EMAILMESSAGE
fi
cd /var/log/OLD_LOGS/
zip -r $NOW_DATE.zip $NOW_DATE
rm -r -f $NOW_DATE
find /var/log/ -type f -mtime +180 -exec rm {} \;
If the application tries to create .log.11 and if it overwrites the old ones as per the script conditions, there is no possibility of having the logs for a day.
What i understand is application logging is much such that all the 10 files have loggings for last 15 minutes and the new lines are again overwritten on them.
Application logic should be modified to make sure it captures a day logs. Also, please make sure to zip the files at regular intervals so that you can save some disk space.

Is there a variable in Linux that shows me the last time the machine was turned on?

I want to create a script that, after knowing that my machine has been turned on for at least 7h, it does something.
Is this possible? Is there a system variable or something like that that shows me the last time the machine was turned on?
The following command placed in /etc/rc.local:
echo 'touch /tmp/test' | at -t $(date -d "+7 hours" +%m%d%H%M)
will create a job that will run a touch /tmp/test in seven hours.
To protect against frequent reboots and prevent adding multiple jobs you could use one at queue exclusively for this type of jobs (e.g. c queue). Adding -q c to the list of at parameters will place the job in the c queue. Before adding new job you can delete all jobs from c queue:
for job in $(atq -q c | sed 's/[ \t].*//'); do atrm $job; done
You can parse the output of uptime I suppose.
As Pavel and thkala point out below, this is not a robust solution. See their comments!
The uptime command shows you how long the system has been running.
To accomplish your task, you can make a script that first does sleep 25200 (25200 seconds = 7 hours), and then does something useful. Have this script run at startup, for example by adding it to /etc/rc.local. This is a better idea than polling the uptime command to see if the machine has been up for 7 hours (which is comparable to a kid in the backseat of a car asking "are we there yet?" :-))
Just wait for uptime to equal seven hours.
http://linux.die.net/man/1/uptime
I don't know if this is what you are looking for, but uptime command will give you for how many computer was running since last reboot.
$ cut -d ' ' -f 1 </proc/uptime
This will give you the current system uptime in seconds, in floating point format.
The following could be used in a bash script:
if [[ "$(cut -d . -f 1 </proc/uptime)" -gt "$(($HOURS * 3600))" ]]; then
...
fi
Add the following to your crontab:
#reboot sleep 7h; /path/to/job
Either /etc/crontab, /etc/cron.d/, or your users crontab, depending on whether you want to run it as root or the user -- don't forget to put "root" after "#reboot" if you put it in /etc/crontab or cron.d
This has the benefit that if you reboot multiple times, the jobs get cancelled at shut down, so you won't get a bunch of them stacking up if you reboot several times within 7 hours. The "#reboot" time specification triggers the job to be run once when the system is rebooted. "sleep 7h;" waits for 7 hours before running "/path/to/job".

Resources