Python旋转文件处理程序记录错误的时间戳顺序

时间:2013-12-13 16:56:51

标签: python logging timestamp cherrypy

我的主管要我修复“日志中的并发问题”,这意味着我们生成的日志文件在不同文件的开头/结尾都有混合时间戳。那就是:

  • 第一个日志文件在最后:

    [03/Dec/2013:13:55:19]---------------------
    [03/Dec/2013:13:55:20]---------------------
    [03/Dec/2013:13:55:20]---------------------
    
  • 第二个文件从:

    开始
    [03/Dec/2013:13:40:16]---------------------
    [03/Dec/2013:13:40:16]---------------------
    [03/Dec/2013:13:40:23]---------------------
    

我们使用旋转文件处理程序,第二个文件应该有第一个结束时开始的时间戳,但事实并非如此。如何在文件旋转期间以正确的顺序将时间戳刷新到日志中?

“Logger”类,它只使用Python日志记录模块:

class logger:
    def __init__(self, logger_name='prod'):
        self.error_logger = logging.getLogger(logger_name+'_error')

    def error(self, msg='', level='error'):
        if msg:
            getattr(self.error_logger,level)(msg)

    def log(self, msg='', level='info'):
        if msg:
            getattr(self.error_logger,level)(msg)

日志格式:

class our_formatter(logging.Formatter):

def find_topmost_stack_frame(self):
    i = 0
    stack = []
    while True:
        try:
            fr = sys._getframe(i)
            if fr.f_code.co_name == '__call__':
                    break
            stack.append(fr)
        except:
            break
        i += 1
    return "%s:%s" % (stack[-4].f_code.co_filename, stack[-4].f_lineno)

def format(self, record):
    try:
        if record.done:
                return record.msg
    except:
        record.done = False

    rtime = time.strftime("%d/%b/%Y:%H:%M:%S", time.localtime(record.created))
    from tools.user_management import user_pack
    email = user_pack().get_email()

    if record.levelno > 20:
        if email:
            record.msg = '[%s][user:%s][%s] {%s} %s' % ( rtime, email, record.levelname, self.find_topmost_stack_frame(),
                                                         record.msg)
        else:
            record.msg = '[%s][%s] {%s} %s' % ( rtime, record.levelname, self.find_topmost_stack_frame(), record.msg)
    else:
        if email:
            record.msg = '[%s][user:%s][%s] %s' % ( rtime, email, record.levelname, record.msg)
        else:
            record.msg = '[%s][%s] %s' % ( rtime, record.levelname, record.msg)

    record.done = True
    return logging.Formatter.format(self, record)

最后是logger的配置:

log = cherrypy.log
log.error_file = None

maxBytes = getattr(log, "rot_maxBytes", 10000000)
backupCount = getattr(log, "rot_backupCount", 1000)
fname = getattr(log, "rot_error_file", "logs/error.log")

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

# Make a new RotatingFileHandler for the error log.
h = logging.handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount)
h.setFormatter(rest_formatter())
log.error_log.addHandler(h)

# set up custom ReST logger
logger = logging.getLogger("rest_error")
logger.addHandler(h)

# set up our custom logger
ha = logging.handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount)
ha.setFormatter(our_formatter())
logger = logging.getLogger("prod_error")
logger.addHandler(ha)

应用程序是多线程的,但是内置日志记录应该是线程安全的(我今天正在阅读其代码的某些部分,它肯定会使用一些锁)。

问题只出现在一个文件的开头和前一个文件的结尾之间(不在中间),所以我认为这是由记录器保留文件空间的一些情况,但我知道它应该保持正确的顺序,因为每个文件处理程序只应该有一个记录器实例。

我们有很多记录。很多我的意思是每秒通常有10多个日志。

2 个答案:

答案 0 :(得分:1)

单个文件的多个处理程序中存在的问题。记录器使用不同的处理程序,因此他们试图同时在同一个文件中写入,偶尔会导致创建一个新文件(然后他们在一段时间内写入两个区分文件)。

删除“ha”处理程序似乎解决了这个问题!

答案 1 :(得分:0)

阅读你的问题,在我看来你需要刷新写缓冲区。

要求系统在文件中写入某些而不等待它(系统)自己触发缓冲区内容的写入,就像这样:

from os import fsync
with open(filename,'a') as fh:
    fh.write(something)
    fh.flush()
    fsync(fh.fileno())
    # continued code

某事是一个很小的数量时,这是一个必要的程序。

但是,当文件关闭时,通常会清空写入缓冲区,并且在完全关闭之前将其内容写入文件中。
Si,我不知道这个答案是否真的为你带来了一些有用的东西。