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)对其进行改进,欢迎提交拉取请求。
开个玩笑,这是我的第一个“只写”保险丝驱动程序! :-)
我正在尝试提出一个 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)对其进行改进,欢迎提交拉取请求。
开个玩笑,这是我的第一个“只写”保险丝驱动程序! :-)