Linux下实时跟踪log4j日志文件的bash脚本 - 增强了tail -f的功能

本文链接:http://codingstandards.iteye.com/blog/803686   (转载请注明出处)

问题描述

  在开发Java应用程序时,我们经常使用log4j作为日志输出工具,它可以根据配置文件来决定生成日志文件的策略,比如可以配置成每小时生成一个日志文件(附件压缩包里有log4j.properties的样本)。我们可以用tail -f logfile的形式去实时跟踪日志,以方便观察程序运行的信息。但是在log4j配置成每隔一定时间生成文件时,当时间间隔到达时,原来的日志文件会根据一定规则进行改名,比如ADMIN.LOG改成ADMIN.2010-11-05-10的格式,然后log4j会重新创建一个新的日志文件。这个时候,就会发现正在运行的tail -f命令不会继续输出新的日志文件内容,而是停在那里不动了,需要Ctrl+C杀掉原来的,再重新运行。能不能通过某种方式来避免这种情况发生呢?

 

解决思路

  Linux系统下每个文件都有一个称为inode的数值,相当于文件的ID,在重新创建文件时,系统会新分配一个inode给这个文件,因此我们可以根据文件的inode是否改变来判断是否有新的日志文件生成。我根据这一点编写了一个bash脚本ftail.sh来做到了原来tail -f无法做到的事情,见后面的脚本内容部分,里面有注释。

使用方式

   载附件ftail.tar.gz,上传到Linux系统,然后执行tar zxf ftail.tar.gz,就可以看到ftail.sh了。

 

  格式:ftail.sh <file>

 

[root@web web_server]# ./ftail.sh 
+-------------------------------------------------------------------------------------------------------+
| ftail.sh v0.1 - a bash script that enhanced 'tail -f', written by codingstandards@gmail.com |
+-------------------------------------------------------------------------------------------------------+
 

usage: ./ftail.sh <file>

[root@web web_server]# ./ftail.sh log/ADMIN.LOG 
+-------------------------------------------------------------------------------------------------------+
| ftail.sh v0.1 - a bash script that enhanced 'tail -f', written by codingstandards@gmail.com |
+-------------------------------------------------------------------------------------------------------+

##### ./ftail.sh: FILE log/ADMIN.LOG INODE=118259971 PID 11495 #####

此处省略了日志输出的具体内容。

提示:可以把ftail.sh复制到/usr/bin下,然后就可以在任何有日志的目录进行使用了。

[root@web web_server]# cp ftail.sh /usr/bin -af 
cp:是否覆盖“/usr/bin/ftail.sh”? y
[root@web web_server]# ftail.sh log/ADMIN.LOG 
+---------------------------------------------------------------------------------------------+
| ftail.sh v0.1 - a bash script that enhanced 'tail -f', written by codingstandards@gmail.com |
+---------------------------------------------------------------------------------------------+

##### /usr/bin/ftail.sh: FILE log/ADMIN.LOG INODE=118259971 PID 11973 #####

此处省略了日志输出的具体内容。

脚本内容

附件压缩包中的ftail.sh文件

Bash代码   收藏代码
  1. #!/bin/sh  
  2.   
  3. # ftail.sh = tail -f 的增强版本,可检查文件是否重建过或删除过  
  4. # usage: ftail.sh <file>  
  5. # author: codingstandards@gmail.com  
  6. # release time: v0.1 2010.11.04/05  
  7.   
  8. # 显示title  
  9. echo "+---------------------------------------------------------------------------------------------+"  
  10. echo "| ftail.sh v0.1 - a bash script that enhanced 'tail -f', written by codingstandards@gmail.com |" >&2  
  11. echo "+---------------------------------------------------------------------------------------------+"  
  12. echo  
  13.   
  14. # 判断参数个数  
  15. if [ "$#" != "1" ]; then  
  16.     echo "usage: $0 <file>" >&2  
  17.     exit 1  
  18. fi  
  19.   
  20. # 取文件参数  
  21. FILE="$1"  
  22.   
  23. # 取文件的inode  
  24. INODE=$(stat -c "%i" "$FILE")  
  25.   
  26. # 启动tail -f进程,并打印信息  
  27. # usage: fork_tail  
  28. fork_tail()  
  29. {  
  30.     if [ -r "$FILE" ]; then  
  31.         tail -f "$FILE" &  
  32.         PID=$!  
  33.         echo "##### $0: FILE $FILE INODE=$INODE PID $PID #####" >&2  
  34.     else  
  35.         PID=  
  36.         INODE=  
  37.         echo "##### $0: FILE $FILE NOT FOUND #####" >&2  
  38.     fi  
  39. }  
  40.   
  41. # 杀掉tail进程  
  42. # usage: kill_tail  
  43. kill_tail()  
  44. {  
  45.     if [ "$PID" ]; then  
  46.         kill $PID  
  47.     fi  
  48. }  
  49.   
  50. # 检查inode是否变化了  
  51. # usage: inode_changed  
  52. inode_changed()  
  53. {  
  54.     NEW_INODE=$(stat -c "%i" "$FILE" 2>/dev/null)  
  55.     if [ "$INODE" == "$NEW_INODE" ]; then  
  56.         return 1  
  57.     else  
  58.         INODE=$NEW_INODE  
  59.     fi  
  60. }  
  61.   
  62. # 设置陷阱,按Ctrl+C终止或者退出时杀掉tail进程  
  63. trap "kill_tail; exit" SIGINT SIGTERM SIGQUIT EXIT  
  64.   
  65. # 首次启动tail -f进程  
  66. fork_tail  
  67.   
  68. # 每隔一定时间检查文件的inode是否变化,如果变化就先杀掉原来的tail进程,重新启动tail进程  
  69. while :  
  70. do  
  71.     sleep 5  
  72.     if inode_changed; then  
  73.         kill_tail  
  74.         fork_tail  
  75.     fi  
  76. done  
  77.   
  78. # END.  

 

Logo

更多推荐