简体   繁体   English

Python TimedRotatingFileHandler 覆盖日志

[英]Python TimedRotatingFileHandler overwrites logs

I setup TimedRotatingFileHandler like that:我像这样设置TimedRotatingFileHandler

import logging as logging
from logging.handlers import TimedRotatingFileHandler
import os
import time

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# new file every minute
rotation_logging_handler = TimedRotatingFileHandler('logs/log', 
                               when='m', 
                               interval=1, 
                               backupCount=5)
rotation_logging_handler.setLevel(logging.DEBUG)

format = u'%(asctime)s\t%(levelname)s\t%(filename)s:%(lineno)d\t%(message)s'
rotation_logging_handler.setFormatter(logging.Formatter(format))
rotation_logging_handler.suffix = '%Y-%m-%d'

logger.addHandler(rotation_logging_handler)

Usage:用法:

logger.logging.info('Service started at port %s', config.get_param('port'))

while True:
    time.sleep(21)
    logger.logging.info('Now time is {}'.format(time.time()))

I expected that every minute new messages from logs/log had to append to existing log file for current date.我希望每分钟来自logs/log新消息都必须附加到当前日期的现有日志文件中。 Instead it every minute messages from logs/log overwrote existing log file for current date.相反,它每分钟来自logs/log消息都会覆盖当前日期的现有日志文件。

What should I do to reach that behaviour?我应该怎么做才能达到这种行为?

PS: After small research I found that TimedRotatingFileHandler in the doRollover method deletes existing log file and creates new file. PS:小研究后,我发现, TimedRotatingFileHandlerdoRollover方法删除现有的日志文件,并创建新的文件。 So first solution is to create new handler derived from TimedRotatingFileHandler which creates new file (with some index for example) insted of deleting existing log file.所以第一个解决方案是创建从TimedRotatingFileHandler派生的新处理程序,它创建新文件(例如带有一些索引),而不是删除现有的日志文件。

After little bit more researching I found BaseRotatingHandler.namer attribute usage in the BaseRotatingHandler.rotation_filename method :经过多一点研究,我发现BaseRotatingHandler.namer的属性使用BaseRotatingHandler.rotation_filename方法

The default implementation calls the 'namer' attribute of the handler, if it's callable, passing the default name to it.默认实现调用处理程序的“namer”属性,如果它是可调用的,则将默认名称传递给它。 If the attribute isn't callable (the default is None), the name is returned unchanged.如果该属性不可调用(默认值为 None),则返回名称不变。

So as a solution I implemented my own namer function that got filename and returned new filename with my template:因此,作为一个解决方案,我实现了自己的namer函数,该函数获取filename并使用我的模板返回新filename

  • 20181231.log
  • 20181231.0.log
  • 20181231.1.log
  • etc.等。

Full example:完整示例:

import logging as logging
from logging.handlers import TimedRotatingFileHandler
import os
import time


def get_filename(filename):
    # Get logs directory
    log_directory = os.path.split(filename)[0]

    # Get file extension (also it's a suffix's value (i.e. ".20181231")) without dot
    date = os.path.splitext(filename)[1][1:]

    # Create new file name
    filename = os.path.join(log_directory, date)

    # I don't want to add index if only one log file will exists for date
    if not os.path.exists('{}.log'.format(filename)):
        return '{}.log'.format(filename)

    # Create new file name with index
    index = 0
    f = '{}.{}.log'.format(filename, index)
    while os.path.exists(f):
        index += 1
        f = '{}.{}.log'.format(filename, index)
    return f


format = u'%(asctime)s\t%(levelname)s\t%(filename)s:%(lineno)d\t%(message)s'
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# new file every minute
rotation_logging_handler = TimedRotatingFileHandler('logs/log', 
                               when='m', 
                               interval=1, 
                               backupCount=5)
rotation_logging_handler.setLevel(logging.DEBUG)
rotation_logging_handler.setFormatter(logging.Formatter(format))
rotation_logging_handler.suffix = '%Y%m%d'
rotation_logging_handler.namer = get_filename

logger.addHandler(rotation_logging_handler)

According to the documentation of TimedRotatingFileHandler :根据TimedRotatingFileHandler的文档:

The system will save old log files by appending extensions to the filename.系统将通过将扩展名附加到文件名来保存旧的日志文件。 The extensions are date-and-time based, using the strftime format %Y-%m-%d_%H-%M-%S or a leading portion thereof, depending on the rollover interval.扩展基于日期和时间,使用 strftime 格式%Y-%m-%d_%H-%M-%S或其前导部分,具体取决于翻转间隔。

In other words: by modifying suffix you are breaking the rollover .换句话说:通过修改后缀,正在打破 rollover Just leave it at default and python will create the files called:只需将其保留为默认值,python 将创建以下文件:

  • logs/log2018-02-02-01-30
  • logs/log2018-02-02-01-31
  • logs/log2018-02-02-01-32
  • logs/log2018-02-02-01-33
  • logs/log2018-02-02-01-34

And after this (if backupCount=5 ) it will delete the -30 one and create the -35 .在此之后(如果backupCount=5 )它将删除-30并创建-35

If you instead want to have names like :如果您想要使用以下名称:

  • logs/log2018-02-02-01.0
  • logs/log2018-02-02-01.1
  • logs/log2018-02-02-01.2
  • logs/log2018-02-02-01.3
  • logs/log2018-02-02-01.4

Where 0 is the newest one and .4 is the oldest one, then yes, that handler has not been designed to do that.其中0是最新的, .4是最旧的,那么是的,该处理程序并未设计为这样做。

It is very much possible to change the filenames when they are rotated to anything you want by overrding the rotation_filename method of the BaseRotatingHandler class and setting it to an appropriate callable.通过覆盖BaseRotatingHandler类的rotation_filename方法并将其设置为适当的可调用对象,很有可能在将文件名旋转为您想要的任何内容时更改文件名。

Here is a very trivial example of doing the same, but you can tweak it to suit your needs.这是一个非常简单的例子,可以做同样的事情,但你可以调整它以满足你的需要。

import logging
from logging.handlers import TimedRotatingFileHandler
import datetime as dt

def filer(self):
    now = dt.datetime.now()
    return 'file.txt'+now.strftime("%Y-%m-%d_%H:%M:%S")


logger = logging.getLogger()
rotating_file_handler = TimedRotatingFileHandler(filename="/Users/rbhanot/file.txt",
                                                 when='S',
                                                 interval=2,
                                                 backupCount=5)
rotating_file_handler.rotation_filename = filer
formatter = logging.Formatter(
    '%(asctime)s %(name)s:%(levelname)s - %(message)s')
rotating_file_handler.setFormatter(formatter)
logger.addHandler(rotating_file_handler)
logger.setLevel(logging.DEBUG)

logger.info("hello")

Here is the output of这是输出

❯ ls file*
file.txt  file.txt2020-10-06_13:12:13  file.txt2020-10-06_13:12:15  file.txt2020-10-06_13:13:45

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM