Python logging模塊

logging模塊簡介

logging模塊是Python的一個標準庫模塊,開發過程中,可以通過該模塊,靈活的完成日誌的記錄。

logging模塊提供了兩種記錄日誌的方式:
    1)使用logging提供的模塊級別的函數(logging.basicConfig,logging.debug,logging.info...)
    2)使用logging模塊的組件(loggers,handlers,filters,formatters)

下面會分別介紹這兩種方式,這裏建議使用第二種方式,使用 logging模塊的組件可以更靈活的完成日誌記錄~

logging模塊的日誌級別

logging模塊的日誌級別(level)包括:DEBUG,INFO,WARNING,ERROR,CRITICAL~

日誌級別(level) 描述
DEBUG 調試級別,一般用於問題的排查,日誌的信息最爲詳細
INFO 僅記錄普通的信息,日誌信息的詳細程度僅次於DEBUG
WARNING 警告信息,一般這類信息不會影響程序的正常運行
ERROR 錯誤信息, 出現錯誤信息時,程序一般已不能正常運行
CRITICAL 更嚴重的錯誤信息,程序不能繼續運行

從 DEBUG 到 CRITICAL,日誌等級依次提高,即嚴重性逐步提升,日誌的信息量依次減少:
DEBUG < INFO < WARNING < ERROR < CRITICAL

通過logging模塊級別的函數記錄日誌

示例如下:

import logging  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')  

輸出結果:
WARNING:root:warning message     # 默認的日誌格式:日誌級別 : Logger名稱 : 用戶輸出消息。
ERROR:root:error message
CRITICAL:root:critical message

這裏僅輸出了大於等於WARNING級別的日誌,說明 logging模塊 默認的日誌級別爲WARNING,即日誌級別大於等於WARNING的纔會被輸出,且默認情況下,日誌會直接打印到標準輸出中~
 
通過 logging模塊 的basicConfig函數可靈活地配置日誌級別,日誌格式以及日誌的輸出位置:

import logging

logging.basicConfig(level=logging.DEBUG, 
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                       # 日誌格式
                    datefmt='%Y-%m-%d %H:%M:%S',    # 時間格式:2018-11-12 23:50:21
                    filename='/tmp/test.log',    # 日誌的輸出路徑
                    filemode='a')                      # 追加模式

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

程序運行後,日誌信息會直接記錄到 指定的文件中(/tmp/test.log),且日誌級別爲DEBUG,所以所有的日誌都會被輸出,日誌信息如下:

➜  ~ cat /tmp/test.log

2018-11-12 23:50:49 test.py[line:9] DEBUG debug message
2018-11-12 23:50:49 test.py[line:10] INFO info message
2018-11-12 23:50:49 test.py[line:11] WARNING warning message
2018-11-12 23:50:49 test.py[line:12] ERROR error message
2018-11-12 23:50:49 test.py[line:13] CRITICAL critical message

 
logging.basicConfig()函數中可通過具體參數來更改logging模塊默認行爲,可用參數有:

filename:用指定的文件名創建FiledHandler,這樣日誌會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲“a”還可指定爲“w”。
format:指定handler使用的日誌顯示格式。
datefmt:指定日期時間格式。
level:設置rootlogger(後邊會講解具體概念)的日誌級別
stream:用指定的stream創建StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默認爲sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。
 
format參數中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 數字形式的日誌級別
%(levelname)s 文本形式的日誌級別
%(pathname)s 調用日誌輸出函數的模塊的完整路徑名,可能沒有
%(filename)s 調用日誌輸出函數的模塊的文件名
%(module)s 調用日誌輸出函數的模塊名
%(funcName)s 調用日誌輸出函數的函數名
%(lineno)d 調用日誌輸出函數的語句所在的代碼行
%(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌信息時的,自Logger創建以 來的毫秒數
%(asctime)s 字符串形式的當前時間。默認格式是 “2018-11-13 00:00:00,896”。逗號後面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s用戶輸出的消息

通過logging模塊的組件記錄日誌

使用logging模塊級別的函數記錄日誌,無法實現將日誌輸出到多個路徑下。這裏logging模塊提供了4個組件,通過這些組件可實現將日誌輸出到多個路徑下,且每個路徑下的日誌格式可單獨配置~

logging模塊中用於記錄日誌的4大組件

組件名稱 功能描述
Logger 日誌器,提供了應用程序可一直使用的接口
Handler 將 logger 產生的日誌發送到指定的路徑下(例如可以是終端,也可以是文件)
Filter 若有多個 Logger,可根據名稱過濾出指定的 Logger 來記錄日誌
Formatter 定義日誌格式

logging模塊組件的使用

使用組件記錄日誌的大致步驟如下:
1)logging.getLogger() 獲取 logger對象
2)創建一個或多個 handler,用於指定日誌信息的輸出流向
3)創建一個或多個 formatter,指定日誌的格式,並分別將 formatter 綁定到 上
4)將 handler 綁定到 logger對象 上
5)logger.setLevel(logging.DEBUG) 設置日誌級別
5)最後便可使用 logger對象 記錄日誌~
 
示例

import logging

# 獲取 logger對象
logger = logging.getLogger()

# 創建一個 handler,用於寫入日誌文件
fh = logging.FileHandler('/tmp/test.log')

# 再創建一個 handler,用於輸出到控制檯
ch = logging.StreamHandler()

# 創建一個 formatter,兩個 handler 使用相同的日誌格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 綁定 formatter 到 handler 上
fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 綁定 handler 到 logger對象 上
logger.addHandler(fh) #logger對象可以添加多個fh和ch對象
logger.addHandler(ch)

# 設置日誌級別
logger.setLevel(logging.WARNING)

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')

查看輸出結果:

終端輸出:
2018-11-13 23:14:09,161 - root - WARNING - logger warning message
2018-11-13 23:14:09,161 - root - ERROR - logger error message
2018-11-13 23:14:09,161 - root - CRITICAL - logger critical message

文件輸出:
➜  ~ cat /tmp/test.log
2018-11-13 23:14:09,161 - root - WARNING - logger warning message
2018-11-13 23:14:09,161 - root - ERROR - logger error message
2018-11-13 23:14:09,161 - root - CRITICAL - logger critical message

也可以通過 handler 來設置日誌級別,當使用 handler 來設置日誌級別時,存在如下兩種情況:
   1)若 handler 設置的日誌級別小於等於 logger 的日誌級別時,則以logger 的日誌級別爲準;
   2)若 handler 設置的日誌級別大於 logger 的日誌級別時,則以handler 的日誌級別爲準;
簡單而言就是,兩者同時設置日誌級別,以日誌級別高的爲準。由於不設置 logger 的日誌級別,其默認日誌級別就是 WARNING,所以不存在 handler 單獨設置日誌級別的情況~

通過示例來驗證:
1)logger 日誌級別設置爲 DEBUG,logger 不設置(默認爲WARNING)

import logging

logger = logging.getLogger()
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

ch.setLevel(logging.DEBUG)
# logger.setLevel(logging.CRITICAL)

ch.setFormatter(formatter)
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')

輸出結果:
2018-11-13 23:40:13,829 - root - WARNING - logger warning message
2018-11-13 23:40:13,829 - root - ERROR - logger error message
2018-11-13 23:40:13,829 - root - CRITICAL - logger critical message

2)logger 日誌級別設置爲 CRITICAL,logger 設置爲 ERROR

import logging

logger = logging.getLogger()
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

ch.setLevel(logging.CRITICAL)
logger.setLevel(logging.ERROR)

ch.setFormatter(formatter)
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')

輸出結果:
2018-11-13 23:41:51,279 - root - CRITICAL - logger critical message

filter組件 的使用

filter組件用來過濾 logger 對象,一個 filter 可以直接添加到 logger對象上,也可以添加到 handler 對象上。
 
例如,定義一個filter: filter = logging.Filter('a.b'),當把這個 filter 添加到一個 handler 上,那麼綁定了該 handler 的 多個 logger對象中,只有名字是 'a.b' 前綴的才能通過該 handler 輸出日誌~
 
在 handler 上添加 filter:

import logging

logger1 = logging.getLogger('a.b.c')
logger2 = logging.getLogger('a.c')

# 定義一個 filter
filter = logging.Filter(name='a.b')

# 定義一個 handler
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)

# 若兩個 logger對象 的日誌級別相同,且都是用通過一個 handler,可以在這個 handler 上設置日誌級別
ch.setLevel(logging.ERROR)

# 在 handler 上放置過濾器
ch.addFilter(filter)

logger1.addHandler(ch)
logger2.addHandler(ch)
logger1.error('logger1 error message')
logger2.error('logger2 error message')

輸出結果:
2018-11-15 21:58:33,409 - a.b.c - ERROR - logger1 error message

可以看到 logger2 被過濾,只有 logger1 輸出日誌~
 
在 handler 上添加 filter:

import logging

logger1 = logging.getLogger('a.b.c')
logger2 = logging.getLogger('a.c')

# 定義一個 filter
filter = logging.Filter(name='a.b')

# 定義一個 handler
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)

# 若兩個 logger對象 的日誌級別相同,且都是用通過一個 handler,可以在這個 handler 上設置日誌級別
ch.setLevel(logging.ERROR)

# 在 logger 上放置過濾器
logger1.addFilter(filter)
logger2.addFilter(filter)

logger1.addHandler(ch)
logger2.addHandler(ch)
logger1.error('logger1 error message')
logger2.error('logger2 error message')

輸出結果一致,即僅有 logger1 輸出日誌。將 filter 添加到 logger 上,這個filter將直接作用於這個 logger,貌似這麼意義不大,很少這樣使用

.................^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章