twisted日志系统提供了按照日期自动创建日志文件的功能, 不需要启动reactor也可以使用
启动日志示例代码:
outpath = '/Users/.../log'
outname = 'server.log'
if not os.path.exists(outpath) :
os.mkdir(outpath)
log.FileLogObserver.timeFormat = '%m-%d %H:%M:%S'
log_file = logfile.DailyLogFile(outname, outpath)
log.startLogging(log_file)
log系统初始化(twisted/python/log.py):
logfile = StdioOnnaStick(0, getattr(sys.stdout, "encoding", None)) # 封装sys.stdout
logerr = StdioOnnaStick(1, getattr(sys.stderr, "encoding", None)) # 封装sys.stderr
如何启动日志系统:
def startLogging(file, *a, **kw):
# 创建观察者,有日志或者说stdout.write操作的时候通知每个observer, file就是DailyLogFile
flo = FileLogObserver(file)
startLoggingWithObserver(flo.emit, *a, **kw) # 开始启动观察者
def startLoggingWithObserver(observer, setStdout=1):
addObserver(observer) # observe就是flo.emit函数
msg("Log opened.")
if setStdout:
sys.stdout = logfile # 将正常的print打印重定向到logfile对象
sys.stderr = logerr
从调用print语句开始打印分析日志打印的代码流程:
# print -> stdout.write -> logfile.write
# 所以看下logfile所对应的StdioOnnaStick类中write方法:
def write(self, data): # 如何到达这步:print -> stdout.write -> logfile.write
...
self.buf = d[-1]
messages = d[0:-1]
for message in messages:
msg(message, printed=1, isError=self.isError) # 调用theLogPublisher.msg
# LogPublisher的msg方法:
def msg(self, *message, **kw):
actualEventDict = (context.get(ILogContext) or {}).copy()
actualEventDict.update(kw)
actualEventDict['message'] = message
actualEventDict['time'] = time.time()
for i in range(len(self.observers) - 1, -1, -1): # 遍历注册的日志观察者
try:
# 调用observer函数,就是FileLogObserver.emit()
self.observers[i](actualEventDict)
...
# FileLogObserver.emit方法:
def emit(self, eventDict):
text = textFromEventDict(eventDict)
if text is None:
return
timeStr = self.formatTime(eventDict['time'])
fmtDict = {'system': eventDict['system'], 'text': text.replace("\n", "\n\t")}
msgStr = _safeFormat("[%(system)s] %(text)s\n", fmtDict)
# 调用最开始FileLogObserver()传入的DailyLogFile.write
util.untilConcludes(self.write, timeStr + " " + msgStr)
util.untilConcludes(self.flush) # Hoorj!
# DailyLogFile.write:
def write(self, data):
"""Write some data to the log file"""
BaseLogFile.write(self, data)
self.lastDate = max(self.lastDate, self.toDate())
# BaseLogFile.write:
def write(self, data):
if self.shouldRotate(): # 根据日期判断是否需要另起一个log文件:if self.toDate() > self.lastDate
self.flush()
self.rotate() # 调用DailyLogFile.rotate()方法新建log文件
self._file.write(data) # 终于开始写文件了
# DailyLogFile.rotate:
def rotate(self):
if not (os.access(self.directory, os.W_OK) and os.access(self.path, os.W_OK)):
return
newpath = "%s.%s" % (self.path, self.suffix(self.lastDate))
if os.path.exists(newpath):
return
self._file.close()
os.rename(self.path, newpath) # 将当前的log文件重命名为带日期的历史log文件
self._openFile() # 以self.path为路径打开一个新文件准备写入