logging模塊定位log的實現

長年打log突然提出一個問題,logging模塊是如何定位到打印log的具體位置(文件、函數、行)的呢?以下從logging模塊的源碼解決這個問題。

Paste_Image.png

調用棧分析

當代碼運行到logging.debug('debug')的時候,我們來看看發(fā)生了什么。

函數調用路徑如下:

函數 函數內調用
logging.debug Logger()._log
Logger()._log Logger().findCaller、 Logger().makeRecord
Logger().findCaller currentframe
currentframe sys.exc_info
makeRecord 調用的函數與本文關系不大

以下詳細分析這些函數的細節(jié)

currentframe函數

currentframe函數的作用是返回當前的棧幀。實現是制造并捕獲一個異常,并通過sys.exc_info函數得到這個異常的信息,實現簡單而巧妙。

currentframe函數的實現

def currentframe():
    """Return the frame object for the caller's stack frame."""
    try:
        raise Exception
    except:
        return sys.exc_info()[2].tb_frame.f_back

sys.exc_info函數獲取當前正在處理的異常類,exc_type、exc_value、exc_traceback是當前處理的異常詳細信息三元組(type, value, traceback)。

sys.exc_info()[2]返回當前異常的棧,調用tb_frame返回當前異常的幀,也就是該函數raise Exception的異常幀,打印log的目的是查看log具體的位置,所以當前的信息肯定是不需要的,所以調用f_back得到他的outer層,并返回。

此時我們返回到父函數findCaller

findCaller

findCaller繼續(xù)子函數currentframef_back功能,在while循環(huán)里面不斷追溯上游捕抓Exception的位置,直到當前棧所在文件不是當前的文件_srcfile為止,實現如下:

def findCaller(self):
    f = currentframe() # 調用上面提到的currentframe函數
    if f is not None:
        f = f.f_back
    rv = "(unknown file)", 0, "(unknown function)"
    while hasattr(f, "f_code"): # 利用f_code屬性
        co = f.f_code
        filename = os.path.normcase(co.co_filename)
        if filename == _srcfile: # 如果上游捕抓的位置是當前文件,那么繼續(xù)上溯,最終得到打印log的位置
            f = f.f_back # 繼續(xù)上溯
            continue
        rv = (co.co_filename, f.f_lineno, co.co_name) # 文件名、行數和函數名
        break
    return rv

# _srcfile定義
_srcfile = os.path.normcase(currentframe.__code__.co_filename) # currentframe函數和findCaller函數在同一個文件里面

返回的rv也是一個三元組(filename、lineno、co_name),包含打印log的文件名、代碼行數、函數名字。到這為止,打印log需要的信息就收集到了。

總結

log日志信息的實現是利用異常的捕獲機制去做的,我們知道當拋出一個異常的時候,異常會一步一步往上拋,直到得到處理或者程序異常結束為止,這樣就一定可以追溯到源頭。
另外可以看到,在尋找_srcfile的時候,調用了__code__來返回當前代碼所屬的文件名;在findCaller里用frame.f_lineno來獲取代碼行,用co.co_name來獲取當前函數的名字;等等。可見,得益于強大自省的特性,整體實現簡單明了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容