因为一个异常没有及时处理,日志疯长到50G… 刚才已经说了,这是异常日志,所以关于日志的内容也都是没用的。
日志这么大怎么处理? 可以使用logrotate来管理,logrotate是个基于crontab实现的日志管理,可以切割删除日志,设置压缩及备份个数。
程序本身是python写的,日志模块肯定是标准库logging,logging其实自带了日志文件的切割功能。 上次有朋友问我,Django关于logging的配置,我强烈推荐他用logrotate,虽然那是基于系统的,又需要相应的sudo权限。
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。
那么我为什么推荐他使用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.