摘要:在同一系統(tǒng)中我們有時(shí)要用到這種機(jī)制來(lái)方便日志打印,因此有時(shí)會(huì)不同進(jìn)程使用同一前綴名來(lái)初始化。避免日志重復(fù)的原則是在名有相同前綴的情況下對(duì)于一個(gè)模塊兩個(gè)進(jìn)程調(diào)的情況,涉及到會(huì)被其他進(jìn)程的模塊,不應(yīng)觸發(fā)任何同名前綴的的操作。
圖:
圖編號(hào)按順序1-4,嫌長(zhǎng)可以跳過(guò)定位過(guò)程看總結(jié)
定位過(guò)程:我司項(xiàng)目幾個(gè)服務(wù)進(jìn)程的初始化log都是這樣的:
這些進(jìn)程都會(huì)初始化一個(gè)叫 sdsom的logger,并且把handler加到了這個(gè)logger對(duì)象中,后面getlogger的時(shí)候我們是 sdsom.xx, 這個(gè)按點(diǎn)分隔會(huì)導(dǎo)致認(rèn)為是子logger,比如是sdsom.A,就會(huì)新建一個(gè)logger叫sdsom.A,然后把 sdsom 這個(gè)logger設(shè)為它的parent(圖1),打日志的時(shí)候,會(huì)一直往上遍歷,把所有parent的所有handler都打一遍(圖2)。這些實(shí)例進(jìn)程間是獨(dú)立的,但如果在一個(gè)進(jìn)程里,比如在A進(jìn)程中 import 了 B 的模塊,而這個(gè)模塊 import 了B自己的log.py模塊,觸發(fā)一次 addHandler (圖3),就把 B 的 handler 加進(jìn)了 A進(jìn)程的 sdsom logger里(把它設(shè)為了parent),所以 A 的 sdsom logger里有兩個(gè)handler (圖4),于是A 的log同時(shí)打到了B的日志文件里。(注意對(duì)比圖3 圖4的對(duì)象地址 是一致的)
這個(gè)logger父子關(guān)系前人要這么用的原因,我估計(jì)是我們項(xiàng)目的common這個(gè)模塊,用父子關(guān)系可以實(shí)現(xiàn)這樣一個(gè)方式:不需另外初始化,log = logging.getLogger("sdsom.common") 只需要執(zhí)行這一句,這個(gè)logger的parent就被設(shè)為 <import這個(gè)common模塊的> 進(jìn)程的 sdsom logger,實(shí)際上sdsom.xxx 點(diǎn)號(hào)后面的內(nèi)容都沒有影響了,這個(gè)common logger打印時(shí),會(huì)調(diào)parent,于是也就被相應(yīng)進(jìn)程的handler打印了。
本身也算方便的機(jī)制,但由于這種方式內(nèi)部實(shí)現(xiàn)不可見, 容易誤用。
如果要共享日志, 還有一種方式就是對(duì)相應(yīng)的logger顯式加handler:
比如要在其他日志里打印zerorpc的日志, 我們大部分日志初始化處都有這句: logging.getLogger("zerorpc").addHandler(handler), 給rpc的Logger加上自己的handler就可以了,由于有了handler,那么只要zerorpc的源碼里是getLogger("zerorpc")的(實(shí)際源碼中一般是getLogger(__name__),在包內(nèi)__name__即為"zerorpc.xxx"),日志就能打印到對(duì)應(yīng)進(jìn)程的日志里。
所以我們完全可以不用父子關(guān)系,而是像zerorpc一樣在進(jìn)程logger初始化的地方加上:
logging.getLogger("common").addHandler(handler)
然后common里的模塊直接log = logging.getLogger("common")用即可,為避免和三方庫(kù)重復(fù)要注意一下命名
當(dāng)然還有一種方式就是自己的handler也通過(guò)函數(shù)觸發(fā),不要在模塊全局上執(zhí)行,加入一個(gè)函數(shù)手動(dòng)調(diào),只在進(jìn)程初始化時(shí)調(diào)。
logging的父子關(guān)系是一個(gè)基礎(chǔ)機(jī)制,稍微看下源碼即可理解(其實(shí)主要就是圖1圖2):以點(diǎn)號(hào).分隔,取最后一個(gè)點(diǎn)號(hào)的左邊為前綴,以此前綴名作父,一個(gè)logger觸發(fā)記錄時(shí),會(huì)調(diào)用所有父親的handler。在同一系統(tǒng)中我們有時(shí)要用到這種機(jī)制來(lái)方便日志打印,因此有時(shí)會(huì)不同進(jìn)程使用同一前綴名來(lái)初始化logger。這時(shí),不同進(jìn)程的模塊若有相互import,容易造成一個(gè)日志打到多個(gè)日志文件里。如:
進(jìn)程A: A.py: logger = logging.getLogger("xxsystem.A") logger.addHandler(logging.FileHandler("service1.log"))
進(jìn)程B 兩個(gè)模塊: B.py: from C import func logger = logging.getLogger("xxsystem.B") logger.addHandler(logging.FileHandler("service2.log")) C.py: from A import func
這樣,就會(huì)造成B進(jìn)程的log總是同時(shí)打到兩個(gè)service1.log, service2.log日志文件里。這里是簡(jiǎn)化環(huán)境,只要B的import樹里有A模塊,就會(huì)造成同樣結(jié)果。
避免日志重復(fù)的原則是:
在logger名有相同前綴的情況下,對(duì)于一個(gè)模塊兩個(gè)進(jìn)程調(diào)的情況,涉及到會(huì)被其他進(jìn)程import的模塊,不應(yīng)觸發(fā)任何同名前綴的logger的addHandler操作。 (不能import <調(diào)用了addHandler方法的> 模塊,自身也不能執(zhí)行getLogger(prefix).addHandler)
實(shí)際上我司使用這種機(jī)制本來(lái)也沒有什么問(wèn)題,只要注意不要隨便import,都用getLogger即可。但由于代碼不規(guī)范還是出現(xiàn)了不應(yīng)有的import 日志初始化模塊的情況。
要達(dá)到:
哪個(gè)進(jìn)程調(diào)用模塊,日志就打在那個(gè)進(jìn)程對(duì)應(yīng)的日志里:
a) 用 getLogger,只要前綴相同,就會(huì)把當(dāng)前進(jìn)程的"prefix" logger設(shè)為父, 由于上面說(shuō)的原因,這個(gè)logger會(huì)且只會(huì)被打到調(diào)用它的進(jìn)程中(自己的handler沒有初始化過(guò))
b) 傳logger對(duì)象
無(wú)論哪個(gè)進(jìn)程調(diào)用模塊,日志都打在自己規(guī)劃所屬的進(jìn)程對(duì)應(yīng)日志里:
不要有任何父子關(guān)系, 日志名不要帶點(diǎn)。這時(shí)反過(guò)來(lái),必須調(diào)用日志初始化模塊觸發(fā)初始化,而不能只用getLogger, 否則是一個(gè)空logger,哪里都不會(huì)打印。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44962.html
摘要:一什么是是一個(gè)基于瀏覽器的自動(dòng)化工具,她提供了一種跨平臺(tái)跨瀏覽器的端到端的自動(dòng)化解決方案。模塊主要用來(lái)記錄用例執(zhí)行情況,以便于高效的調(diào)查用例失敗信息以及追蹤用例執(zhí)行情況。測(cè)試用例倉(cāng)庫(kù)用例倉(cāng)庫(kù)主要用來(lái)組織自動(dòng)化測(cè)試用例。 一、什么是Selenium? Selenium是一個(gè)基于瀏覽器的自動(dòng)化工具,她提供了一種跨平臺(tái)、跨瀏覽器的端到端的web自動(dòng)化解決方案。Selenium主要包括三部分:...
摘要:最近修改了項(xiàng)目里的相關(guān)功能,用到了標(biāo)準(zhǔn)庫(kù)里的模塊,在此做一些記錄??赡軟]有線程名??赡軟]有用戶輸出的消息日志級(jí)別有如下級(jí)別,,,,默認(rèn)級(jí)別是,模塊只會(huì)輸出指定以上的。在或者中這是很常見的方式。正常的做法應(yīng)該是全局只配置一次。 最近修改了項(xiàng)目里的logging相關(guān)功能,用到了python標(biāo)準(zhǔn)庫(kù)里的logging模塊,在此做一些記錄。主要是從官方文檔和stackoverflow上查詢到的一...
摘要:的繼承關(guān)系使用做日志輸出時(shí),首先我們需要一個(gè)創(chuàng)建一個(gè)對(duì)象。再設(shè)計(jì)多級(jí)別的日志系統(tǒng)時(shí),尤其要注意這點(diǎn)。當(dāng)然,這樣做其實(shí)是有悖于的本意的。是什么是一個(gè)程序內(nèi)全局唯一的,所有對(duì)象的祖先。因此,直接修改是危險(xiǎn)的。 0x00 python logging的繼承關(guān)系 使用python做日志輸出時(shí),首先我們需要一個(gè)創(chuàng)建一個(gè)Logger對(duì)象:import logging; logger = log...
摘要:類似這樣執(zhí)行打印最終輸出的日志要想在命令行模式工作的時(shí)候,查看它的編譯進(jìn)度,霖哥一般會(huì)遠(yuǎn)程跑進(jìn)執(zhí)行編譯工作的機(jī)器,然后用命令,把它的日志實(shí)時(shí)輸出來(lái)嗯,這相當(dāng)?shù)牟豢茖W(xué)啊。我是霖哥,一個(gè)商學(xué)院畢業(yè)的程序員,一個(gè)游戲開發(fā)工程師。 showImg(https://segmentfault.com/img/remote/1460000008856262); 如果你使用過(guò)Unity命令行模式(ba...
摘要:裝飾器介紹中的裝飾器的目的是為一個(gè)目標(biāo)函數(shù)添加額外的功能卻不修改函數(shù)本身。裝飾器的本身其實(shí)是一個(gè)特殊的函數(shù)。那么有啥更好的解決方式呢裝飾器代碼像上面這么寫,可以較好地解決了上面提到的第一個(gè)問(wèn)題。裝飾器語(yǔ)法糖放在函數(shù)前面,相當(dāng)于執(zhí)行了等。 怎么理解python中的裝飾器 一個(gè)比喻 知乎上有一個(gè)比較形象的比喻 https://www.zhihu.com/questio...:人類穿著內(nèi)褲很...
閱讀 3240·2021-11-24 09:39
閱讀 3179·2021-10-21 09:38
閱讀 2406·2019-08-29 15:28
閱讀 3749·2019-08-26 12:23
閱讀 2624·2019-08-26 12:19
閱讀 1369·2019-08-23 12:44
閱讀 2135·2019-08-23 12:02
閱讀 1007·2019-08-22 17:05