【问题标题】:Limit Python log file限制 Python 日志文件
【发布时间】:2014-08-01 04:15:26
【问题描述】:

我正在使用 Python3 (Ubuntu 14.04) 写出一个日志文件。我想限制日志文件的大小,所以选择了RotatingFileHandler。此外,我不想轮换日志文件(.log 变为 .log.1 等等) - 我只想限制日志文件的大小。

我试过像这样使用RotatingFileHandler

filehandler = logging.handlers.RotatingFileHandler( "app.log", "a", 1000, 0, None, True )
logging.basicConfig( format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s", level = logging.DEBUG, handlers = [ filehandler ] )

我发现日志文件继续增长,并且永远不会被截断或“包装”到极限。

我原以为设置backupCount = 0会导致在写入之前检查日志文件大小,如果有空间容纳日志消息,则写入它,否则清空文件并写出消息。

有什么想法吗?

提前致谢,

伯恩迈斯特。

【问题讨论】:

    标签: logging python-3.x


    【解决方案1】:

    如果您查看source code of the RotatingFileHandler,您会看到backupCount 0 刚刚关闭然后重新打开日志的流。这是一个修改后的版本,可以满足您的要求,丢弃旧文件:

    import os
    import logging
    import logging.handlers
    
    
    class TruncatedFileHandler(logging.handlers.RotatingFileHandler):
        def __init__(self, filename, mode='a', maxBytes=0, encoding=None, delay=0):
            super(TruncatedFileHandler, self).__init__(
                filename, mode, maxBytes, 0, encoding, delay)
    
        def doRollover(self):
            """Truncate the file"""
            if self.stream:
                self.stream.close()
            dfn = self.baseFilename + ".1"
            if os.path.exists(dfn):
                os.remove(dfn)
            os.rename(self.baseFilename, dfn)
            os.remove(dfn)
            self.mode = 'w'
            self.stream = self._open()
    

    这里是如何使用它:

    filehandler = TruncatedFileHandler("app.log", "w", 1000)
    logging.basicConfig(
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        level=logging.DEBUG, handlers=[filehandler])
    
    logger = logging.getLogger('spam_application')
    
    for i in range(100):
        logger.debug("a log line, number: %s", i)
    

    并证明它有效

    ❯❯❯ python3.4 main.py
    ❯❯❯ cat app.log*
    2014-06-11 11:50:44,871 - spam_application - DEBUG - a log line, number: 91
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 92
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 93
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 94
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 95
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 96
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 97
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 98
    2014-06-11 11:50:44,872 - spam_application - DEBUG - a log line, number: 99
    

    【讨论】:

    • @Bernmeister:请注意,此解决方案在翻转时完全删除旧日志。可能很容易只丢弃其中的一部分并继续附加,但我没有时间研究这个......
    • doRollover(),你为什么要删除文件self.baseFilename + ".1"...我看不到除了self.baseFilename之外的任何文件?
    • @Bernmeister:我留下这些语句是因为,如果在os.renameos.remove 语句之间停止记录器(例如,因为解释器崩溃),那么可能存在剩余文件。但我认为您的回答是正确的:只需删除 baseFilename 即可。
    【解决方案2】:

    受logc的回答启发,我采取了更野蛮的做法:我只是删除了日志文件。

    class TruncatedFileHandler( logging.handlers.RotatingFileHandler ):
        def __init__( self, filename, mode = "a", maxBytes = 0, encoding = None, delay = 0 ):
            super( TruncatedFileHandler, self ).__init__( filename, mode, maxBytes, 0, encoding, delay )
    
    
        def doRollover( self ):
            if self.stream: self.stream.close()
    
            if os.path.exists( self.baseFilename ): os.remove( self.baseFilename )
    
            self.mode = "a" # Not sure why but "w" behaves in the same way as "a".
            self.stream = self._open()
    

    我在我的解决方案和 logc 的解决方案中发现的一点是,一旦调用了 doRollover(),设置 self.mode="a"self.mode="w" 在写入文件方面没有任何区别。也就是说,我希望“w”每次都从文件的开头开始写入,但事实并非如此(它的行为方式与“a”相同,并从它最后写入的位置开始写入)。

    【讨论】:

    • 只是一个小注释:"a" 的行为与"w" 相同,因为如果文件不存在——而您刚刚删除了它——,附加到文件与写入文件。在原始代码中,我认为它们更改为“w”(从“a”)以确保在将所有其他文件滚动到其他名称后从头开始创建
    猜你喜欢
    • 1970-01-01
    • 2012-07-22
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 2014-07-27
    相关资源
    最近更新 更多