溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python接口自動(dòng)化之logging日志模塊分析

發(fā)布時(shí)間:2021-06-15 17:11:24 來(lái)源:億速云 閱讀:148 作者:chen 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“python接口自動(dòng)化之logging日志模塊分析”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、logging模塊介紹

前言:我們之前運(yùn)行代碼時(shí)都是將日志直接輸出到控制臺(tái),而實(shí)際項(xiàng)目中常常需要把日志存儲(chǔ)到文件,便于查閱,如運(yùn)行時(shí)間、描述信息以及錯(cuò)誤或者異常發(fā)生時(shí)候的特定上下文信息。

Python中自帶的logging模塊提供了標(biāo)準(zhǔn)的日志接口,在debug時(shí)使用往往會(huì)事半功倍。為什么不直接使用print去輸出呢?這種方式對(duì)簡(jiǎn)單的腳本來(lái)說(shuō)有用,對(duì)于復(fù)雜的系統(tǒng)來(lái)說(shuō)相當(dāng)于一個(gè)花瓶擺設(shè),大量的print輸出很容易被遺忘在代碼里,并且print是標(biāo)準(zhǔn)輸出,這很難從一堆信息里去判斷哪些是你需要重點(diǎn)關(guān)注的。

logging的優(yōu)勢(shì)就在于可以控制日志的級(jí)別,把不需要的信息進(jìn)行過(guò)濾,且可以決定它輸出到什么地方、如何輸出,還可以通過(guò)控制等級(jí)把特定等級(jí)的信息輸出到特定的位置等。logging一共分為四個(gè)部分:

  • Loggers:日志收集器,可供程序直接調(diào)用的接口,app通過(guò)調(diào)用提供的api來(lái)記錄日志

  • Handlers:日志處理器, 決定將日志記錄分配至正確的目的地

  • Filters:日志過(guò)濾器,對(duì)日志信息進(jìn)行過(guò)濾, 提供更細(xì)粒度的日志是否輸出的判斷

  • Formatters:日志格式器,制定最終記錄打印的格式布局

二、日志等級(jí)

logging將logger的等級(jí)劃分成5個(gè)level,由低到高分別是DEBUG、INFO、WARNING、ERROE、CRITICAL,默認(rèn)是WARNING級(jí)別,CRITICAL最高,相關(guān)等級(jí)說(shuō)明如下:

Level說(shuō)明
DEBUG輸出詳細(xì)的運(yùn)行信息,主要用于調(diào)試,追蹤問(wèn)題時(shí)使用
INFO輸出正常的運(yùn)行的信息,一切按預(yù)期進(jìn)行的情況
WARNING一些意想不到的或即將會(huì)發(fā)生的情況,比如警告:內(nèi)存空間不足,但不影響程序運(yùn)行
ERROR由于某些問(wèn)題,程序的一些功能會(huì)受到影響,還可以繼續(xù)運(yùn)行
CRITICAL一個(gè)嚴(yán)重的錯(cuò)誤,表明程序本身可能無(wú)法繼續(xù)運(yùn)行

這些等級(jí)的日志中低包含高,比如INFO,會(huì)收集INFO及以上等級(jí)的日志,DEBUG等級(jí)的日志將不進(jìn)行收集。下面我們來(lái)輸出這5個(gè)等級(jí)的日志:

import logging

"""
logging模塊默認(rèn)收集的日志是warning以上等級(jí)的

"""

a = 100
logging.debug(a)
logging.info('這是INFO等級(jí)的信息')
logging.warning('這是WARNING等級(jí)的信息')
logging.error('這是ERROR等級(jí)的信息')
logging.critical('這是CRITICAL等級(jí)的信息')

輸出結(jié)果:

C:\software\python\python.exe D:/learn/test.py

WARNING:root:這是WARNING等級(jí)的信息

ERROR:root:這是ERROR等級(jí)的信息

CRITICAL:root:這是CRITICAL等級(jí)的信息

Process finished with exit code 0

三、日志收集器

日志是怎么被收集和輸出的呢?答案就是日志收集器,設(shè)置一個(gè)收集器,把指等級(jí)的日志信息輸出到指定的地方,控制臺(tái)或文件等,其工作過(guò)程大致如下:

python接口自動(dòng)化之logging日志模塊分析

logging中默認(rèn)的日志收集器是root,收集等級(jí)默認(rèn)是WARNING,我們可以通過(guò)setLevel來(lái)改變它的收集等級(jí)。

# 獲取默認(rèn)的日志收集器root
my_log = logging.getLogger()
# 設(shè)置默認(rèn)的日志收集器等級(jí)
my_log.setLevel("DEBUG")  # 日志將全部被收集

a = 100
logging.debug(a)
logging.info('這是INFO等級(jí)的信息')
logging.warning('這是WARNING等級(jí)的信息')
logging.error('這是ERROR等級(jí)的信息')
logging.critical('這是CRITICAL等級(jí)的信息')

輸出結(jié)果:

C:\software\python\python.exe D:/learn/test.py

DEBUG:root:100

INFO:root:這是INFO等級(jí)的信息

WARNING:root:這是WARNING等級(jí)的信息

ERROR:root:這是ERROR等級(jí)的信息

CRITICAL:root:這是CRITICAL等級(jí)的信息


Process finished with exit code 0


除了使用默認(rèn)的日志收集器,我們也可以自己創(chuàng)建一個(gè)收集器logging.getLogger,如下:

import logging

my_logger = logging.getLogger('my_logger')	# 創(chuàng)建logging對(duì)象
my_logger.setLevel('INFO')	# 設(shè)置日志收集等級(jí)

a = 100
logging.debug(a)
logging.info('這是INFO等級(jí)的信息')
logging.warning('這是WARNING等級(jí)的信息')
logging.error('這是ERROR等級(jí)的信息')
logging.critical('這是CRITICAL等級(jí)的信息')

輸出結(jié)果:

C:\software\python\python.exe D:/learn/test.py

WARNING:root:這是WARNING等級(jí)的信息

ERROR:root:這是ERROR等級(jí)的信息

CRITICAL:root:這是CRITICAL等級(jí)的信息


Process finished with exit code 0

四、日志處理器

上面例子中設(shè)置的收集器都是輸出到控制臺(tái),除此我們還可以輸出到文件中。

Handlers(處理器)的作用就是將logger發(fā)過(guò)來(lái)的信息進(jìn)行準(zhǔn)確地分配,送往正確的地方。比如,送往控制臺(tái)、文件或者是兩者。它決定了每個(gè)日志收集器的行為,是創(chuàng)建收集器之后需要配置的重點(diǎn)區(qū)域。每個(gè)Handler同樣有一個(gè)日志級(jí)別,一個(gè)logger可以擁有多個(gè)handler也就是說(shuō)logger可以根據(jù)不同的日志級(jí)別將日志傳遞給不同的handler。當(dāng)然也可以相同的級(jí)別傳遞給多個(gè)handler,這就根據(jù)需求來(lái)靈活的配置了。

下面實(shí)例中設(shè)置了兩個(gè)handler,一個(gè)是輸出到控制臺(tái),一個(gè)是輸出到文件中。關(guān)鍵代碼:

  • logging.StreamHandler:輸出到控制臺(tái)的處理器

  • logging.FileHandler:輸出到文件的處理器

  • addHandler:添加處理器

  • removeHandler:移除處理器

import logging

my_logger = logging.getLogger('my_logger')
my_logger.setLevel('INFO')

# 創(chuàng)建一個(gè)輸出到控制臺(tái)的處理器
sh = logging.StreamHandler()
sh.setLevel("ERROR")    # 設(shè)置處理器的輸出等級(jí)
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 = 100
my_logger.debug(a)
my_logger.info('這是INFO等級(jí)的信息')
my_logger.warning('這是WARNING等級(jí)的信息')
my_logger.error('這是ERROR等級(jí)的信息')
my_logger.critical('這是CRITICAL等級(jí)的信息')

運(yùn)行結(jié)果:

C:\software\python\python.exe D:/learn/test.py

這是ERROR等級(jí)的信息

這是CRITICAL等級(jí)的信息


Process finished with exit code 0

python接口自動(dòng)化之logging日志模塊分析

五、日志過(guò)濾器

Filters可以實(shí)現(xiàn)比level更復(fù)雜的過(guò)濾功能,限制只有滿足過(guò)濾規(guī)則的日志才會(huì)被輸出。比如我們定義了filter = logging.Filter('A.B'),并將這個(gè)Filter添加到了一個(gè)Handler上,則使用該Handler的Logger中只有名字帶A.B前綴的Logger才能輸出其日志。下面是一個(gè)簡(jiǎn)單實(shí)例:

import logging

# 這是logger1
my_logger = logging.getLogger('A.C,B')
my_logger.setLevel('INFO')

# 這是logger2
my_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è)過(guò)濾器綁到處理器上
my_filter = logging.Filter(name='A.B')
sh.addFilter(my_filter)    # 把過(guò)濾器添加到處理器上
# sh3.removeFilter(my_filter)   # 移除過(guò)濾器

my_logger.debug('這是logger1-DEBUG等級(jí)的信息')
my_logger.info('這是logger1-INFO等級(jí)的信息')
my_logger.warning('這是logger1-WARNING等級(jí)的信息')
my_logger.error('這是logger1-ERROR等級(jí)的信息')
my_logger.critical('這是logger1-CRITICAL等級(jí)的信息')

my_logger2.debug('這是logger2-DEBUG等級(jí)的信息')
my_logger2.info('這是logger2-INFO等級(jí)的信息')
my_logger2.warning('這是logger2-WARNING等級(jí)的信息')
my_logger2.error('這是logger2-ERROR等級(jí)的信息')
my_logger2.critical('這是logger2-CRITICAL等級(jí)的信息')

因?yàn)橹挥衛(wèi)ogger2滿足過(guò)濾器的條件,因此只會(huì)輸出logger2的日志,運(yùn)行結(jié)果如下:

C:\software\python\python.exe D:/learn/test.py

這是logger2-ERROR等級(jí)的信息

這是logger2-CRITICAL等級(jí)的信息


Process finished with exit code 0

filter方法用于具體控制傳遞的record記錄是否能通過(guò)過(guò)濾,如果該方法返回值為0表示不能通過(guò)過(guò)濾,非0表示可以通過(guò)過(guò)濾。

六、日志格式器

顧名思義,對(duì)日志進(jìn)行格式化,因?yàn)槌R?guī)的日志輸出并不直觀美觀,通過(guò)美化日志的輸出格式,可以讓我們閱讀起來(lái)更加舒服。

format常用格式如下:

  • %(name)s: 打印收集器名稱

  • %(levelno)s: 打印日志級(jí)別的數(shù)值

  • %(levelname)s: 打印日志級(jí)別名稱

  • %(pathname)s: 打印當(dāng)前執(zhí)行程序的路徑,其實(shí)就是sys.argv[0]

  • %(filename)s: 打印當(dāng)前執(zhí)行程序名

  • %(funcName)s: 打印日志的當(dāng)前函數(shù)

  • %(lineno)d: 打印日志的當(dāng)前行號(hào)

  • %(asctime)s: 打印日志的時(shí)間

  • %(thread)d: 打印線程ID

  • %(threadName)s: 打印線程名稱

  • %(process)d: 打印進(jìn)程ID

  • %(message)s: 打印日志信息

import logging

my_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等級(jí)的信息')
my_logger.info('這是logger1-INFO等級(jí)的信息')
my_logger.warning('這是logger1-WARNING等級(jí)的信息')
my_logger.error('這是logger1-ERROR等級(jí)的信息')
my_logger.critical('這是logger1-CRITICAL等級(jí)的信息')

運(yùn)行結(jié)果:

C:\software\python\python.exe D:/learn/test.py

2020-08-01 18:28:43,645 - [test.py-->line:17] - ERROR: 這是logger1-ERROR等級(jí)的信息

2020-08-01 18:28:43,645 - [test.py-->line:18] - CRITICAL: 這是logger1-CRITICAL等級(jí)的信息


Process finished with exit code 0


七、日志滾動(dòng)

如果你用 FileHandler 存儲(chǔ)日志,文件的大小會(huì)隨著時(shí)間推移而不斷增大,最終有一天它會(huì)占滿你所有的磁盤空間。Python 的 logging 模塊提供了兩個(gè)支持日志滾動(dòng)的 FileHandler 類,分別是 RotatingFileHandler 和 TimedRotatingFileHandler,它就可以解決這個(gè)尷尬的問(wèn)題。

  • RotatingFileHandler 的滾動(dòng)時(shí)刻是日志文件的大小達(dá)到一定值,當(dāng)達(dá)到指定值的時(shí)候,RotatingFileHandler會(huì)將日志文件重命名存檔,然后打開一個(gè)新的日志文件。

  • TimedRotatingFileHandler 是當(dāng)某個(gè)時(shí)刻到來(lái)時(shí)就進(jìn)行滾動(dòng),同 RotatingFileHandler 一樣,當(dāng)滾動(dòng)時(shí)機(jī)來(lái)臨時(shí),TimedRotatingFileHandler 會(huì)將日志文件重命名存檔,然后打開一個(gè)新的日志文件。

在實(shí)際應(yīng)用中,我們通常會(huì)根據(jù)時(shí)間進(jìn)行滾動(dòng),以下實(shí)例也以時(shí)間滾動(dòng)為例,按大小滾動(dòng)的同理:

import logging
from logging.handlers import TimedRotatingFileHandler

my_logger = logging.getLogger('A.C,B')
my_logger.setLevel('INFO')

# 創(chuàng)建一個(gè)處理器,使用時(shí)間滾動(dòng)的文件處理器
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等級(jí)的信息')
my_logger.info('這是logger1-INFO等級(jí)的信息')
my_logger.warning('這是logger1-WARNING等級(jí)的信息')
my_logger.error('這是logger1-ERROR等級(jí)的信息')
my_logger.critical('這是logger1-CRITICAL等級(jí)的信息')

參數(shù)說(shuō)明:

filename:日志文件名;

when:是一個(gè)字符串,用于描述滾動(dòng)周期的基本單位,字符串的值及意義如下:

  • S - Seconds

  • M - Minutes

  • H - Hours

  • D - Days

  • midnight - roll over at midnight

  • W{0-6} - roll over on a certain day; 0 - Monday

interval: 滾動(dòng)周期,單位由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匹配不上的話,過(guò)期的日志是不會(huì)被刪除的。比如,suffix=“%Y-%m-%d.log”, extMatch的只能是re.compile(r"^\d{4}-\d{2}-\d{2}.log$")。默認(rèn)情況下,在TimedRotatingFileHandler對(duì)象初始化時(shí),suffxi和extMatch會(huì)根據(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}";

如果對(duì)日志文件名沒(méi)有特殊要求的話,可以不用設(shè)置suffix和extMatch,如果需要,一定要讓它們匹配上。

八、模塊封裝

一次封裝,一勞永逸,之后直接調(diào)用即可,封裝內(nèi)容按需。

import logging
from logging.handlers import TimedRotatingFileHandler


class MyLogger(object):

    @staticmethod
    def create_logger():
        my_logger = logging.getLogger("my_logger")
        my_logger.setLevel("DEBUG")
        # 控制臺(tái)處理器
        stream_handler = logging.StreamHandler()
        stream_handler.setLevel("ERROR")
        my_logger.addHandler(stream_handler)
        # 使用時(shí)間滾動(dòng)的文件處理器
        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接口自動(dòng)化之logging日志模塊分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI