我正在寻找一种相当简单的方法(不涉及开发——我可以用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,比如posh
as-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 要求)。在模式下zsh
或bash
不在模式下时不需要它sh
。
现在,我们在循环中休眠 60 秒,your-filter
可能需要几秒钟才能运行。如果your-filter
平均每分钟运行一次很重要,使用ksh
、bash
或zsh
,您可以将其更改为:
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
使用ksh93
和zsh
,并且如果您sleep
接受浮点参数,您可以运行typeset -F SECONDS
.