4
\$\begingroup\$

We have a process that outputs to log files in the format /var/log/xxx/YYYY_MM_DD.log - the file name is chosen programmatically and is not rotated using logrotate or anything like that. We want to automatically tail the latest file and pipe that to slackcat so that we can see the logs in a certain slack channel.

I came up with the following solution that works great, but I'm no bash expert so I am wondering if this could be simplified? The hardest part was avoiding zombie processes when something dies or gets killed, but I'd love to do this with one file instead of 2 also:

watchlogdir.sh

#!/bin/sh
trap "pkill -TERM -g $$; exit" INT TERM EXIT
 while true; do
 /root/tailtoslack.sh &
 PID=$!
 echo $PID
 echo $$
 inotifywait -e create /var/log/xxx/
 pkill -TERM -P $PID
 kill $PID
done

tailtoslack.sh

while true; do
 FILETOWATCH=`ls -t /var/log/xxx/*.log | head -1`
 tail $FILETOWATCH -f -n1 | grep -v "DEBUG:\|^$" --color=never --line-buffered | /root/slackcat &> /tmp/slackcat
 sleep 31
done

The core of watchlogdir.sh, besides the interruption handling stuff, is using inotifywait to watch for a new file created in the log directory, and when that happens, killing tailtoslack.sh and respawning it so it can find the new file

tailtoslack.sh just looks for the latest file, and pipes that to slackcat after filtering out DEBUG lines and empty lines. the while loop here is because some lines in the error logs cause slackcat to crash, so this way if that happens it'll sleep for a little while and retry.

Without changing the requirements of how the log files are written, can any of this be done better?

chicks
2,8593 gold badges18 silver badges30 bronze badges
asked Mar 5, 2016 at 21:14
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

This seems quite fine. Given your circumstances, I don't see how this can be done simpler.

(削除) The script could use a bit of tidying up though. The indentation of watchlogdir.sh is haphazard, it would be more readable to make it consistent. (削除ここまで) Oh I see now. It's the $$ that messes things up, your formatting is fine.

In the other script, this line could be written better:

FILETOWATCH=`ls -t /var/log/xxx/*.log | head -1`

By using $(...) instead of `...` for command substitution, and using the canonical option -n1 instead of -1 with head:

FILETOWATCH=$(ls -t /var/log/xxx/*.log | head -n1)
answered Mar 5, 2016 at 21:30
\$\endgroup\$
5
  • \$\begingroup\$ thanks! As you can see, stackexchange seems to be doing something weird to the indentation, I can't figure out why but it is in fact sane in the actual file. \$\endgroup\$ Commented Mar 5, 2016 at 22:42
  • \$\begingroup\$ uggh, I see. Amended my post \$\endgroup\$ Commented Mar 5, 2016 at 22:58
  • \$\begingroup\$ Don't parse the output of ls! At least use the -1 option to guarantee only one entry per line! \$\endgroup\$ Commented Mar 6, 2016 at 10:27
  • 1
    \$\begingroup\$ @DavidFoerster I don't think that getting the first line of ls is really parsing. I think that recommendation concerns parsing the content of lines, especially the output of ls -l. I also don't see how -1 has an effect on the pipeline to | head -n1. As far as I know it only affects display in an interactive shell. Please do correct me if I'm wrong. \$\endgroup\$ Commented Mar 6, 2016 at 10:35
  • \$\begingroup\$ I never thought of the different defaults for interactive and non-interactive output. Makes sense though. +1 \$\endgroup\$ Commented Mar 6, 2016 at 11:02

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.