patternbashMinor
Bash log monitoring
Viewed 0 times
monitoringbashlog
Problem
I've made a Bash script to monitor some server log files for certain data and my method probably isn't the most efficient.
One section specifically bugs me is that I have to write a newline to the monitored log so that the same line wont be read over continually.
Feedback would be greatly appreciated!
``
if [ "$line" > 1 ]; then
sed -i "$line"d $offlinefile
unset loginplayer
unset line
fi
fi
# Check for Player Logout
if [ ! -z "$logoutplayer" ]; then
echo "$logoutplayer $logoutdate $logouttime" >> "$offlinefile"
echo "Player $loginplayer logout detected" >> "$serverlog"
One section specifically bugs me is that I have to write a newline to the monitored log so that the same line wont be read over continually.
Feedback would be greatly appreciated!
``
#!/bin/bash
serverlog=/home/skay/NewWorld/server.log
onlinefile=/home/skay/website/log/online.log
offlinefile=/home/skay/website/log/offline.log
index=0
# Creating the file
if [ ! -f "$onlinefile" ]; then
touch $onlinefile
echo "Name Date Time" >> "$onlinefile"
fi
if [ ! -f "$offlinefile" ]; then
touch $offlinefile
echo "Name Date Time" >> "$offlinefile"
fi
# Functions
function readfile {
# Login Variables
loginplayer=tail -1 $serverlog | grep "[INFO]" | grep "joined the game" | awk '{print $4}'
logintime=tail -1 $serverlog | grep "[INFO]" | grep "joined the game" | awk '{print $2}'
logindate=tail -1 $serverlog | grep "[INFO]" | grep "joined the game" | awk '{print $1}'
# Logout Variables
logoutplayer=tail -1 $serverlog | grep "[INFO]" | grep "left the game" | awk '{print $4}'
logouttime=tail -1 $serverlog | grep "[INFO]" | grep "left the game" | awk '{print $2}'
logoutdate=tail -1 $serverlog | grep "[INFO]" | grep "left the game" | awk '{print $1}'
# Check for Player Login
if [ ! -z "$loginplayer" ]; then
echo "$loginplayer $logindate $logintime" >> "$onlinefile"
echo "Player $loginplayer login detected" >> "$serverlog"
line=grep -rne "$loginplayer" $offlinefile | cut -d':' -f1`if [ "$line" > 1 ]; then
sed -i "$line"d $offlinefile
unset loginplayer
unset line
fi
fi
# Check for Player Logout
if [ ! -z "$logoutplayer" ]; then
echo "$logoutplayer $logoutdate $logouttime" >> "$offlinefile"
echo "Player $loginplayer logout detected" >> "$serverlog"
Solution
Your goal is to monitor
Note that
I'm going to guess that
It's also possible to skip
but there could be a vulnerability if
With other versions of
$serverlog continuously, and update $onlinefile and $offlinefile accordingly. The fact that you repeatedly close and reopen $serverlog is problematic, not only for performance reasons, but as you remarked, you risk processing the same line endlessly. Therefore, your general strategy should be to keep the file open, like this:tail -f "$serverlog" | do_all_processing_hereNote that
grep "[INFO]" doesn't do what you intend; instead, it matches lines that contain any of the characters I, N, F, or O. You probably meant grep -F '[INFO]' — the -F causes grep to treat your pattern as a fixed string rather than a regular expression. Then, your structure would be:tail -f "$serverlog" | grep -F '[INFO]' | do_more_processing_hereI'm going to guess that
[INFO] would appear in the third field of your server log. If so, the efficient solution would be…tail -f "$serverlog" | \
while read date time severity player message ; do
case "$severity" in
\[INFO\])
case "$message" in
*joined the game*)
echo "$player $date $time" >> "$onlinefile"
sed -i -e "$(
awk -v player="$player" '$1 == player { print NR "d;"}' "$offlinefile"
)" "$offlinefile"
;;
*left the game*)
echo "$player $date $time" >> "$offlinefile"
sed -i -e "$(
awk -v player="$player" '$1 == player { print NR "d;"}' "$onlinefile"
)" "$onlinefile"
;;
esac # case $message
;;
esac # case $severity
doneIt's also possible to skip
awk and edit $offlinefile and $onlinefile directly withsed -i "/^$player /d" "$offlinefile"but there could be a vulnerability if
$player contained special characters such as .*. A better solution, if you have GNU awk ≥ 4.1.0, isawk -v player="$player" '$1 != player' -i inplace "$offlinefile"With other versions of
awk, you could use tempfile to help you perform the edit.Code Snippets
tail -f "$serverlog" | do_all_processing_heretail -f "$serverlog" | grep -F '[INFO]' | do_more_processing_heretail -f "$serverlog" | \
while read date time severity player message ; do
case "$severity" in
\[INFO\])
case "$message" in
*joined the game*)
echo "$player $date $time" >> "$onlinefile"
sed -i -e "$(
awk -v player="$player" '$1 == player { print NR "d;"}' "$offlinefile"
)" "$offlinefile"
;;
*left the game*)
echo "$player $date $time" >> "$offlinefile"
sed -i -e "$(
awk -v player="$player" '$1 == player { print NR "d;"}' "$onlinefile"
)" "$onlinefile"
;;
esac # case $message
;;
esac # case $severity
donesed -i "/^$player /d" "$offlinefile"awk -v player="$player" '$1 != player' -i inplace "$offlinefile"Context
StackExchange Code Review Q#28734, answer score: 4
Revisions (0)
No revisions yet.