定期从文件中获取新行,可能会进行日志轮转

定期从文件中获取新行,可能会进行日志轮转

我正在寻找一种相当简单的方法(不涉及开发——我可以用Python编写它,但我希望已经有一些东西)。

我有一个日志文件(在我的例子中是由 rsyslogd 编写的)。出于分析目的,我想每 1 分钟读取一次并计算最后一分钟的指标,例如我的 http 服务器有多少页面点击。我的2个要求:

1)我只想查看自上次读取文件以来添加的行。 (我只需要最后一分钟左右,文件太大,无法每分钟重新读取和过滤)。

2) 每天对文件进行一次记录。日志轮换后第一次,我想要我尚未读取的前一个文件中的所有行,以及新文件中的所有行。

我想我现在是唯一有这样要求的人了——其他人会做什么呢?

答案1

假设your-filter从 stdin 读取其数据:

while your-filter; do
  sleep 60
done < file.log

例如,假设your-filter只是读取数据并且不尝试写入数据。lseek

现在,为了解决日志轮换问题,如果在 Linux 上(与大多数其他系统相反,/dev/fd/n是指向实际文件的符号链接),使用ksh, bash, zsh, dash, yash(大多数 POSIX shell,除了最迂腐的 POSIX shell,比如poshas-ef不是 POSIX) :

while your-filter; do
  if [ file.log -ef /dev/stdin ]; then
    sleep 60
  else
    exec < file.log
  fi
done < file.log

在日志轮换时,your-filter如果您希望将旧的和新的连接调用一次,那么它将调用两次:

while 
  if [ file.log -ef /dev/stdin ]; then
    your-filter
  else
    exec 3<&0 < file.log
    (cat <&3; cat) | your-filter &&
      exec 3<&-
  fi
do
  sleep 60
done < file.log

现在,在日志轮转时,可能有一段时间旧的 file.log 已被重命名,但新的 file.logfile.log尚未创建,在这种情况下,如果exec < file.log此时执行上述操作,则上述操作将失败。然后你可以用以下方法解决这个问题:

while 
  if [ file.log -ef /dev/stdin ] || ! command exec 3< file.log; then
    your-filter
  else
    (cat; cat <&3) | your-filter &&
      exec <&3 3<&-
  fi
do
  sleep 60
done < file.log

因此它会继续读取旧文件,直到新文件出现。

command需要避免exec导致 shell 在失败时退出(如 POSIX 要求)。在模式下zshbash不在模式下时不需要它sh

现在,我们在循环中休眠 60 秒,your-filter可能需要几秒钟才能运行。如果your-filter平均每分钟运行一次很重要,使用kshbashzsh,您可以将其更改为:

t=$SECONDS
while 
  if [ file.log -ef /dev/stdin ] || ! command exec 3< file.log; then
    your-filter
  else
    (cat; cat <&3) | your-filter &&
      exec <&3 3<&-
  fi
do
  t=$(($t + 60))
  sleep "$((t - SECONDS))"
done < file.log

使用ksh93zsh,并且如果您sleep接受浮点参数,您可以运行typeset -F SECONDS.

相关内容