我从崩溃的应用程序中获得了许多日志文件(20-500)。所有日志文件都来自应用程序的一次运行 - 它是高度多线程的,每个线程都写入自己的文件。但日志是大的。 (在某些情况下,每个可能是数百 MB)
现在,其中一个线程崩溃了,当它崩溃时,它会将一条消息写入其日志文件的最后一百行左右。有时线程都完成正常并且该行从未被写入。
我运行崩溃应用程序的包装脚本位于 bash 中,我想检测应用程序何时以这种方式崩溃,以便我可以重新启动它。我能做比以下更好的事情吗:
# We want to run at least once
CRASHED=1
while [ CRASHED -eq 1 ]
# Run the app
run_application
# Check the end of all the logs for KEY
CRASHED=0
for x in logs/* ; do
if tail -n 100 $x | grep "KEY" ; then
CRASHED=1
# We'll only find it once, so may as well bail out now
break
fi
done
done
我主要感兴趣的是是否可以用内置的东西替换日志文件上的循环。我不能只使用
grep "KEY" logs/*
因为文件太大,效率不高。
答案1
使用;
tail --follow -n 100 *.log | grep -q key
如果应用程序实际上在崩溃时退出,则省略 --follow 。 https://linux.die.net/man/1/tail
答案2
由于您已经能够暂停直到应用程序退出,因此您可以仅搜索最近修改过日志文件。您可以按数量或时间进一步限制此集合。
以下是一些假设日志文件名相当合理的替代解决方案。
假设日志文件名不包含空格,并且崩溃消息写入最后几 (6) 个文件之一中的某个位置:
if grep -q "KEY" $(ls -dt logs/* | head -6) then echo FOUND; else echo NOT FOUND fi
假设日志文件名可能包含空格,但崩溃消息写入最后写入的几 (6) 个文件之一
ls -t logs | head -6 | ( while IFS= read -r f do grep -q "KEY" logs/"$f" && break done exit 1 ) if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
假设日志文件名可能包含空格,但崩溃消息写入最后几 (6) 个写入的文件之一的最后部分(400 行)
ls -t logs | head -6 | ( while IFS= read -r f do tail -n400 logs/"$f" | grep -q "KEY" && break done exit 1 ) if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
假设日志文件名不包含空格,并且崩溃消息写入最近几 (5) 分钟内写入的文件之一
if grep -q "KEY" $(find logs -type f -min -5) then echo FOUND; else echo NOT FOUND fi
假设日志文件名可能包含空格,但崩溃消息写入最近几 (5) 分钟内写入的文件之一
find logs -type f -min -5 | ( while IFS= read -r f do grep -q "KEY" "$f" && break done exit 1 ) if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
假设日志文件名可能包含空格,但崩溃消息写入最近几 (5) 分钟写入的文件的最后部分(400 行)
find logs -type f -min -5 | ( while IFS= read -r f do tail -n400 "$f" | grep -q "KEY" && break done exit 1 ) if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
答案3
最后我采用了评论中的一些方法。将尾部从核心循环中取出可以进一步简化逻辑:我最终得到的是这样的:
while true
echo "Starting the application"
run_application
echo "Application exited - checking logs for KEY"
if ! tail -qn 100 logs/* | grep -q "KEY"
then
echo "Failed without KEY in the logs - exiting"
break
fi
echo "Failed with KEY in the logs - restarting"
done