检测何时不再写入日志,tail -f

时间:2014-04-26 16:15:21

标签: bash tail

我正在使用以下脚本,该脚本是根据我在网络上发现的其他想法拼凑而成的,以满足我监控日志文件和捕获错误的目的。

tail -f log_file | while read LOGLINE
do
  echo -e "${LOGLINE}"
  if [[ "${LOGLINE}" == *ERROR* ]] ; then
    echo -e "ERROR FOUND : ${LOGLINE}\n"

    # handle the error here

  fi
done

如果生成日志文件的程序崩溃或被终止且不再写入 日志,我怎么检测到它?事实上,tail只会等待并等到另一条线。

4 个答案:

答案 0 :(得分:2)

通常,如果您不一定知道进程名称,或者只是想知道任何进程是否正在访问文件,您可以尝试fuser。例如,在Linux上如果我有一个服务器进程写入server.log,那么fuser server.log给出类似的东西:

/var/log/server.log: 28977

其中28977是服务器进程的进程ID。当服务器进程退出时,fuser不返回任何内容。显然在你的情况下你也有尾部进程读取文件,所以你期望有多个PID,例如:

/var/log/server.log: 28977 28990

从手册页注意:“fuser仅将PID输出到stdout,其他所有内容都发送到stderr。”。因此,举例来说,您可以管道wc -w并检查您至少获得2。获取1只表示您的tail -f正在访问该文件。

在循环中集成它的障碍是read将阻塞,直到它可以读取一行,因此在文件未被写入任何更长时间后,在循环内执行的任何检查都将永远不会运行。您需要使用read -t并指定超时。像这样:

tail -f log_file | while [ 1 ]
do
  read -t 10 LOGLINE
  if [[ -z "${LOGLINE}" && $? -ne 0 ]] ; then
    # Variable is empty and read timed out
    if [[ `fuser log_file 2> /dev/null | wc -w` < 2 ]] ; then
      # Nothing else is using the log file     
      pkill -f "tail -f log_file"  # Specific, so we don't kill tails of other files
      break
    fi
  else
    echo -e "${LOGLINE}"

    # Do your stuff...
  fi
done

(感谢anubhava提醒我pkill!另外,请注意,如果你知道写入日志的过程有足够的识别信息,你可以做一个pgrep而不是热熔器检查。)

如果您正在使用Linux,那么更简单的另一件事就是使用尾部的--pid选项,如果具有该PID的进程已停止,它将停止它。然后你可以这样做:

LOG_WRITER=`pgrep something-identifying-the-process-writing-the-log`
tail -f log_file --pid=$LOG_WRITER | while read LOGLINE
…the rest of your script

然而,似乎可能存在这种情况,即没有注意到该过程已经停止。这对你来说可能已经足够了。

答案 1 :(得分:1)

您可以致电pgrep检查原始流程是否正在运行&gt;

while read -r LOGLINE
do
  echo -e "${LOGLINE}"
  if [[ "${LOGLINE}" == *ERROR* ]] ; then
    echo -e "ERROR FOUND : ${LOGLINE}\n"

    # handle the error here
    if pgrep -q process; then
      echo "process has exited/crashed"
      # kill tail process and break out of loop
      pkill -f tail
      break
    fi

  fi
done < <(tail -f log_file)

答案 2 :(得分:1)

要获取打开日志文件的所有进程的进程ID,请使用lsof

lsof -Fp /path/to/your/logfle

请注意,这只会显示实际打开文件的进程。您可能会错过使文件保持关闭的程序,除非它们实际需要写入时的短暂时刻。

lsof对脚本友好,有很多选项。请参阅man lsof

这是一个脚本,一旦没有打开日志文件的进程,它就会将消息写入屏幕:

while lsof -Fp /tmp/mylogfile  >/dev/null
do
    sleep 1
done
echo "No processes have the log file open"

上面有一个问题:您的tail -f进程将打开文件。当打开该文件的进程数低于2时,您可能希望显示该消息:

while [ "$(lsof -Fp /tmp/mylogfile | wc -l)" -ge 2 ]
do
    sleep 1
done
echo "There are less than two processes with the log file open"

[我最初在Unix site上回答了这个问题。由于这个问题正在被关闭,我在这里保留答案。]

答案 3 :(得分:0)

您的方法存在一般问题:

while ... 构造中的代码仅在日志文件更改时运行,即当有问题的进程将某些内容写入日志文件时。

现在,如果该进程在没有写入日志文件的情况下崩溃(您要检测的事件),那么您将永远不会再次进入while循环体。

因此,在while循环中检查进程是否有效是没有用的 - 除非进程在崩溃时在日志中留下有用的消息,那么你当然可以检查这样的消息。

您必须运行第二个监控流程,以检测流程何时终止。该问题的一个简单解决方案是mon,您可以在此处找到:https://github.com/visionmedia/mon

我建议不要进行间接检查(“是否仍然可以写入日志文件?”);只是直接检查过程,并使用专门的工具来做到这一点。