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

Python旋转文件处理程序记录错误的时间戳顺序,python,logging,timestamp,cherrypy,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: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)
最后是记录器的配置:

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多个日志。

阅读您的问题,我觉得您需要刷新写入缓冲区

为了强制系统在不等待的情况下将某些内容写入文件(系统)本身触发缓冲区内容的写入,如下所示:

from os import fsync
with open(filename,'a') as fh:
    fh.write(something)
    fh.flush()
    fsync(fh.fileno())
    # continued code
这是一个必要的过程,当一些东西是一个很小的数量写

但是,当文件关闭时,通常写入缓冲区会清空,其内容会在文件完全关闭之前写入文件。

是的,我不知道这个答案是否真的给你带来了有用的东西。

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


删除“ha”处理程序似乎已经解决了问题

我们需要查看您的一些代码,甚至开始了解如何解决您的问题。日志是如何设置的。是否有多个进程/线程?为什么不同的处理程序写入同一个文件?@J.F.Sebastian我认为这是因为我们不想有太多类型的日志文件。无论如何-cherrypy本身几乎没有将任何内容记录到日志文件中(只有启动/重新启动序列)。rest_错误-我没有看到它在初始化后的任何地方被使用。@J.F.Sebastian-更正,我只是检查了一下,实际上也使用了rest记录器。但是,有时只有来自rest_logger的日志会出现时间戳顺序不正确的问题。我想知道这是否是cherrypy线程在接收请求时调度造成的某种问题。
日志记录
模块调用
flush()
本身。无论如何,旋转的日志文件是关闭的,应该会刷新缓冲区
fsync
可能有助于确保在进程崩溃时写入数据。请参阅中的讨论。但我看不出它与“日志中的并发问题”有什么关系。我认为后续文件可以打开,而前一个文件可以在未使用时间戳写入的特定时间内保持未关闭。我的主管告诉我,实际上,当他查看日志时,有两个日志同时写入,而其中一个几乎完成。因此,记录器似乎同时将其缓冲区刷新为两个文件,这看起来确实很奇怪。