網站首頁 編程語言 正文
問題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)
問題2: Logger對象的層級,父子關系如何實現的?
首先,logging模塊中logger層級關系是一個樹形關系的結構,這個關系的樹根是'root'。
root = RootLogger(WARNING) #RootLogger類是Logger的子類,無特殊功能,只是定義名字為‘root'。
Logger.root = root
Logger.manager = Manager(Logger.root)
當調用logging.getLogger(),用以獲取某個Logger時,如果參數為空,則返回‘root’。否則,調用Manager的getLogger()方法獲取Logger。
def getLogger(name=None):
"""
Return a logger with the specified name, creating it if necessary.
If no name is specified, return the root logger.
"""
if name:
return Logger.manager.getLogger(name)
else:
return root
Manager的getLogger()定義如下:
def getLogger(self, name):
"""
Get a logger with the specified name (channel name), creating it
if it doesn't yet exist. This name is a dot-separated hierarchical
name, such as "a", "a.b", "a.b.c" or similar.
If a PlaceHolder existed for the specified name [i.e. the logger
didn't exist but a child of it did], replace it with the created
logger and fix up the parent/child references which pointed to the
placeholder to now point to the logger.
"""
rv = None
_acquireLock()
try:
if name in self.loggerDict:
rv = self.loggerDict[name]
if isinstance(rv, PlaceHolder):
ph = rv
rv = _loggerClass(name)
rv.manager = self
self.loggerDict[name] = rv
self._fixupChildren(ph, rv)
self._fixupParents(rv)
else:
rv = _loggerClass(name)
rv.manager = self
self.loggerDict[name] = rv
self._fixupParents(rv)
finally:
_releaseLock()
return rv
Manager對象中的loggerDict字典,存放logger名字和logger對象的映射關系。PlaceHolder類,是一個容器。
例如,名字為'sell'的PlaceHolder對象,首先還不存在'sell'的logger,然后,所以以'sell‘開頭的logger在這個對象內都存在一個引用,如'sell.food','sell.cloth.china'等已有的logger對象。 當調用getLogger()獲取一個未存在的logger時,如名字為'level1.level2', 首先創建一個名字為'level1.level2'的logger對象,并存于loggerDict中。然后,調用_fixupParents()。
_fixupParents()的作用:
在這個名字的層級鏈上,找到第一個logger對象,將其作為父親,并返回。鏈上不是logger對象的名字,創建一個PlaceHolder對象(如果未創建),將自己加入其中。
例如,新增‘level1.level2.level3’的logger,調用_fixupParents將創建一個名字為'level1.level2‘的PlaceHolder對象,創建一個名字為’level1‘的PlaceHolder對象,并將’level1.level2.level3‘這個logger分別加入以上兩個PlaceHolder對象容器內,將它的父親設定為’root‘。
總之,_fixupParents是使logger對象指向真正的父親節點(logger對象),并將logger自己加入到所有上層的PlaceHolder對象容器內。
如果獲取一個名字已存在于loggerDict中,并且這個名字對應的是一個先前創建的PlaceHolder對象。首先,創建一個對應名字的logger對象。然后,調用_fixupChild(),修正這個PlaceHolder對象所包含的下游logger對象的父親。最后,調用_fixupParent(),作用與上一步相同。
父子層級關系,主要作用是,當logger對象的propagate屬性值1(默認值)時,每條logRecord記錄都會傳給父logger處理。這樣可以只需要定義好‘root’根logger對象,其他的logger定義個名字,根據模塊名,類名等,然后綁定一個NullHandler。最后,所有的logRecord將交給’root‘統一處理處理。這是多模塊產生統一格式log的方式。
原文鏈接:https://blog.csdn.net/wangst4321/article/details/8658859
相關推薦
- 2023-05-29 scipy稀疏數組coo_array的實現_python
- 2022-10-14 面試官:int(1) 和 int(10) 有什么區別?
- 2022-07-11 SOC驗證環境的啟動方式
- 2022-08-12 Android自定義View實現圓形加載進度條_Android
- 2022-07-01 iOS?DispatchSourceTimer?定時器的具體使用_IOS
- 2022-03-23 C++控制權限關鍵字protected_C 語言
- 2022-06-29 python人工智能tensorflow函數tf.get_collection使用方法_python
- 2022-08-03 Python如何對文件進行重命名_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支