logging 模块多线程, 多用户访问时有问题

0 views
Skip to first unread message

Marco

unread,
Sep 21, 2012, 4:20:29 AM9/21/12
to pyth...@googlegroups.com, shlug, yunt...@googlegroups.com
如题, 我和队友一起写一套东西, 他写的代码基本上一个以一个thread的形式存活在我的进程里, 当然我也有其它的线程。
然后我们各自初始化logging库, 初始化的方式不太相同, 使用方式上(formatting)什么的也完全独立的, 然后我们使用不同的文件各自记录各自的东西。。。


结果跑下来出现各种问题。。。。日志文件支离破碎得非常严重, 要不丢失, 要不各个rotate之间乱写。。。。大致看了下库的实现, 有点儿罗嗦, 索性自己实现了一个更简单的日志模块, 我自己用(目测这样share使用也没问题, 不要太在意性能的话)。

目前跑下来非常安逸。


水平有限, 贴代码于此, 各位钛合金狗眼的不要瞎掉才好

#!/usr/bin/python
import os
import sys
import time
import inspect
import datetime
import threading
 

RAISE_IO_ERROR = True
 

class HandlerBase( object ):
    def __init__(self, lock, logfile, name):
        self.lock = lock
        
        self.logfile = logfile
        self.name = name
        self.current_level = None
    
    def _open_log(self):
        try:
            self.fd = open(self.logfile, 'a+', 0)
        except Exception, ex:
            global RAISE_IO_ERROR
            if RAISE_IO_ERROR:
                raise ex
    
    def __getattribute__(self, name):
        if name in ('debug', 'info', 'warning', 'error', 'critical'):
            self.current_level = name
            return self.write
        else:
            return object.__getattribute__(self, name)
    
    def write(self, string):
        with self.lock:
            if self.need_rotate():
                self.rotate()
            
            self.check_file()
            
            self.do_write(string)
    
    def check_file(self):
        
        if not os.path.isfile(self.logfile):
            global RAISE_IO_ERROR
            self._open_log()
    
    def need_rotate(self):
        return False
    
    def rotate(self):
        return
    
    def do_write(self, string):
        fmt = '%(asctime)s %(name)s %(levelname)s\t%(module)s->%(funcName)s.L%(lineno)s %(message)s'
        content = {}
        content['asctime'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
        content['name'] = self.name
        content['levelname'] = self.current_level
        
        #f = inspect.currentframe()
        f = sys._getframe(2)
        content['module'], content['lineno'], content['funcName'], _, _ = inspect.getframeinfo(f)
        content['module'] = os.path.basename(content['module'])
        
        if string[0] == '\n':
            string = string[1:]
            fmt = '\n' + fmt
        content['message'] = string
        
        fmt = fmt%content
        #print fmt
        fmt += '\n'
        
        try:
            self.fd.write(fmt)
            self.fd.flush()
        except Exception, ex:
            global RAISE_IO_ERROR
            if RAISE_IO_ERROR:
                raise ex

class TimedRotatingFileHandler( HandlerBase ):
    
    def __init__(self, lock, logfile, name):
        super(TimedRotatingFileHandler, self).__init__(lock, logfile, name)
        self.logfile_base = logfile
        
        self.fd = None
        self._remove_old(keep=10)
        self._open_log()
    
    def _open_log(self):
        global RAISE_IO_ERROR
        
        self.ltime_suffix = self._get_localtime_suffix()
        
        if self.fd:
            try:
                self.fd.close()
            except Exception, ex:
                if RAISE_IO_ERROR:
                    raise ex
        
        self.logfile = self.logfile_base + self.ltime_suffix
        try:
            self.fd = open(self.logfile, 'a+', 0)
        except Exception, ex:
            if RAISE_IO_ERROR:
                raise ex
    def _remove_old(self, keep=10):
        oldpwd = os.getcwd()
        
        os.chdir(os.path.dirname(self.logfile_base))
        
        files = filter(os.path.isfile, os.listdir('./'))
        files.sort(key=lambda x: os.path.getmtime(x), reverse=True)
        
        for f in files[keep:]: # keep 20 recently
            try:
                os.remove(f)
            except Exception, ex:
                if RAISE_IO_ERROR:
                    raise ex
        
        os.chdir(oldpwd)
    def _get_localtime_suffix(self):
        ltime = time.localtime()
        return '.' + str(ltime.tm_mon) + '-' + str(ltime.tm_mday) + '-' + str(ltime.tm_year)
    def need_rotate(self):
        return False if self._get_localtime_suffix() == self.ltime_suffix else True
    
    def rotate(self):
        print '!!'
        self._remove_old(keep=10)
        self._open_log()

class TinyLog( object ):
    
    _lock = threading.RLock()
    _handlers = dict()
    def __init__(self, logfile=None, name=None):
        name = str(name)
        
        if self._handlers.get(name):
            pass
        else:
            #self._handlers[name] = HandlerBase(self._lock, logfile, name)
            self._handlers[name] = TimedRotatingFileHandler(self._lock, logfile, name)
    
    def get_logger(self, name):
        name = str(name)
        return self._handlers.get(name)

#######################
if __name__ == '__main__':
    logger = TinyLog('/tmp/test.log', 'test').get_logger('test')
    
    logger.info('12345\n')



--
LinuX
Violin
Canon EOS
log.py
Reply all
Reply to author
Forward
0 new messages