150分相送,请问如何截断一个log文件前面一半,谁有效率高的好办法!!!

时间:2022-10-03 14:43:24
syslo*生的log文件,现在我要做的是在这个log文件的大小超过2M的时候将文件前面1M去掉,并且要恰好截到一条日志结束的位置,不然读取就有问题了。

在这个过程中还要允许日志继续往里面写,不然新的日志会丢失。

请问有什么好的方法,效率高的方法!

18 个解决方案

#1


可以用logrotate或者类似的工具.
logrotate是一个log维护工具, 当你的log太大的时候, 可以自动压缩备份并清空当前log文件.
也许这个功能就能满足你的需求, 但是如果它的功能不只于此, 实际上它是一个cron, 也就是定期执行的程序, 你可以修改它的配置文件来调用你自己的文件.

配置文件在/etc/logrotate.conf和/etc/logrotate.d/*
比如说对/var/log/messages的配置是
       /var/log/messages {
           rotate 5
           weekly
           postrotate
                                     /sbin/killall -HUP syslogd
           endscript
       }

#2


再比如:
       "/var/log/httpd/access.log" /var/log/httpd/error.log {
           rotate 5
           size=100k
           sharedscripts
           postrotate
                                     /sbin/killall -HUP httpd
           endscript
       }
意思是最多生成5个log文件(/var/log/httpd/access.log.*)
当前文件最大100k, 超过100k就清空并备份成/var/log/httpd/access.log.1
备份后发HUP信号给httpd重起

#3


sed '1,10d' filename
可以简单的删除文件的前10行

如果要实现同时还要写log,你可以自己写程序,
1、需要锁定log文件,你的进程在发现log文件被锁时需要等候
2、从log文件尾向前seek 1M,往后搜索'\n',之后的内容读到内存
3、读出的内容写回log文件。为了安全,最好先写临时文件。

#4


截1M,可以考虑下,先在将指针偏移1M,然后利用strstr(p, '\n'),查找出临近的换行符,认为是一条日志的结束,不知道行不。
如果想在截的同时还往里面插,相当于两个进程同时操作一个文件,恐怕会导致不一致。我认为可以考虑分开来,插的时候就不截,截的时候就不插。
在截的过程中加一个写锁,然后在插入中捕捉不能写的错误码,适当延时。
插入的过程中也加一个写锁,类似。

#5


如果限定用文件,我觉得没什么好办法。插入记录的是syslogd,它是否会管文件锁?如果设置为强制锁,syslogd会怎么反应?所有这些问题都与syslogd的实现有关。
一个办法是象syslog现在的实现,改名(移动)文件。不知道楼主的要求为什么还要保留1M,不需要那么复杂吧。
另一个办法是用Named Pipe,让syslogd往里写,自己写个进程往外读,愿意怎么样就怎么样。

#6


保留1M是要日志文件不至于一下子就没有了,因为在网络大流量的情况下,2M很快就满了,如果以下就没有用户会感觉很奇怪。

可以考虑修改syslogd的实现,还没有看代码,不太清楚具体怎么做的。

#7


提个思路不知道正确不很久不在linux下写程序了!


在知道文件的大小的情况下,通过设置偏移将文件的指针直接定位到你想要的位置(一半,1M),然后顺序查找到你文件中下一记录的开始位置,前面部分扔掉就可以了,不知道可行不?欢迎斧正!

#8


楼上的,思路是对的

但是有时候实现和思路不能百分百的相同。

#9


想来想去,还是用管道更安全方便。

#10


想来想去,还是用管道更安全方便。


管道怎么做,版主给个思路。

#11


???
“另一个办法是用Named Pipe,让syslogd往里写,自己写个进程往外读,愿意怎么样就怎么样。”
在syslogd.conf里配置就可以让syslogd写往mkfifo创建的管道。你的应用打开管道读就行了。

#12


[在这个过程中还要允许日志继续往里面写,不然新的日志会丢失。]

不知道该怎么实现这个功能,对文件进行操作的时候还有允许别的进程写文件。
如果你对文件进行加锁,那么别的进程写文件就会失败,除非程序中判断加锁就等待。

搂主的这种功能通常都是在程序里面做的,现在要拿到外面作,我觉得有点不太现实吧。
两个不相关的进程能同时操作文件?读可以,要写就麻烦了吧!

我思路都没有,各位有什么好的意见。

#13


有一个肯定保险的办法, 不过理论上可行,实际上没什么实用性:

开一块共享内存用于写log, 在来一个进程刷新log.

按照这个思路也可以用一个文件代替共享内存.

还有一种想法, 可以将log文件复制一份进行处理, 处理完后发信号给你的程序, 程序自己去合并日志.

再一种办法, 假设程序里只有一个地方写日志(如果有多个线程或进程写,就加上进程同步), 那么日志截短处理就在写日志的时候做好了, 2M的文件也不会太慢.

#14


可以将log文件复制一份进行处理, 处理完后发信号给你的程序, 程序自己去合并日志.
这个办法我觉的可以,就是不知道你的log写的频率有多高

#15


这个日志文件记录所有防火墙数据包所过的规则的信息,在测评防火墙的时候可能测试发送10000个包,看看你的日志是否有10000条记录之类的项目,所以日志信息最好不能丢。

#16


那么我觉的x86的第二个方法是可以的
首先数据量还好,不是特别大
其次,频率高了点,要想不丢日志,就得快,或者用备份来做

#17


谢谢大家的回复,问题解决了,借鉴了Oracle写日志的方式,我现在用两个文件记录日志,当一个文件超过1M,就拷贝为另一个文件,然后清空继续写。

做法很简单,就是修改了写日志程序,用一个10多行的程序就搞定了,而且不会丢掉日志。

/**
 * when fw.log size > 1M, cp fw.log to fw.log.old and zero fw.log
 */
static int
truncate_log(void)
{
struct stat statebuf;
char cmdbuf[100];

if (stat(fwlog_file, &statebuf) < 0) {
/* can't stat fw.log */
return -1;
}

if ((unsigned int)statebuf.st_size > max_log_size) {
sprintf(cmdbuf, "cp %s %s", fwlog_file, fwlogold_file);
system(cmdbuf);

/* zero fw.log size */
truncate(fwlog_file, 0);
}

return 0;
}

#18


自己写还是syslog写?我怎么越看越糊涂?

#1


可以用logrotate或者类似的工具.
logrotate是一个log维护工具, 当你的log太大的时候, 可以自动压缩备份并清空当前log文件.
也许这个功能就能满足你的需求, 但是如果它的功能不只于此, 实际上它是一个cron, 也就是定期执行的程序, 你可以修改它的配置文件来调用你自己的文件.

配置文件在/etc/logrotate.conf和/etc/logrotate.d/*
比如说对/var/log/messages的配置是
       /var/log/messages {
           rotate 5
           weekly
           postrotate
                                     /sbin/killall -HUP syslogd
           endscript
       }

#2


再比如:
       "/var/log/httpd/access.log" /var/log/httpd/error.log {
           rotate 5
           size=100k
           sharedscripts
           postrotate
                                     /sbin/killall -HUP httpd
           endscript
       }
意思是最多生成5个log文件(/var/log/httpd/access.log.*)
当前文件最大100k, 超过100k就清空并备份成/var/log/httpd/access.log.1
备份后发HUP信号给httpd重起

#3


sed '1,10d' filename
可以简单的删除文件的前10行

如果要实现同时还要写log,你可以自己写程序,
1、需要锁定log文件,你的进程在发现log文件被锁时需要等候
2、从log文件尾向前seek 1M,往后搜索'\n',之后的内容读到内存
3、读出的内容写回log文件。为了安全,最好先写临时文件。

#4


截1M,可以考虑下,先在将指针偏移1M,然后利用strstr(p, '\n'),查找出临近的换行符,认为是一条日志的结束,不知道行不。
如果想在截的同时还往里面插,相当于两个进程同时操作一个文件,恐怕会导致不一致。我认为可以考虑分开来,插的时候就不截,截的时候就不插。
在截的过程中加一个写锁,然后在插入中捕捉不能写的错误码,适当延时。
插入的过程中也加一个写锁,类似。

#5


如果限定用文件,我觉得没什么好办法。插入记录的是syslogd,它是否会管文件锁?如果设置为强制锁,syslogd会怎么反应?所有这些问题都与syslogd的实现有关。
一个办法是象syslog现在的实现,改名(移动)文件。不知道楼主的要求为什么还要保留1M,不需要那么复杂吧。
另一个办法是用Named Pipe,让syslogd往里写,自己写个进程往外读,愿意怎么样就怎么样。

#6


保留1M是要日志文件不至于一下子就没有了,因为在网络大流量的情况下,2M很快就满了,如果以下就没有用户会感觉很奇怪。

可以考虑修改syslogd的实现,还没有看代码,不太清楚具体怎么做的。

#7


提个思路不知道正确不很久不在linux下写程序了!


在知道文件的大小的情况下,通过设置偏移将文件的指针直接定位到你想要的位置(一半,1M),然后顺序查找到你文件中下一记录的开始位置,前面部分扔掉就可以了,不知道可行不?欢迎斧正!

#8


楼上的,思路是对的

但是有时候实现和思路不能百分百的相同。

#9


想来想去,还是用管道更安全方便。

#10


想来想去,还是用管道更安全方便。


管道怎么做,版主给个思路。

#11


???
“另一个办法是用Named Pipe,让syslogd往里写,自己写个进程往外读,愿意怎么样就怎么样。”
在syslogd.conf里配置就可以让syslogd写往mkfifo创建的管道。你的应用打开管道读就行了。

#12


[在这个过程中还要允许日志继续往里面写,不然新的日志会丢失。]

不知道该怎么实现这个功能,对文件进行操作的时候还有允许别的进程写文件。
如果你对文件进行加锁,那么别的进程写文件就会失败,除非程序中判断加锁就等待。

搂主的这种功能通常都是在程序里面做的,现在要拿到外面作,我觉得有点不太现实吧。
两个不相关的进程能同时操作文件?读可以,要写就麻烦了吧!

我思路都没有,各位有什么好的意见。

#13


有一个肯定保险的办法, 不过理论上可行,实际上没什么实用性:

开一块共享内存用于写log, 在来一个进程刷新log.

按照这个思路也可以用一个文件代替共享内存.

还有一种想法, 可以将log文件复制一份进行处理, 处理完后发信号给你的程序, 程序自己去合并日志.

再一种办法, 假设程序里只有一个地方写日志(如果有多个线程或进程写,就加上进程同步), 那么日志截短处理就在写日志的时候做好了, 2M的文件也不会太慢.

#14


可以将log文件复制一份进行处理, 处理完后发信号给你的程序, 程序自己去合并日志.
这个办法我觉的可以,就是不知道你的log写的频率有多高

#15


这个日志文件记录所有防火墙数据包所过的规则的信息,在测评防火墙的时候可能测试发送10000个包,看看你的日志是否有10000条记录之类的项目,所以日志信息最好不能丢。

#16


那么我觉的x86的第二个方法是可以的
首先数据量还好,不是特别大
其次,频率高了点,要想不丢日志,就得快,或者用备份来做

#17


谢谢大家的回复,问题解决了,借鉴了Oracle写日志的方式,我现在用两个文件记录日志,当一个文件超过1M,就拷贝为另一个文件,然后清空继续写。

做法很简单,就是修改了写日志程序,用一个10多行的程序就搞定了,而且不会丢掉日志。

/**
 * when fw.log size > 1M, cp fw.log to fw.log.old and zero fw.log
 */
static int
truncate_log(void)
{
struct stat statebuf;
char cmdbuf[100];

if (stat(fwlog_file, &statebuf) < 0) {
/* can't stat fw.log */
return -1;
}

if ((unsigned int)statebuf.st_size > max_log_size) {
sprintf(cmdbuf, "cp %s %s", fwlog_file, fwlogold_file);
system(cmdbuf);

/* zero fw.log size */
truncate(fwlog_file, 0);
}

return 0;
}

#18


自己写还是syslog写?我怎么越看越糊涂?