關於使用python logging模組的幾點總結

2021-07-03 15:16:55 字數 4493 閱讀 8639

關於使用python logging模組的幾點總結

使用python的標準日誌模組logging可以非常方便地記錄日誌。python日誌系統非常豐富。新增結構化或非結構化日誌輸出到python**,寫到檔案,輸出到控制台,傳送到系統日誌,或者自定義輸出格式都很容易。

下面是我實踐過程中遇到的一些經驗和教訓的總結。

1.乙個簡單的日誌系統示例

業務場景如下:

開發乙個日誌系統, 既要把日誌輸出到控制台, 還要寫入日誌檔案

#!/usr/bin/env python

#encoding: utf-8

import logging

#建立乙個logger例項

logger = logging.getlogger('mylogger')

logger.setlevel(logging.debug)

#建立乙個handler,用於寫入日誌檔案

fh = logging.filehandler('******_log.log')

fh.setlevel(logging.debug)

#建立乙個handler,用於輸出到控制台

ch = logging.streamhandler()

ch.setlevel(logging.debug)

#定義handler的輸出格式

formatter = logging.formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setformatter(formatter)

ch.setformatter(formatter)

#給logger新增handler

logger.addhandler(fh)

logger.addhandler(ch)

#記錄一條日誌

logger.info('foobar')

執行後, 在控制台和日誌檔案都有一條日誌:

2.logging模組的api

結合上面的例子,我們說下幾個最常使用的api

logging.getlogger([name])

返回乙個logger例項,如果沒有指定name,返回root logger。

只要name相同,返回的logger例項都是同乙個而且只有乙個,即name和logger例項是一一對應的。這意味著,無需把logger例項在各個模組中傳遞。只要知道name,就能得到同乙個logger例項

logger.setlevel(lvl)

設定logger的level, level有以下幾個級別:

如果把looger的級別設定為info, 那麼小於info級別的日誌都不輸出, 大於等於info級

別的日誌都輸出

logger.debug("foobar")    # 不輸出   

logger.info("foobar")        # 輸出  

logger.warning("foobar") # 輸出  

logger.error("foobar")      # 輸出  

logger.critical("foobar")    # 輸出  

logger.addhandler(hdlr)

logger可以僱傭handler來幫它處理日誌, handler主要有以下幾種:

streamhandler: 輸出到控制台

filehandler:   輸出到檔案

handler還可以設定自己的level以及輸出格式。

logging.basicconfig([**kwargs])

* 這個函式用來配置root logger, 為root logger建立乙個streamhandler,

設定預設的格式。

* 這些函式: logging.debug()、logging.info()、logging.warning()、

logging.error()、logging.critical() 如果呼叫的時候發現root logger沒有任何

handler, 會自動呼叫basicconfig新增乙個handler

* 如果root logger已有handler, 這個函式不做任何事情

使用basicconfig來配置root logger的輸出格式和level:

import logging  

logging.basicconfig(format='%(levelname)s:%(message)s', level=logging.debug)

3.日誌物件間的層級結構除了root logger, 實際上logger例項之間還有父子關係, root logger就是處於最頂層的logger, 它是所有logger的祖先。如下圖:

root logger是預設的logger

如果不建立logger例項, 直接呼叫logging.debug()、logging.info()logging.warning()、logging.error()、logging.critical()這些函式,

那麼使用的logger就是 root logger, 它可以自動建立,也是單例項的。

如何得到root logger

通過logging.getlogger()或者logging.getlogger("")得到root logger例項。

預設的level

root logger預設的level是logging.warning

如何表示父子關係

logger的name的命名方式可以表示logger之間的父子關係. 比如:

parent_logger = logging.getlogger('foo')

child_logger = logging.getlogger('foo.bar')

什麼是effective level

logger有乙個概念,叫effective level。 如果乙個logger沒有顯示地設定level,那麼它就

用父親的level。如果父親也沒有顯示地設定level, 就用父親的父親的level,以此推....

最後到達root logger,一定設定過level。預設為logging.warning

child loggers得到訊息後,既把訊息分發給它的handler處理,也會傳遞給所有祖先logger處理,

來看乙個例子

#!/usr/bin/env python

#encoding: utf-8

import logging

logging.basicconfig(format='%(levelname)s:%(message)s', level=logging.debug)

r = logging.getlogger()

ch = logging.streamhandler()

ch.setlevel(logging.debug)

formatter = logging.formatter('%(asctime)s - %(levelname)s - %(message)s')

ch.setformatter(formatter)

r.addhandler(ch)

p = logging.getlogger('foo')

p.setlevel(logging.debug)

ch = logging.streamhandler()

ch.setlevel(logging.debug)

formatter = logging.formatter('%(asctime)s - %(message)s')

ch.setformatter(formatter)

p.addhandler(ch)

c = logging.getlogger('foo.bar')

c.debug('foo')

輸出如下:

可見,孩子logger沒有任何handler,所以對訊息不做處理。但是它把訊息**給了它的父親以及root logger。最後輸出四條日誌。

參考文獻

[1].

關於this 的使用

如有不對的地方請大家指出,呵呵.this 的使用 1.this是指當前物件自己。當在乙個類中要明確指出使用物件自己的的變數或函式時就應該加上this引用。如下面這個例子中 public class a public static void main string args 執行結果 s hellow...

關於使用saiku,MDX

最近在研究saiku的動態報表部分,沒有頭緒。saiku是乙個輕量級的olap分析引擎,可以方便的擴充套件 嵌入和配置。saiku通過rest api連線olap系統,利用其友好的介面為使用者提供直觀的分析資料的方式,它是基於jquery做的前端介面。已經將saiku server搭建好了,也將乙個...

關於AsyncHttpClient使用

在android開發中,傳送 處理http請求簡直太常見了,以至於我們的 裡到處充斥著各種httpclient和與之相關又臭又長的 它們存在於你 的各個角落,每次看見都令人作嘔,而你僅僅是為了server能返回乙個string或者json給你。每次當我自己寫這樣 的 時,我都會想能不能簡化下這個流程...