unix 上的环形缓冲区日志文件

Ring buffer log file on unix

我正在尝试提出一个 unix 命令管道,它允许我仅将程序输出的最新 n 行记录到文本文件中。

文本文件的长度不应超过 n 行。 (第一次填文件的时候可能会少)

在有限 memory/resources 的设备上它将是 运行,因此优先考虑保持文件大小较小。

我试过这样的东西 (n=500):

program_spitting_out_text > output.txt
cat output.txt | tail -500 > recent_output.txt
rm output.txt

program_spitting_out_text | tee output.txt | tail -500 > recent_output.txt

显然这两个都不适合我的目的...

有没有人有一个很好的方法在一行中做到这一点?或者我必须写一个 script/utility?

注意:我不想与 dmesg 有任何关系,必须使用标准 BSD unix 命令。 "program_spitting_out_text" 每秒打印出大约 60 lines/second。

提前致谢!

如果 program_spitting_out_text 连续运行并保持其文件打开,您无能为力。

即使删除文件也无济于事,因为它仍会继续写入现在的 "hidden" 文件(数据仍然存在,但没有目录条目)直到关闭它,此时它将真正被删除。


如果它定期关闭并重新打开日志文件(每行或每十秒或其他),那么您有一个相对简单的选择。

简单地监视文件直到它达到一定大小,然后滚动文件,比如:

while true; do
    sleep 5
    lines=$(wc -l <file.log)
    if [[ $lines -ge 5000 ]]; then
        rm -f file2.log
        mv file.log file2.log
        touch file.log
    fi
done

此脚本将每五秒检查一次文件,如果超过 5000 行,会将其移至备份文件。写入它的程序将继续写入该备份文件(因为它有打开的句柄)直到它关闭它,然后它将重新打开新文件。

这意味着您在日志文件集中总是(大约)有五到一万行,您可以使用结合这两者的命令搜索它们:

grep ERROR file2.log file.log

另一种可能性是,如果您可以在不影响其功能的情况下定期重启该程序。例如,一个程序每秒查找一次文件是否存在并报告该文件,可能可以毫无问题地重新启动。将 PI 计算到 1000 亿有效数字可能 not 可以在没有影响的情况下重新启动。

如果它可重启的,那么您基本上可以使用与上述相同的技巧。当日志文件达到一定大小时,终止当前程序(您将作为脚本的后台任务启动该程序),执行滚动日志文件所需的任何魔法,然后重新启动程序。

例如,考虑以下(可重新启动的)程序 prog.sh,它只是连续输出当前日期和时间:

#!/usr/bin/bash
while true; do
    date
done

然后,以下脚本将负责根据需要启动和停止其他脚本,方法是每五秒检查一次日志文件,看它是否超出限制:

#!/usr/bin/bash

exe=./prog.sh
log1=prog.log
maxsz=500

pid=-1
touch ${log1}
log2=${log1}-prev

while true; do
    if [[ ${pid} -eq -1 ]]; then
        lines=${maxsz}
    else
        lines=$(wc -l <${log1})
    fi
    if [[ ${lines} -ge ${maxsz} ]]; then
        if [[ $pid -ge 0 ]]; then
            kill $pid >/dev/null 2>&1
        fi
        sleep 1
        rm -f ${log2}
        mv ${log1} ${log2}
        touch ${log1}
        ${exe} >> ${log1} &
        pid=$!
    fi
    sleep 5
done

并且此输出(来自两个日志文件的每秒 wc -l)显示了切换时发生的情况,请注意,由于切换涉及的延迟,它只是近似值:

474 prog.log       0 prog.log-prev
496 prog.log       0 prog.log-prev
518 prog.log       0 prog.log-prev
539 prog.log       0 prog.log-prev
542 prog.log       0 prog.log-prev
 21 prog.log     542 prog.log-prev

请记住,这是一个示例脚本。它 相对 智能,但可能需要一些错误处理,以便它不会在您关闭监视器时留下可执行文件 运行。


最后,如果 none 就足够了,没有什么可以阻止您编写自己的 过滤器程序,该程序接受标准输入并不断将其输出到真实的环形缓冲区文件。

那么你只需要做:

program_spitting_out_text | ringbuffer 4096 last4k.log

该程序可能是一个真正的环形缓冲区,因为它将 4k 文件视为一个循环字符缓冲区,但是,当然,您需要在文件中使用一个特殊的标记来指示写入点,以及一个可以将其转回真实流的程序。

或者,它可以执行与上述脚本相同的操作,重写文件,使其始终低于所需大小。

由于 GNU/Linux 上显然不存在此基本功能(循环文件),并且因为我需要它来跟踪存储空间有限的 Raspberry Pi 上的日志,所以我只是按照建议编写了代码以上!

看:circFS

与此 post 和其他类似工具中引用的其他工具不同,最大大小是任意的,仅受实际可用存储空间的限制。 它不与多个文件一起旋转,所有文件都保存在单个文件中,该文件在“发布”时被重写。 您可以根据需要在虚拟目录中拥有任意数量的日志文件。

它是单个 C 文件(约 600 行,包括注释),并且在安装 fuse 开发依赖项后使用单个编译行构建。

第一个版本非常基础(参见 README),如果您想通过一些 TODO(参见 TODO)对其进行改进,欢迎提交拉取请求。

开个玩笑,这是我的第一个“只写”保险丝驱动程序! :-)