如何理解python接口自動化之logging日志模塊
前言:我們之前運(yùn)行代碼時(shí)都是將日志直接輸出到控制臺,而實(shí)際項(xiàng)目中常常需要把日志存儲到文件,便于查閱,如運(yùn)行時(shí)間、描述信息以及錯(cuò)誤或者異常發(fā)生時(shí)候的特定上下文信息。
Python中自帶的logging模塊提供了標(biāo)準(zhǔn)的日志接口,在debug時(shí)使用往往會事半功倍。為什么不直接使用print去輸出呢?這種方式對簡單的腳本來說有用,對于復(fù)雜的系統(tǒng)來說相當(dāng)于一個(gè)花瓶擺設(shè),大量的print輸出很容易被遺忘在代碼里,并且print是標(biāo)準(zhǔn)輸出,這很難從一堆信息里去判斷哪些是你需要重點(diǎn)關(guān)注的。
logging的優(yōu)勢就在于可以控制日志的級別,把不需要的信息進(jìn)行過濾,且可以決定它輸出到什么地方、如何輸出,還可以通過控制等級把特定等級的信息輸出到特定的位置等。logging一共分為四個(gè)部分:
Loggers:日志收集器,可供程序直接調(diào)用的接口,app通過調(diào)用提供的api來記錄日志 Handlers:日志處理器, 決定將日志記錄分配至正確的目的地 Filters:日志過濾器,對日志信息進(jìn)行過濾, 提供更細(xì)粒度的日志是否輸出的判斷 Formatters:日志格式器,制定最終記錄打印的格式布局二、日志等級logging將logger的等級劃分成5個(gè)level,由低到高分別是DEBUG、INFO、WARNING、ERROE、CRITICAL,默認(rèn)是WARNING級別,CRITICAL最高,相關(guān)等級說明如下:
Level 說明 DEBUG 輸出詳細(xì)的運(yùn)行信息,主要用于調(diào)試,追蹤問題時(shí)使用 INFO 輸出正常的運(yùn)行的信息,一切按預(yù)期進(jìn)行的情況 WARNING 一些意想不到的或即將會發(fā)生的情況,比如警告:內(nèi)存空間不足,但不影響程序運(yùn)行 ERROR 由于某些問題,程序的一些功能會受到影響,還可以繼續(xù)運(yùn)行 CRITICAL 一個(gè)嚴(yán)重的錯(cuò)誤,表明程序本身可能無法繼續(xù)運(yùn)行這些等級的日志中低包含高,比如INFO,會收集INFO及以上等級的日志,DEBUG等級的日志將不進(jìn)行收集。下面我們來輸出這5個(gè)等級的日志:
import logging'''logging模塊默認(rèn)收集的日志是warning以上等級的'''a = 100logging.debug(a)logging.info(’這是INFO等級的信息’)logging.warning(’這是WARNING等級的信息’)logging.error(’這是ERROR等級的信息’)logging.critical(’這是CRITICAL等級的信息’)
輸出結(jié)果:
C:softwarepythonpython.exe D:/learn/test.py
WARNING:root:這是WARNING等級的信息
ERROR:root:這是ERROR等級的信息
CRITICAL:root:這是CRITICAL等級的信息
Process finished with exit code 0
三、日志收集器日志是怎么被收集和輸出的呢?答案就是日志收集器,設(shè)置一個(gè)收集器,把指等級的日志信息輸出到指定的地方,控制臺或文件等,其工作過程大致如下:
logging中默認(rèn)的日志收集器是root,收集等級默認(rèn)是WARNING,我們可以通過setLevel來改變它的收集等級。
# 獲取默認(rèn)的日志收集器rootmy_log = logging.getLogger()# 設(shè)置默認(rèn)的日志收集器等級my_log.setLevel('DEBUG') # 日志將全部被收集a = 100logging.debug(a)logging.info(’這是INFO等級的信息’)logging.warning(’這是WARNING等級的信息’)logging.error(’這是ERROR等級的信息’)logging.critical(’這是CRITICAL等級的信息’)
輸出結(jié)果:
C:softwarepythonpython.exe D:/learn/test.py
DEBUG:root:100
INFO:root:這是INFO等級的信息
WARNING:root:這是WARNING等級的信息
ERROR:root:這是ERROR等級的信息
CRITICAL:root:這是CRITICAL等級的信息
Process finished with exit code 0
除了使用默認(rèn)的日志收集器,我們也可以自己創(chuàng)建一個(gè)收集器logging.getLogger,如下:
import loggingmy_logger = logging.getLogger(’my_logger’)# 創(chuàng)建logging對象my_logger.setLevel(’INFO’)# 設(shè)置日志收集等級a = 100logging.debug(a)logging.info(’這是INFO等級的信息’)logging.warning(’這是WARNING等級的信息’)logging.error(’這是ERROR等級的信息’)logging.critical(’這是CRITICAL等級的信息’)
輸出結(jié)果:
C:softwarepythonpython.exe D:/learn/test.py
WARNING:root:這是WARNING等級的信息
ERROR:root:這是ERROR等級的信息
CRITICAL:root:這是CRITICAL等級的信息
Process finished with exit code 0
四、日志處理器上面例子中設(shè)置的收集器都是輸出到控制臺,除此我們還可以輸出到文件中。
Handlers(處理器)的作用就是將logger發(fā)過來的信息進(jìn)行準(zhǔn)確地分配,送往正確的地方。比如,送往控制臺、文件或者是兩者。它決定了每個(gè)日志收集器的行為,是創(chuàng)建收集器之后需要配置的重點(diǎn)區(qū)域。每個(gè)Handler同樣有一個(gè)日志級別,一個(gè)logger可以擁有多個(gè)handler也就是說logger可以根據(jù)不同的日志級別將日志傳遞給不同的handler。當(dāng)然也可以相同的級別傳遞給多個(gè)handler,這就根據(jù)需求來靈活的配置了。
下面實(shí)例中設(shè)置了兩個(gè)handler,一個(gè)是輸出到控制臺,一個(gè)是輸出到文件中。關(guān)鍵代碼:
logging.StreamHandler:輸出到控制臺的處理器 logging.FileHandler:輸出到文件的處理器 addHandler:添加處理器 removeHandler:移除處理器import loggingmy_logger = logging.getLogger(’my_logger’)my_logger.setLevel(’INFO’)# 創(chuàng)建一個(gè)輸出到控制臺的處理器sh = logging.StreamHandler()sh.setLevel('ERROR') # 設(shè)置處理器的輸出等級my_logger.addHandler(sh) # 將處理器綁定到日志收集器上# 創(chuàng)建一個(gè)輸出到文件的處理器fh = logging.FileHandler('logs.logs', encoding='utf8')fh.setLevel('INFO')my_logger.addHandler(fh)# my_logger.removeHandler(fh)# 移除處理器a = 100my_logger.debug(a)my_logger.info(’這是INFO等級的信息’)my_logger.warning(’這是WARNING等級的信息’)my_logger.error(’這是ERROR等級的信息’)my_logger.critical(’這是CRITICAL等級的信息’)
運(yùn)行結(jié)果:
C:softwarepythonpython.exe D:/learn/test.py
這是ERROR等級的信息
這是CRITICAL等級的信息
Process finished with exit code 0
Filters可以實(shí)現(xiàn)比level更復(fù)雜的過濾功能,限制只有滿足過濾規(guī)則的日志才會被輸出。比如我們定義了filter = logging.Filter(’A.B’),并將這個(gè)Filter添加到了一個(gè)Handler上,則使用該Handler的Logger中只有名字帶A.B前綴的Logger才能輸出其日志。下面是一個(gè)簡單實(shí)例:
import logging# 這是logger1my_logger = logging.getLogger(’A.C,B’)my_logger.setLevel(’INFO’)# 這是logger2my_logger2 = logging.getLogger(’A.B’)my_logger2.setLevel(’INFO’)# 創(chuàng)建一個(gè)處理器,兩個(gè)logger都使用這個(gè)處理器sh = logging.StreamHandler()sh.setLevel('ERROR')my_logger.addHandler(sh)my_logger2.addHandler(sh)# 創(chuàng)建一個(gè)過濾器綁到處理器上my_filter = logging.Filter(name=’A.B’)sh.addFilter(my_filter) # 把過濾器添加到處理器上# sh2.removeFilter(my_filter) # 移除過濾器my_logger.debug(’這是logger1-DEBUG等級的信息’)my_logger.info(’這是logger1-INFO等級的信息’)my_logger.warning(’這是logger1-WARNING等級的信息’)my_logger.error(’這是logger1-ERROR等級的信息’)my_logger.critical(’這是logger1-CRITICAL等級的信息’)my_logger2.debug(’這是logger2-DEBUG等級的信息’)my_logger2.info(’這是logger2-INFO等級的信息’)my_logger2.warning(’這是logger2-WARNING等級的信息’)my_logger2.error(’這是logger2-ERROR等級的信息’)my_logger2.critical(’這是logger2-CRITICAL等級的信息’)
因?yàn)橹挥衛(wèi)ogger2滿足過濾器的條件,因此只會輸出logger2的日志,運(yùn)行結(jié)果如下:
C:softwarepythonpython.exe D:/learn/test.py
這是logger2-ERROR等級的信息
這是logger2-CRITICAL等級的信息
Process finished with exit code 0
filter方法用于具體控制傳遞的record記錄是否能通過過濾,如果該方法返回值為0表示不能通過過濾,非0表示可以通過過濾。
六、日志格式器顧名思義,對日志進(jìn)行格式化,因?yàn)槌R?guī)的日志輸出并不直觀美觀,通過美化日志的輸出格式,可以讓我們閱讀起來更加舒服。
format常用格式如下:
%(name)s: 打印收集器名稱 %(levelno)s: 打印日志級別的數(shù)值 %(levelname)s: 打印日志級別名稱 %(pathname)s: 打印當(dāng)前執(zhí)行程序的路徑,其實(shí)就是sys.argv[0] %(filename)s: 打印當(dāng)前執(zhí)行程序名 %(funcName)s: 打印日志的當(dāng)前函數(shù) %(lineno)d: 打印日志的當(dāng)前行號 %(asctime)s: 打印日志的時(shí)間 %(thread)d: 打印線程ID %(threadName)s: 打印線程名稱 %(process)d: 打印進(jìn)程ID %(message)s: 打印日志信息import loggingmy_logger = logging.getLogger(’A.C,B’)my_logger.setLevel(’INFO’)# 創(chuàng)建一個(gè)處理器sh = logging.StreamHandler()sh.setLevel('ERROR')my_logger.addHandler(sh)# 設(shè)置一個(gè)格式,并設(shè)置到處理器上formatter = logging.Formatter(’%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s’)sh.setFormatter(formatter)my_logger.debug(’這是logger1-DEBUG等級的信息’)my_logger.info(’這是logger1-INFO等級的信息’)my_logger.warning(’這是logger1-WARNING等級的信息’)my_logger.error(’這是logger1-ERROR等級的信息’)my_logger.critical(’這是logger1-CRITICAL等級的信息’)
運(yùn)行結(jié)果:
C:softwarepythonpython.exe D:/learn/test.py
2020-08-01 18:28:43,645 - [test.py-->line:17] - ERROR: 這是logger1-ERROR等級的信息
2020-08-01 18:28:43,645 - [test.py-->line:18] - CRITICAL: 這是logger1-CRITICAL等級的信息
Process finished with exit code 0
七、日志滾動如果你用 FileHandler 存儲日志,文件的大小會隨著時(shí)間推移而不斷增大,最終有一天它會占滿你所有的磁盤空間。Python 的 logging 模塊提供了兩個(gè)支持日志滾動的 FileHandler 類,分別是 RotatingFileHandler 和 TimedRotatingFileHandler,它就可以解決這個(gè)尷尬的問題。
RotatingFileHandler 的滾動時(shí)刻是日志文件的大小達(dá)到一定值,當(dāng)達(dá)到指定值的時(shí)候,RotatingFileHandler會將日志文件重命名存檔,然后打開一個(gè)新的日志文件。 TimedRotatingFileHandler 是當(dāng)某個(gè)時(shí)刻到來時(shí)就進(jìn)行滾動,同 RotatingFileHandler 一樣,當(dāng)滾動時(shí)機(jī)來臨時(shí),TimedRotatingFileHandler 會將日志文件重命名存檔,然后打開一個(gè)新的日志文件。在實(shí)際應(yīng)用中,我們通常會根據(jù)時(shí)間進(jìn)行滾動,以下實(shí)例也以時(shí)間滾動為例,按大小滾動的同理:
import loggingfrom logging.handlers import TimedRotatingFileHandlermy_logger = logging.getLogger(’A.C,B’)my_logger.setLevel(’INFO’)# 創(chuàng)建一個(gè)處理器,使用時(shí)間滾動的文件處理器log_file_handler = TimedRotatingFileHandler(filename=’log.log’, when=’D’, interval=1, backupCount=10)# log_file_handler.suffix = '%Y-%m-%d'# log_file_handler.extMatch = re.compile(r'^d{4}-d{2}-d{2}.log$')log_file_handler.setLevel('ERROR')my_logger.addHandler(log_file_handler)# 設(shè)置一個(gè)格式,并設(shè)置到處理器上formatter = logging.Formatter(’%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s’)log_file_handler.setFormatter(formatter)my_logger.debug(’這是logger1-DEBUG等級的信息’)my_logger.info(’這是logger1-INFO等級的信息’)my_logger.warning(’這是logger1-WARNING等級的信息’)my_logger.error(’這是logger1-ERROR等級的信息’)my_logger.critical(’這是logger1-CRITICAL等級的信息’)
參數(shù)說明:
filename:日志文件名;
when:是一個(gè)字符串,用于描述滾動周期的基本單位,字符串的值及意義如下:
S - Seconds M - Minutes H - Hours D - Days midnight - roll over at midnight W{0-6} - roll over on a certain day; 0 - Mondayinterval: 滾動周期,單位由when指定,比如:when=’D’,interval=1,表示每天產(chǎn)生一個(gè)日志文件;
backupCount: 表示日志文件的保留個(gè)數(shù);
除了上述參數(shù)之外,TimedRotatingFileHandler還有兩個(gè)比較重要的成員變量,它們分別是suffix和extMatch。suffix是指日志文件名的后綴,suffix中通常帶有格式化的時(shí)間字符串,filename和suffix由“.”連接構(gòu)成文件名(例如:filename='test', suffix='%Y-%m-%d.log',生成的文件名為test.2020-08-01.log。extMatch是一個(gè)編譯好的正則表達(dá)式,用于匹配日志文件名的后綴,它必須和suffix是匹配的,如果suffix和extMatch匹配不上的話,過期的日志是不會被刪除的。比如,suffix=“%Y-%m-%d.log”, extMatch的只能是re.compile(r'^d{4}-d{2}-d{2}.log$')。默認(rèn)情況下,在TimedRotatingFileHandler對象初始化時(shí),suffxi和extMatch會根據(jù)when的值進(jìn)行初始化:
S:suffix='%Y-%m-%d_%H-%M-%S',extMatch=r'^d{4}-d{2}-d{2}_d{2}-d{2}-d{2}';M:suffix='%Y-%m-%d_%H-%M',extMatch=r'^d{4}-d{2}-d{2}_d{2}-d{2}';H:suffix='%Y-%m-%d_%H',extMatch=r'^d{4}-d{2}-d{2}_d{2}';D:suffxi='%Y-%m-%d',extMatch=r'^d{4}-d{2}-d{2}';MIDNIGHT:'%Y-%m-%d',extMatch=r'^d{4}-d{2}-d{2}';W:'%Y-%m-%d',extMatch=r'^d{4}-d{2}-d{2}';
如果對日志文件名沒有特殊要求的話,可以不用設(shè)置suffix和extMatch,如果需要,一定要讓它們匹配上。
八、模塊封裝一次封裝,一勞永逸,之后直接調(diào)用即可,封裝內(nèi)容按需。
import loggingfrom logging.handlers import TimedRotatingFileHandlerclass MyLogger(object): @staticmethod def create_logger():my_logger = logging.getLogger('my_logger')my_logger.setLevel('DEBUG')# 控制臺處理器stream_handler = logging.StreamHandler()stream_handler.setLevel('ERROR')my_logger.addHandler(stream_handler)# 使用時(shí)間滾動的文件處理器log_file_handler = TimedRotatingFileHandler(filename=’log.log’, when=’D’, interval=1, backupCount=10)log_file_handler.setLevel('INFO')my_logger.addHandler(log_file_handler)formatter = logging.Formatter(’%(asctime)s - [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s’)stream_handler.setFormatter(formatter)log_file_handler.setFormatter(formatter)return my_logger
以上就是如何理解python接口自動化之logging日志模塊的詳細(xì)內(nèi)容,更多關(guān)于python 接口自動化 logging日志模塊的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. ASP刪除img標(biāo)簽的style屬性只保留src的正則函數(shù)2. 詳解CSS偽元素的妙用單標(biāo)簽之美3. XML入門的常見問題(一)4. XML入門的常見問題(四)5. 詳解JS前端使用迭代器和生成器原理及示例6. HTML DOM setInterval和clearInterval方法案例詳解7. html小技巧之td,div標(biāo)簽里內(nèi)容不換行8. 使用css實(shí)現(xiàn)全兼容tooltip提示框9. ASP中格式化時(shí)間短日期補(bǔ)0變兩位長日期的方法10. 詳解PHP實(shí)現(xiàn)HTTP服務(wù)器過程
