python—logger python之配置日誌的幾種方式 Python之向日志輸出中添加上下文信息 Python之日誌處理(logging模塊)

logging模塊能夠提供一個很簡單的basicConfig,可是它不夠強大,忘記它吧

html

使用logging模塊的loggerpython

 

import logging
 
logger = logging.getLogger()#建立一個logger實例
# 建立一個handler實例,用於寫入日誌文件
logger.setLevel('DEBUG')#默認級別是WARNING
fh = logging.FileHandler('test.log',encoding='utf-8')
 
# 再建立一個handler實例,用於輸出到控制檯
ch = logging.StreamHandler()
#建立格式實例
formatter = logging.Formatter('[%(asctime)s] %(levelname)s [%(pathname)s %(lineno)d [%(funcName)s] %(message)s',
                                datefmt='%Y-%m-%d %H:%M:%S')
fh.setLevel(logging.DEBUG)#若是logger的level級別比fh高,按logger的走
fh.setFormatter(formatter) #將第一個handler實例關聯格式實例
ch.setFormatter(formatter) #將第二個handler實例關聯格式實例
logger.addHandler(fh) #logger對象能夠添加多個fh和ch對象
logger.addHandler(ch)
 
#試驗輸出
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

 

先上一個簡單應用實例:服務器

logger記錄Exception
網絡

logger.exception("Exception Logged")

 

1. logging日誌模塊四大組件

在介紹logging模塊的日誌流處理流程以前,咱們先來介紹下logging模塊的四大組件:函數

組件名稱 對應類名 功能描述
日誌器 Logger 提供了應用程序可一直使用的接口
處理器 Handler 將logger建立的日誌記錄發送到合適的目的輸出
過濾器 Filter 提供了更細粒度的控制工具來決定輸出哪條日誌記錄,丟棄哪條日誌記錄
格式器 Formatter 決定日誌記錄的最終輸出格式

logging模塊就是經過這些組件來完成日誌處理的,上面所使用的logging模塊級別的函數也是經過這些組件對應的類來實現的。工具

這些組件之間的關係描述:
  • 日誌器(logger)須要經過處理器(handler)將日誌信息輸出到目標位置,如:文件、sys.stdout、網絡等;
  • 不一樣的處理器(handler)能夠將日誌輸出到不一樣的位置;
  • 日誌器(logger)能夠設置多個處理器(handler)將同一條日誌記錄輸出到不一樣的位置;
  • 每一個處理器(handler)均可以設置本身的過濾器(filter)實現日誌過濾,從而只保留感興趣的日誌;
  • 每一個處理器(handler)均可以設置本身的格式器(formatter)實現同一條日誌以不一樣的格式輸出到不一樣的地方。

簡單點說就是:日誌器(logger)是入口,真正幹活兒的是處理器(handler),處理器(handler)還能夠經過過濾器(filter)和格式器(formatter)對要輸出的日誌內容作過濾和格式化等處理操做。post

2. logging日誌模塊相關類及其經常使用方法介紹

下面介紹下與logging四大組件相關的類:Logger, Handler, Filter, Formatter。url

Logger類

Logger對象有3個任務要作:spa

  • 1)嚮應用程序代碼暴露幾個方法,使應用程序能夠在運行時記錄日誌消息;
  • 2)基於日誌嚴重等級(默認的過濾設施)或filter對象來決定要對哪些日誌進行後續處理;
  • 3)將日誌消息傳送給全部感興趣的日誌handlers。

Logger對象最經常使用的方法分爲兩類:配置方法 和 消息發送方法debug

最經常使用的配置方法以下:

方法 描述
Logger.setLevel() 設置日誌器將會處理的日誌消息的最低嚴重級別
Logger.addHandler() 和 Logger.removeHandler() 爲該logger對象添加 和 移除一個handler對象
Logger.addFilter() 和 Logger.removeFilter() 爲該logger對象添加 和 移除一個filter對象

關於Logger.setLevel()方法的說明:

內建等級中,級別最低的是DEBUG,級別最高的是CRITICAL。例如setLevel(logging.INFO),此時函數參數爲INFO,那麼該logger將只會處理INFO、WARNING、ERROR和CRITICAL級別的日誌,而DEBUG級別的消息將會被忽略/丟棄。

logger對象配置完成後,可使用下面的方法來建立日誌記錄:

方法 描述
Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical() 建立一個與它們的方法名對應等級的日誌記錄
Logger.exception() 建立一個相似於Logger.error()的日誌消息
Logger.log() 須要獲取一個明確的日誌level參數來建立一個日誌記錄

說明:

  • Logger.exception()與Logger.error()的區別在於:Logger.exception()將會輸出堆棧追蹤信息,另外一般只是在一個exception handler中調用該方法。
  • Logger.log()與Logger.debug()、Logger.info()等方法相比,雖然須要多傳一個level參數,顯得不是那麼方便,可是當須要記錄自定義level的日誌時仍是須要該方法來完成。

那麼,怎樣獲得一個Logger對象呢?一種方式是經過Logger類的實例化方法建立一個Logger類的實例,可是咱們一般都是用第二種方式--logging.getLogger()方法。

logging.getLogger()方法有一個可選參數name,該參數表示將要返回的日誌器的名稱標識,若是不提供該參數,則其值爲'root'。若以相同的name參數值屢次調用getLogger()方法,將會返回指向同一個logger對象的引用。

關於logger的層級結構與有效等級的說明:

  • logger的名稱是一個以'.'分割的層級結構,每一個'.'後面的logger都是'.'前面的logger的children,例如,有一個名稱爲 foo 的logger,其它名稱分別爲 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的後代。
  • logger有一個"有效等級(effective level)"的概念。若是一個logger上沒有被明確設置一個level,那麼該logger就是使用它parent的level;若是它的parent也沒有明確設置level則繼續向上查找parent的parent的有效level,依次類推,直到找到個一個明確設置了level的祖先爲止。須要說明的是,root logger老是會有一個明確的level設置(默認爲 WARNING)。當決定是否去處理一個已發生的事件時,logger的有效等級將會被用來決定是否將該事件傳遞給該logger的handlers進行處理。
  • child loggers在完成對日誌消息的處理後,默認會將日誌消息傳遞給與它們的祖先loggers相關的handlers。所以,咱們沒必要爲一個應用程序中所使用的全部loggers定義和配置handlers,只須要爲一個頂層的logger配置handlers,而後按照須要建立child loggers就可足夠了。咱們也能夠經過將一個logger的propagate屬性設置爲False來關閉這種傳遞機制。
Handler類

Handler對象的做用是(基於日誌消息的level)將消息分發到handler指定的位置(文件、網絡、郵件等)。Logger對象能夠經過addHandler()方法爲本身添加0個或者更多個handler對象。好比,一個應用程序可能想要實現如下幾個日誌需求:

  • 1)把全部日誌都發送到一個日誌文件中;
  • 2)把全部嚴重級別大於等於error的日誌發送到stdout(標準輸出);
  • 3)把全部嚴重級別爲critical的日誌發送到一個email郵件地址。
    這種場景就須要3個不一樣的handlers,每一個handler複雜發送一個特定嚴重級別的日誌到一個特定的位置。

一個handler中只有很是少數的方法是須要應用開發人員去關心的。對於使用內建handler對象的應用開發人員來講,彷佛惟一相關的handler方法就是下面這幾個配置方法:

方法 描述
Handler.setLevel() 設置handler將會處理的日誌消息的最低嚴重級別
Handler.setFormatter() 爲handler設置一個格式器對象
Handler.addFilter() 和 Handler.removeFilter() 爲handler添加 和 刪除一個過濾器對象

須要說明的是,應用程序代碼不該該直接實例化和使用Handler實例。由於Handler是一個基類,它只定義了素有handlers都應該有的接口,同時提供了一些子類能夠直接使用或覆蓋的默認行爲。下面是一些經常使用的Handler:

Handler 描述
logging.StreamHandler 將日誌消息發送到輸出到Stream,如std.out, std.err或任何file-like對象。
logging.FileHandler 將日誌消息發送到磁盤文件,默認狀況下文件大小會無限增加
logging.handlers.RotatingFileHandler 將日誌消息發送到磁盤文件,並支持日誌文件按大小切割
logging.hanlders.TimedRotatingFileHandler 將日誌消息發送到磁盤文件,並支持日誌文件按時間切割
logging.handlers.HTTPHandler 將日誌消息以GET或POST的方式發送給一個HTTP服務器
logging.handlers.SMTPHandler 將日誌消息發送給一個指定的email地址
logging.NullHandler 該Handler實例會忽略error messages,一般被想使用logging的library開發者使用來避免'No handlers could be found for logger XXX'信息的出現。
Formater類

Formater對象用於配置日誌信息的最終順序、結構和內容。與logging.Handler基類不一樣的是,應用代碼能夠直接實例化Formatter類。另外,若是你的應用程序須要一些特殊的處理行爲,也能夠實現一個Formatter的子類來完成。

Formatter類的構造方法定義以下:

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

可見,該構造方法接收3個可選參數:

  • fmt:指定消息格式化字符串,若是不指定該參數則默認使用message的原始值
  • datefmt:指定日期格式字符串,若是不指定該參數則默認使用"%Y-%m-%d %H:%M:%S"
  • style:Python 3.2新增的參數,可取值爲 '%', '{'和 '$',若是不指定該參數則默認使用'%'
Filter類

Filter能夠被Handler和Logger用來作比level更細粒度的、更復雜的過濾功能。Filter是一個過濾器基類,它只容許某個logger層級下的日誌事件經過過濾。該類定義以下:

class logging.Filter(name='') filter(record)

好比,一個filter實例化時傳遞的name參數值爲'A.B',那麼該filter實例將只容許名稱爲相似以下規則的loggers產生的日誌記錄經過過濾:'A.B','A.B,C','A.B.C.D','A.B.D',而名稱爲'A.BB', 'B.A.B'的loggers產生的日誌則會被過濾掉。若是name的值爲空字符串,則容許全部的日誌事件經過過濾。

filter方法用於具體控制傳遞的record記錄是否能經過過濾,若是該方法返回值爲0表示不能經過過濾,返回值爲非0表示能夠經過過濾。

說明:

  • 若是有須要,也能夠在filter(record)方法內部改變該record,好比添加、刪除或修改一些屬性。
  • 咱們還能夠經過filter作一些統計工做,好比能夠計算下被一個特殊的logger或handler所處理的record數量等。
參考目錄: 
相關文章
相關標籤/搜索