如题, 我和队友一起写一套东西, 他写的代码基本上一个以一个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')