問題1:如何獲取caller的(文件名,行號,函數名)?
當新增一條log記錄時,最終將調用Logger類的_log方法,這個方法首先會創建一個LogRecord對象。LogRecord對象需要(filename, lineno, funcname)參數信息。這是通過如下語句得到的:
fn, lno, func = self.findCaller()
findCaller內容如下:
f = currentframe() #f是frame對象,每個方法調用生成一個frame對象,放在程序堆棧中。
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code #獲取code對象,它包含filename屬性,funcname屬性
filename = os.path.normcase(co.co_filename)
if filename == _srcfile: #_srcfile是這個模塊文件自己的文件名,當文件名不再相同時
f = f.f_back # 得到外部調用者的frame,這就是需要的。
continue
rv = (filename, f.f_lineno, co.co_name)
break
return rv
currentframe函數的定義:
def currentframe():
"""Return the frame object for the caller's stack frame."""
try:
raise Exception #拋出異常,將生成traceback對象,其中包含frame對象。
except:
#sys.exc_traceback.tb_frame當前的frame, f_back調用著的frame
return sys.exc_traceback.tb_frame.f_back
#sys._getframe(3)返回的並不是當前的frame,3應該是計算好了的,減少循環的次數,返回的是logger.error()的frame
if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)