聊聊logging的RotatingFileHandler切割日志

因为一个异常没有及时处理,日志疯长到50G… 刚才已经说了,这是异常日志,所以关于日志的内容也都是没用的。
日志这么大怎么处理? 可以使用logrotate来管理,logrotate是个基于crontab实现的日志管理,可以切割删除日志,设置压缩及备份个数。 

程序本身是python写的,日志模块肯定是标准库logging,logging其实自带了日志文件的切割功能。   上次有朋友问我,Django关于logging的配置,我强烈推荐他用logrotate,虽然那是基于系统的,又需要相应的sudo权限。 

该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。

http://xiaorui.cc/?p=3114

那么我为什么推荐他使用logrotate,而不是django框架自带内置的日志管理模块. 

原因如下,我们使用RotatingFileHandler创建了一个handler,他的参数是日志文件,单个文件日志的字节大小,备份个数.  

他的实现原理也很是粗暴,有意思 。每次写入日志都会open,然后取出 tell(),人话就是拿到字节大小,每次写入都要针对日志都要len(msg)判断,如果符合超过maxbytes字节大小,那么开始切割日志. 

tell():  文件的当前位置,即tell是获得文件指针位置

logging的RotatingFileHandler我们可以稍微扩展一下,牺牲一些日志切割的准确性,来更省资源的管理这日志。 在继承BaseRotatingHandler类的时候,我们可以放一个线程,慢慢的来判断日志文件,不用每次都去判断…

另外在stackoverflow里看到不少老外跟我的想法是如出一辙…  看来还算时尚.  如果在multiprocessing多进程下使用logging RotatingFileHandler,会出现一些问题,但这问题发生的边界还是会有的 ! 有 A B 两个进程,当A和B都获取了文件,但A切割并写入日志,但B这时候会出问题的.

说明下logging对于多线程是数据安全的,但对于多进程那就不是数据安全了,只是很少有人注意到而已.

#xiaorui.cc
class RotatingFileHandler(BaseRotatingHandler):
   def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0):
       if maxBytes > 0:
           mode = 'a'
       BaseRotatingHandler.__init__(self, filename, mode, encoding, delay)
       self.maxBytes = maxBytes
       self.backupCount = backupCount

    def doRollover(self):
        if self.stream:
            self.stream.close()
            self.stream = None
        if self.backupCount > 0:
            for i in range(self.backupCount - 1, 0, -1):
                sfn = "%s.%d" % (self.baseFilename, i)
                dfn = "%s.%d" % (self.baseFilename, i + 1)
                if os.path.exists(sfn):
                    #print "%s -> %s" % (sfn, dfn)
                    if os.path.exists(dfn):
                        os.remove(dfn)
                    os.rename(sfn, dfn)
            dfn = self.baseFilename + ".1"
            if os.path.exists(dfn):
                os.remove(dfn)
            # Issue 18940: A file may not have been created if delay is True.
            if os.path.exists(self.baseFilename):
                os.rename(self.baseFilename, dfn)
        if not self.delay:
            self.stream = self._open()

    def shouldRollover(self, record):

        if self.stream is None:                 # delay was set...
            self.stream = self._open()
        if self.maxBytes > 0:                   # are we rolling over?
            msg = "%s\n" % self.format(record)
            self.stream.seek(0, 2)  #due to non-posix-compliant Windows feature
            if self.stream.tell() + len(msg) >= self.maxBytes:
                return 1
        return 0


在github中看到一哥们说是实现了进程的日志安全写入,看了下源码甚是简单,用multiprocessing queue实现队列,然后logging.info(msg)来推送日志到queue队列里面…


END.


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

发表评论

邮箱地址不会被公开。 必填项已用*标注