【问题标题】:Rotate logfiles each time the application is started (Python)每次启动应用程序时轮换日志文件(Python)
【发布时间】:2011-06-06 23:54:34
【问题描述】:

我在 Python 中使用日志记录模块,我希望它在每次启动我的应用程序时创建一个新的日志文件。应该轮换旧的日志文件(例如:logfile.txt -> logfile1.txt 等)。

我已经找到了:

http://docs.python.org/library/logging.html

BaseRotatingHandler 是基类 对于将日志文件轮换到的处理程序 某一点。这并不意味着 直接实例化。相反,使用 RotatingFileHandler 或 TimedRotatingFileHandler。

RotatingFileHandler 以预定大小进行翻转,而 TimedRotatingFileHandler 根据时间和间隔的乘积进行翻转。两者都不是我想要的,我希望在我的应用程序启动时立即进行轮换。

【问题讨论】:

    标签: python logging rotation


    【解决方案1】:

    我有一个类似的要求,即能够在启动时根据命令行选项强制进行日志轮换,但要让日志文件按其常规时间表进行轮换。这是我的解决方案:

    import logging
    
    from logging.handlers import BaseRotatingHandler
    from typing import Union
    
    def rotate_logs(loggers: Union[str,list]=None, delimiter: str=','):
        """Rotate logs.
    
        Args:
            loggers: List of logger names as list object or as string,
                separated by `delimiter`.
    
            delimiter: Separator for logger names, if `loggers` is :obj:`str`.
                Defaults to ``,`` (comma).
    
        """
    
        # Convert loggers to list.
        if isinstance(loggers, str):
            loggers = [t.strip() for t in loggers.split(delimiter)]
    
        handlers = []
        root = logging.getLogger()
    
        # Include root logger in dict.    
        ld = {'': root, **root.manager.loggerDict}
    
        for k, v in ld.items():
            if loggers is not None and k not in loggers:
                continue
    
            try:
                for h in v.handlers:
                    if (isinstance(h, BaseRotatingHandler) and
                        h not in handlers):
    
                        handlers.append(h)
    
            except AttributeError:
                pass
    
        for h in handlers:
            h.doRollover()
    
    
    
    if __name__ == '__main__':
        pass
    

    注意事项:

    • 如果maxBytes > 0RotatingFileHandler 上,这已经过验证。

    • 此方法尚未使用TimedRotatingFileHandler 进行测试,但应该可以使用。

    • 此方法无需维护对要旋转的RotatingFileHandler 的引用;因此,在使用logging.config 配置日志记录时可以轻松使用它。

    【讨论】:

      【解决方案2】:

      最简单的方法就是在日志文件名中加上一个日期标签,这样每次启动应用时都会得到一个新的日志文件。

      例如

      dateTag = datetime.datetime.now().strftime("%Y-%b-%d_%H-%M-%S")
      logging.basicConfig(filename="myapp_%s.log" % dateTag, level=logging.DEBUG)
      

      所以每次你都会有像myapp_2011-Jan-11_12-27-29.log这样的日志

      另一个好处是,您可以将其与 RotatingFileHandler 混合使用,以便为每个应用调用提供单独的日志,其中每个日志本身进​​一步分为多个固定大小的日志。

      【讨论】:

      • 有没有办法在 logging.conf 文件中给日志文件加上时间戳?
      • 有人试过这个吗?在我的例子中,该文件仅在第一次运行时创建,对于后续运行,相同的文件会被拾取并附加到。
      • @krypto07 我有,直接使用 FileHandler,工作完美。 handler = FileHandler('io-%s.log' % dateTag)
      【解决方案3】:

      在没有maxBytes 的情况下使用RotatingFileHandler 可能就足够了,然后在应用程序启动时调用doRollover()

      是的,似乎工作正常。下面的代码将在每个应用程序运行时创建一个新的日志文件,并为日志开始和关闭时间添加时间戳。运行它将打印可用日志文件的列表。您可以检查它们以检查正确的行为。改编自 Python 文档示例:

      import os
      import glob
      import logging
      import logging.handlers
      import time
      
      LOG_FILENAME = 'logging_rotatingfile_example.out'
      
      # Set up a specific logger with our desired output level
      my_logger = logging.getLogger('MyLogger')
      my_logger.setLevel(logging.DEBUG)
      
      # Check if log exists and should therefore be rolled
      needRoll = os.path.isfile(LOG_FILENAME)
      
      # Add the log message handler to the logger
      handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, backupCount=50)
      
      my_logger.addHandler(handler)
      
      # This is a stale log, so roll it
      if needRoll:    
          # Add timestamp
          my_logger.debug('\n---------\nLog closed on %s.\n---------\n' % time.asctime())
      
          # Roll over on application start
          my_logger.handlers[0].doRollover()
      
      # Add timestamp
      my_logger.debug('\n---------\nLog started on %s.\n---------\n' % time.asctime())
      
      # Log some messages
      for i in xrange(20):
          my_logger.debug('i = %d' % i)
      
      # See what files are created
      logfiles = glob.glob('%s*' % LOG_FILENAME)
      
      print '\n'.join(logfiles)
      

      【讨论】:

      • +1 实用解决方案。不幸的是,这个解决方案需要知道添加了哪些订单处理程序——即 my_logger.handlers[0] 与 my_logger.handlers[n]。有没有一种优雅的方法可以避免对该值进行硬编码?
      • 我很确定你可以调用 handler.doRollover()。换句话说,在某处保持对它的引用。
      【解决方案4】:

      Log Rotation 和 RoatatingFileHandler 通常是在应用程序运行很长时间(几天)并且您希望日志保持轮换时设计和需要的。在我必须在重新启动应用程序时轮换日志的情况下,我必须在 Logfile 处理程序之外执行此操作,这更容易。就像,在第一次调用日志写入器之前,我会查看日志文件是否已经存在,如果存在,则重命名并创建一个新的日志文件。重命名应与处理程序的重命名机制区分开来。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-09
        • 1970-01-01
        • 2014-02-19
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-18
        相关资源
        最近更新 更多