Компактные (архивные) старые файлы журналов в python

Я использую стандартную библиотеку логгеров в Python. Например, есть RotatingFileHandler, который может ежедневно менять файлы журналов.

Но он просто переименовывает их. Будет здорово, если он сможет не только переименовывать, но и складывать старые файлы в zip (или gz, bzip и т.п.) архив.

Есть ли простой способ добиться этого?


person werewindle    schedule 10.08.2011    source источник
comment
подкласс его и реализовать это.   -  person BrainStorm    schedule 10.08.2011


Ответы (3)


Я думаю, что вам лучше всего расширить RotatingFileHandler примерно так (не проверено):

import os
from logging.handlers import RotatingFileHandler


COMPRESSION_SUPPORTED = {}

try:
   import gzip
   COMPRESSION_SUPPORTED['gz'] = gzip
except ImportError:
   pass

try:
   import zipfile
   COMPRESSION_SUPPORTED['zip'] = zipfile
except ImportError:
   pass


class NewRotatingFileHandler(RotatingFileHandler):

     def __init__(self, *args, **kws):
         compress_mode = kws.pop('compress_mode')

         try:
             self.compress_cls = COMPRESSION_SUPPORTED[compress_mode]
         except KeyError:
             raise ValueError('"%s" compression method not supported.' % compress_mode)

         super(NewRotatingFileHandler, self).__init__(self, *args, **kws)

     def doRollover(self):
         super(NewRotatingFileHandler, self).doRollover()

         # Compress the old log.
         old_log = self.baseFilename + ".1"
         with open(old_log) as log:
             with self.compress_cls.open(old_log + '.gz', 'wb') as comp_log:
                 comp_log.writelines(log)

         os.remove(old_log)
person mouad    schedule 10.08.2011
comment
Похоже, ваш метод - лучшее решение на данный момент. Спасибо. - person werewindle; 10.08.2011
comment
что означает ".1"? - person Cacheing; 09.10.2013
comment
@Cacheing см. документы на RotatingFileHandler: если backupCount не -zero, система будет сохранять старые файлы журналов, добавляя расширения «.1», «.2» и т. д. к имени файла. - person dwurf; 24.10.2013
comment
@dwurf Спасибо за ответ на мой вопрос! - person Cacheing; 24.10.2013
comment
это неправильно обрабатывает backupCount > 1, так как сжатые файлы неправильно переименовываются - person Jörn Hees; 26.06.2015
comment
см. stackoverflow.com/a/35547094/107049 для версии, которая обрабатывает backupCount > 1 - person Thomasleveil; 10.03.2016

Принятый ответ заархивирует только 1 файл - (basefile.log.1). Остальные файлы не архивируются. Этот код заархивирует все файлы журналов, кроме базового файла.

import os
import gzip
import logging.handlers

class NewRotatingFileHandler(logging.handlers.RotatingFileHandler):
    def __init__(self, filename, **kws):
        backupCount = kws.get('backupCount', 0)
        self.backup_count = backupCount
        logging.handlers.RotatingFileHandler.__init__(self, filename, **kws)

    def doArchive(self, old_log):
        with open(old_log) as log:
            with gzip.open(old_log + '.gz', 'wb') as comp_log:
                comp_log.writelines(log)
       os.remove(old_log)

   def doRollover(self):
      if self.stream:
          self.stream.close()
          self.stream = None
      if self.backup_count > 0:
          for i in range(self.backup_count - 1, 0, -1):
              sfn = "%s.%d.gz" % (self.baseFilename, i)
              dfn = "%s.%d.gz" % (self.baseFilename, i + 1)
              if os.path.exists(sfn):
                  if os.path.exists(dfn):
                      os.remove(dfn)
                  os.rename(sfn, dfn)
      dfn = self.baseFilename + ".1"
      if os.path.exists(dfn):
          os.remove(dfn)
      if os.path.exists(self.baseFilename):
          os.rename(self.baseFilename, dfn)
          self.doArchive(dfn)
      if not self.delay:
          self.stream = self._open()
person bibinjose    schedule 22.02.2016

Вы можете автоматически записывать сжатые файлы журнала bz2, инициализируя RotatingFileHandler с помощью encoding='bz2-codec':

import logging
import logging.handlers as handlers

if __name__=='__main__':
    log_filename='log_rotate.bz2'
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    handler = handlers.RotatingFileHandler(
        log_filename, maxBytes=20, backupCount=5, encoding='bz2-codec')
    logger.addHandler(handler)
    for i in range(20):
        logger.debug('i = %d' % i)

PS. Python3 удалил "bz2-codec" из набора допустимых кодировок, поэтому это решение относится только к Python2.

person unutbu    schedule 10.08.2011
comment
Это работает, когда журнал добавлен? Я ожидал, что нет, но не проверял. - person ron rothman; 03.06.2014