- 任何可以监视日志文件的工具,一旦它达到最大值,就从开头开始截断文件内容,这样应用程序就可以继续在结尾附加内容。
- 任何可以在创建文件时指定其最大大小的工具,当文件达到该最大值时,它将不再增长。
- 设置计划任务或脚本以在一定时间间隔(例如1小时)后监视文件大小,然后在那个时间删除其内容。
作为一个shell脚本:
file=file_to_watch
maxsize=98765
truncsice=8765
while : ; do
inotifywait -e modify "$file"
filesize=$(du "$file")
if [ $filesize -gt $maxsize ] ; then
tail -c $truncsize "$file" > /tmp/truncatedfile.$$
mv /tmp/truncatedfile.$$ "$file"
fi
done
你觉得使用 truncate -s 10M log.txt
怎么样?
更多细节请查看 man truncate
truncate -s \
sed 1,10000 log.txt | wc -c` log.txt`。 - Alexis Wilke几乎没有任何系统提供删除文件的一部分并允许您附加更多数据的过程,即使这是可能的,也不是人们经常做的事情。它可以在内核级别完成,并且非常高效,但我从未见过这样的操作。(即内核将简单地取消链接文件开始处的inode,并在文件的第一个inode中具有字节能力的偏移量--而不是页面能力。)
在Unix系统上,您可以使用mmap()
和unmap()
来实现此目的。因此,当您的应用程序确定文件大小超过某个特定值时,它必须从文件开头读取,确定例如日志的第10,000行的位置,然后将其余部分memmove()
到开头。最后,它会截断文件并以追加模式重新打开它。这最后一步非常重要...
// WARNING: code without any error checking
// if multiple processes may run in parallel, make sure to use a lock as well
int fd = open("/var/log/mylog.log", O_RDWR);
ssize_t size = lseek(fd.get(), 0, SEEK_END);
lseek(fd.get(), 0, SEEK_SET);
char * start = (char *)mmap(nullptr,
size,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd,
0);
char * end = start + size;
char * l10000 = start; // search line 10,000
for(int line(0); line < 10000; ++line)
{
for(; l10000 < end && *l10000 != '\n'; ++l10000);
if(*l10000 == '\n')
{
++l10000; // skip the '\n'
}
}
ssize_t new_size = end - l10000;
memmove(start, l10000, new_size);
truncate(fd, new_size);
close(fd);
在GitHub上找到的示例(包括此处未找到的所有错误检查):sendmail::dequeue()
重要提示:调用memmove()
会很慢,特别是在一个相当大的日志文件上。
请注意,大多数情况下,当进程打开一个日志文件时,它会保持打开状态,这意味着在其脚下更改文件不会有太大好处。实际上,在这里的mmap()
示例中,如果您不确保关闭并重新打开日志文件(代码中未显示),则会创建许多零(\0
字符)之间的间隙。
因此,这在代码中是可行的(在C++中,您可以轻松将其编译为C)。但是,如果您只想使用bash
,那么logrotate
肯定是您最好的选择。但是,默认情况下,至少在Ubuntu上,logrotate
每天只运行一次。您可以针对使用您的应用程序或系统的用户更改该设置。
你至少可以通过移动或复制logrotate
脚本来每小时运行它:
sudo cp /etc/cron.daily/logrotate /etc/cron.hourly/logrotate
您还可以设置每分钟运行该脚本的CRON文件。要编辑根crontab
文件:
sudo crontab -u root -e
然后添加一行:
* * * * * root /etc/cron.daily/logrotate
确保测试并查看它是否按预期工作。如果您添加了这样的内容,还可以从中删除/etc/cron.daily/logrotate
脚本,以便它不会尝试两次运行(一次在“每日”运行中,一次在每分钟运行中)。
请注意,CRON中存在一个悬而未决的错误,如我向Ubuntu提交的错误报告所示。当过度使用CRON(例如每分钟一次)时,它可能会导致内存问题。
此外,如上面的代码示例中所述,您必须重新打开日志文件。仅进行旋转是没有用的,除非应用程序每次要写入文件时都重新打开日志文件,或者被告知进行旋转(即关闭旧文件并打开新文件)。如果没有旋转操作,应用程序将继续将数据附加到旧文件中,无论它的名称是什么。Unix会记住因为它使用了inode,而不是文件名。 (在MS-Windows下,您将无法重命名文件,而不先关闭对该文件的所有访问...那很烦人!)
在许多情况下,你要么重新启动整个应用程序(因为它太愚蠢而不知道如何重新打开日志),要么向应用程序发送信号以便重新打开日志文件,或者应用程序知道文件已更改,以某种方式...
man logrotate
的翻译:日志轮换管理工具的手册。 - Cyrusman logrotate
是你最有可能从任何人那里得到的答案。 - Niall Cosgrove