Python 日志模塊 logging

Python 日志模塊 logging 是比較好用的顶滩,但似乎官方文檔寫得不是很好。這里分享一下我是怎么使用的寸爆〗嘎常基礎(chǔ)的就不介紹了,只介紹 2 個知識點(diǎn):第一赁豆,日志信息如何從模塊傳遞給 main 腳本仅醇;第二,如何使用 filter 選擇性處理日志魔种。
logging 日志包含幾個互相關(guān)聯(lián)的部分:

  • Logger - 產(chǎn)生 LogRecord (日志記錄對象)
  • Handler - 處理日志析二,如輸出到文件
  • Formatter - 將日志信息格式化
  • Filter - 按條件過濾或處理日志

由于 Logger 是會按層級傳遞日志記錄的,比如名字為 A.B 的 Logger 會將日志傳遞給名字為 A 的 Logger务嫡,并且所有 Logger 都會將消息往上傳遞甲抖,直到 root Logger,利用這個機(jī)制可以將日志信息從模塊傳遞給 main心铃,而不是將 Logger 本身在不同模塊傳遞准谚。

下面是第一個知識點(diǎn)的示例代碼,假如有個 main.py 它會調(diào)用 child.py 的函數(shù)并且 child.py 產(chǎn)生的日志由 main.py 處理去扣。

$ ls
child.py  main.py  __pycache__

child.py 代碼如下柱衔。

import logging

_logger = logging.getLogger(name=__name__)

def create_log():
    _logger.info("info from child.py")
    _logger.error("child.py has some problem")

if __name__ == "__main__":
    pass

child.py 使用 getLogger 函數(shù)創(chuàng)建了個 Logger 并使用文件名命名,這是推薦的創(chuàng)建 Logger 對象方法愉棱。之后在 create_log 函數(shù)創(chuàng)建了一條 INFO 和一條 ERROR 日志唆铐。

main.py 代碼如下。

import logging

from child import create_log

logger = logging.getLogger()
logger.setLevel("DEBUG")
formater = logging.Formatter(fmt="[%(levelname)s %(asctime)s] %(message)s")
handler = logging.StreamHandler()
handler.setFormatter(formater)
handler.setLevel("DEBUG")
logger.addHandler(handler)

logger.info("info from main.py")
logger.debug("debug from main.py")
logger.warning("warning from main.py")

create_log()

main.py 同樣使用 getLogger 函數(shù)創(chuàng)建 Logger 但是不輸入名字奔滑,此時獲取的是 root Logger艾岂,因此 child.py 的 Logger 會將日志記錄傳遞過來。

使用 setLevel 設(shè)置了 Logger 日志等級朋其,低于等級設(shè)置的日志將被忽略王浴,比如設(shè)置為 ERROR 時那么由于 WARNING脆炎, INFO, DEBUG 都是低于 ERROR 等級的氓辣,這些日志記錄會被忽略秒裕。

使用 Formatter 定義了日志信息格式,其格式為 [等級 時間] 信息钞啸。
使用 StreamHandler 創(chuàng)建一個流 Handler 默認(rèn)流為 stderr 因此會將日志信息輸出到標(biāo)準(zhǔn)錯誤輸出几蜻。將 Formatter 添加到這個 Handler 并設(shè)置 Handler 的日志等級,Handler 將會按照規(guī)定格式輸出高于等級的日志信息到標(biāo)準(zhǔn)錯誤輸出体斩。
將 Handler 添加到 root Logger 就能處理所有的日志信息了梭稚。

運(yùn)行 main.py 后得到以下屏幕輸出∷段穑可以看到 child.py 的日志信息順利傳遞給了 main.py 并得到處理哨毁。

$ python main.py
[INFO 2024-04-22 20:02:34,558] info from main.py
[DEBUG 2024-04-22 20:02:34,558] debug from main.py
[WARNING 2024-04-22 20:02:34,558] warning from main.py
[INFO 2024-04-22 20:02:34,558] info from child.py
[ERROR 2024-04-22 20:02:34,559] child.py has some problem

如果將 Formatter 格式修改為輸出模塊名 "[%(levelname)s %(module)s] %(message)s" 那么日志將顯示為。

$ python main.py
[INFO main] info from main.py
[DEBUG main] debug from main.py
[WARNING main] warning from main.py
[INFO child] info from child.py
[ERROR child] child.py has some problem

第二個知識點(diǎn)示例代碼如下源武。在 main.py 寫一個自己的 Filter 類,繼承自 logging.Filter 在里面覆蓋 filter 方法想幻,設(shè)置自己的過濾條件粱栖。在示例里設(shè)置輸出 message 長度小于或等于 20 的日志。

import logging

class MyFilter(logging.Filter):
    def __init__(self, name: str = "") -> None:
        super().__init__(name)
        
    def filter(self, record: logging.LogRecord) -> bool:
        if len(record.msg) > 20:
            return False
        else:
            return True

logger = logging.getLogger()
logger.setLevel("DEBUG")
formater = logging.Formatter(fmt="[%(levelname)s %(module)s] %(message)s")
handler = logging.StreamHandler()
handler.setFormatter(formater)
handler.setLevel("DEBUG")
# 添加 Filter 到 handler
handler.addFilter(MyFilter())
logger.addHandler(handler)

logger.info("a long long long long long info")
logger.info("a short info")

運(yùn)行輸出如下脏毯。

$ python main.py
[INFO main] a short info

可以看到實(shí)現(xiàn)了想要的過濾效果闹究。

使用 Filter 也可以修改日志,比如食店。

class MyFilter(logging.Filter):
    def __init__(self, name: str = "") -> None:
        super().__init__(name)

    def filter(self, record: logging.LogRecord) -> bool:
        if len(record.msg) > 20:
            record.msg = ">20"
        else:
            record.msg = "<=20"
        return True

那么 main.py 運(yùn)行輸出為渣淤。

$ python main.py
[INFO main] >20
[INFO main] <=20
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吉嫩,隨后出現(xiàn)的幾起案子价认,更是在濱河造成了極大的恐慌,老刑警劉巖自娩,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件用踩,死亡現(xiàn)場離奇詭異,居然都是意外死亡忙迁,警方通過查閱死者的電腦和手機(jī)脐彩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姊扔,“玉大人惠奸,你說我怎么就攤上這事∏∩遥” “怎么了佛南?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵梗掰,是天一觀的道長。 經(jīng)常有香客問我共虑,道長愧怜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任妈拌,我火速辦了婚禮拥坛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘尘分。我一直安慰自己猜惋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布培愁。 她就那樣靜靜地躺著著摔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪定续。 梳的紋絲不亂的頭發(fā)上谍咆,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音私股,去河邊找鬼摹察。 笑死,一個胖子當(dāng)著我的面吹牛倡鲸,可吹牛的內(nèi)容都是我干的供嚎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼峭状,長吁一口氣:“原來是場噩夢啊……” “哼克滴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起优床,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤劝赔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后羔巢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體望忆,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年竿秆,在試婚紗的時候發(fā)現(xiàn)自己被綠了启摄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡幽钢,死狀恐怖歉备,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匪燕,我是刑警寧澤蕾羊,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布喧笔,位于F島的核電站,受9級特大地震影響龟再,放射性物質(zhì)發(fā)生泄漏书闸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一利凑、第九天 我趴在偏房一處隱蔽的房頂上張望浆劲。 院中可真熱鬧,春花似錦哀澈、人聲如沸牌借。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膨报。三九已至,卻和暖如春适荣,著一層夾襖步出監(jiān)牢的瞬間现柠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工弛矛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晒旅,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓汪诉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谈秫。 傳聞我的和親對象是個殘疾皇子扒寄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容