从活动的日志文件中删除前N行


Answers:


10

不,像Linux这样的操作系统及其文件系统,没有为从文件开头删除数据做好准备。换句话说,文件存储的起点是固定的。

通常通过将剩余数据写入新文件并删除旧文件来完成从文件开头删除行的操作。如果程序打开了要写入的旧文件,则该文件的删除将推迟到应用程序关闭该文件为止。


正如评论者所指出的那样,由于我上一句话中提到的原因,您通常需要将日志文件修剪与正在编写日志的程序进行协调。确切的操作方式取决于程序。当您向它们发送信号(例如HUP)时,某些程序将关闭并重新打开其日志文件,这可用于防止将日志记录写入“已删除”日志文件,而不会中断服务。

有许多实用程序可用于管理日志文件的大小,例如logrotate

一些程序具有自己的实用程序。例如,Apache Web服务器包含一个rotatelogs实用程序。


3
但是,当某些东西仍然具有打开的文件并仍附加到文件时,您不应该这样做,因为它将写入现在已删除的文件,并且您会丢失这些日志消息。
TarnayKálmán2012年

真正。即使您使用了相同的文件名。
Hennes

太糟糕了,操作系统不允许您这样做,对于原木旋转器来说,不必在旋转后重新加载进程会很方便:
rogerdpack '16

25

我认为这个任务可以通过 sed

sed -i '1,10d' myfile

将消除从1行第一至10 线形式的文件。

我认为每个人至少应该看看sed 1衬板

请注意,这不适用于应用程序正在主动附加的日志文件(如问题中所述)。

sed -i将创建一个新文件并“删除”正在写入的文件。大多数应用程序将继续将日志记录写入已删除的日志文件,并将继续填充磁盘空间。新的,被截断的日志文件将不会附加到该文件。仅当应用程序重新启动或以其他方式发出关闭并重新打开其日志文件的信号时,此操作才会停止。如果在使用sed和应用程序重新启动之间进行了任何可记录的活动,则新日志文件中将存在一个间隙(缺少日志记录)。

一种安全的方法是停止应用程序,使用sed截断日志,然后重新启动应用程序。对于某些服务(例如,具有高吞吐量和高服务连续性要求的Web服务器),这种方法可能是不可接受的


2
您知道要追加的应用程序发生什么情况吗?
亚当·马坦

1
让我们假设一个普通的打开文件处理程序,该处理程序附加行并不时刷新。
亚当·马坦

1
我知道我围绕sed的方式,并且将行提取到新文件中对sed来说毫无疑问。问题在于将它们全部保存在同一文件中。
亚当·马坦

10
不,这不起作用。 使用已编辑的内容sed -i创建一个新文件,并且删除了旧文件,因此您不编辑活动文件:$ ls -i --- 6823554 testfile --- $ sed -i 's/test/final/' testfile --- $ ls -i --- 6823560 testfile------请检查其sed -i工作方式。为什么这个错误的答案会有这么多的反对?
pabouk

1
问题指出“来自应用程序正在主动添加的日志”。操作词是“积极”。也许在您的答案出现后才进行了澄清。但就目前情况而言,倾向于“最多票”的读者将产生误导。我只能选票一次。
Scott Prive


2

这是一个答案,而不是解决方案。这个问题没有解决方案。询问者清楚地指出:“从应用程序正在主动添加的日志中”。 您可以继续阅读以了解更多信息,并根据我的推测跳过最后的建议,以使我理解为什么此代码未遵循最佳实践。

需要明确的是:此处的其他“答案”提供了虚假的承诺。重命名不会欺骗应用程序使用新文件。在对这些错误答案的评论中掩藏了最有用的信息。

活动文件不是您只是将数据放入其中的某种容器。文件名指向一个inode(文件的开始),每个inode都有一个指向另一个inode的指针(如果有更多数据)。这意味着一个连续写入的文件中将添加一个恒定的inode流,并且您对“文件”的想法实际上是inode的日志序列。

想象一下,您正在跟踪Google Maps上的某个人,并且该人可以随时随地传送到世界任何地方,并且您试图连接这些点。

Linux工具“截断”可以通过简单地遍历inode树来丢弃文件末尾的数据,并且(在您指定的位置/大小处)它将丢弃堆栈中的所有后续指针。进行相反的操作(在文件开头丢弃数据)将是一个极其复杂且冒险的过程,需要实时重写inode树,没人会为公众编写此类工具,因为它们经常会失败并导致数据丢失。该索引节点维基是短暂的,但解释了这些概念。

**我的建议:解决此问题-为什么此应用程序会以这种方式运行?有许多日志记录最佳实践,但是通常它们与您的日志记录系统(syslog等)实际联系在一起。从根本上讲,应用程序应该“释放”它对文件的处理,因此logrotate(等)可以处理旧数据的进一步处理。

每当我听到“发送到活动日志文件”时,我都会立即要求该人告诉我此应用程序背后的“特殊故事”。通常是“开发人员退出,我们无法更改代码。这实际上是安全性的倒退,它有其自身的一系列风险。但是我得到您想要一种避免接触源代码的解决方案。如果这是情况下,需要一个更具体的问题。



-1

也许复制,截断,拖尾复制到size = 0截断,然后删除副本?

更好的是从尾部到尾部复制,截断原件,将concat尾部复制到原件上。

您会在日志中找到尾部长度的行,因此比字节长度限制更好。

修改评论的详细信息:

首先,您可以使用Python3中的记录器脚本

from time import sleep

idx = 0
while 1 == 1:
    idx = (idx + 1)
    lf = open('tailTrunc.log', 'a')
    lf.write("line to file " + str(idx) + '\n')
    lf.close()
    sleep(0.01)

然后我们有截断器

#!/usr/bin/env bash

trap "kill 0" EXIT

rm tailTrunc.log
touch tailTrunc.log

python3 logLoop.py &
loggerPID=$!
sleep 1

kill -STOP $loggerPID
tail -10 tailTrunc.log > trimEnd.log
truncate -s 0 tailTrunc.log
kill -CONT $loggerPID
sleep 1

trimEnd.log显示80到89

日志显示90结束

无论如何,有志者事竟成。

合并器的许多更复杂的示例以及写流的打开或关闭方式可能需要针对每个cpu内核进行调整,等等。如果可以在记录器中记录日志过程等,只需暂停写入并排队。


“从应用程序正在主动附加的日志中”。您的解决方案忽略的问题是应用程序正在“永久”使用日志文件-意味着日志文件的inode仍在播放。您的解决方案会“备份”日志文件数据,该数据可能在此问题之外有用途。
Scott Prive

感谢您的评论和不赞成投票?我已经修改了一个简单而廉价的例子,作为考虑因素,您必须更深入地考虑自己的处境,但是只要有意愿,就有办法。
詹姆斯大师

别以为这是我的不赞成票,但我想这是在其他答案的评论中所碰到的:如果您复制日志文件,那么它将不再是活动日志文件……无论您做什么。应用程序的文件句柄将始终指向原始日志文件的索引节点。可以这样想:您有一个使用非标准日志记录功能的应用程序,并不断向已打开的文件中添加字节。
Scott Prive

1
对不起,我推断。是的,inode需要保持不变,这就是给出的示例/证明使用截断的原因,并且它再次取决于情况(所有选项显然都隐藏在纯站点中)。
詹姆斯大师
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.