概述
在上一節(jié),我們介紹了Python的collections模塊,包括:collections模塊中一些常用的函數(shù)和類。在這一節(jié)靴迫,我們將介紹Python的logging模塊。logging模塊是一個(gè)用于記錄和調(diào)試的標(biāo)準(zhǔn)庫(kù)楼誓,它提供了一種靈活的方式來記錄不同級(jí)別的消息玉锌,比如:調(diào)試信息、錯(cuò)誤信息疟羹、警告信息等主守。這個(gè)模塊非常有用禀倔,因?yàn)樗梢詭椭_發(fā)者理解應(yīng)用程序在運(yùn)行時(shí)到底發(fā)生了什么。當(dāng)程序出現(xiàn)錯(cuò)誤或異常時(shí)参淫,通過合理的日志記錄救湖,我們可以迅速定位問題,了解問題的來龍去脈涎才。
logging的基本使用
在Python中捎谨,logging模塊的使用比較簡(jiǎn)單。導(dǎo)入logging模塊后憔维,通過調(diào)用basicConfig方法可以進(jìn)行基本的配置。比如:可以設(shè)置日志級(jí)別畏邢、日志輸出位置业扒、日志格式等。
import logging
logging.basicConfig(level = logging.INFO,
format = '%(asctime)s - %(levelname)s - %(message)s',
filename = 'app.log',
filemode = 'w')
進(jìn)行上述的基本配置后舒萎,我們就可以創(chuàng)建logger對(duì)象程储,并調(diào)用其各種方法來記錄日志信息了。
logger = logging.getLogger('my_logger')
logger.debug('Debug message')
logger.info('Info message')
logger.warning('Warning message')
logger.error('Error message')
logger.critical('Critical message')
執(zhí)行上述的示例代碼后臂寝,會(huì)在當(dāng)前目錄下生成app.log文件章鲤,其內(nèi)容如下。
2023-09-24 19:44:43,086 - INFO - Info message
2023-09-24 19:44:43,086 - WARNING - Warning message
2023-09-24 19:44:43,086 - ERROR - Error message
2023-09-24 19:44:43,086 - CRITICAL - Critical message
可以看到咆贬,logger.debug函數(shù)寫入的調(diào)試信息沒有出現(xiàn)在文件中败徊。這是因?yàn)椋覀冎付巳罩炯?jí)別為logging.INFO掏缎,比該日志級(jí)別低的信息會(huì)被過濾掉皱蹦,不會(huì)寫入日志文件中。
logging的選項(xiàng)設(shè)置
logging模塊提供了很多選項(xiàng)來配置日志記錄的行為眷蜈,以下是一些常見的選項(xiàng)沪哺。
日志記錄器名稱:每個(gè)記錄器都有一個(gè)名稱,可以通過名稱來獲取和配置特定的記錄器酌儒。
日志級(jí)別:一共有五個(gè)級(jí)別的日志記錄辜妓,從低到高依次為:DEBUG、INFO忌怎、WARNING籍滴、ERROR、
CRITICAL榴啸。我們可以設(shè)置日志記錄器的級(jí)別异逐,這樣低于該級(jí)別的所有消息都不會(huì)被記錄。比如:如果級(jí)別設(shè)置為WARNING插掂,那么DEBUG和INFO級(jí)別的消息將不會(huì)被記錄灰瞻。
日志格式:可以通過設(shè)置日志記錄器的格式字符串來改變?nèi)罩鞠⒌娘@示方式腥例。比如:可以包含時(shí)間戳、日志級(jí)別酝润、消息燎竖、線程名等。
日志輸出地:日志消息可以輸出到多種地方要销,比如:控制臺(tái)构回、文件等∈韪溃可以使用多種Handler來實(shí)現(xiàn)纤掸,比如:輸出到控制臺(tái)使用StreamHandler、輸出到文件使用FileHandler等浑塞。
日志旋轉(zhuǎn):如果日志文件可能會(huì)變得很大借跪,我們需要在滿足某個(gè)條件(比如:日志文件達(dá)到一定大小)時(shí)創(chuàng)建一個(gè)新的日志文件酌壕,這可以通過使用RotatingFileHandler或TimedRotatingFileHandler等處理程序來實(shí)現(xiàn)掏愁。
日志過濾:可以通過使用過濾器來進(jìn)一步定制哪些消息應(yīng)該被記錄。比如:我們可以設(shè)置一個(gè)過濾器卵牍,只有包含特定關(guān)鍵字的消息才會(huì)被記錄果港。
在下面的示例代碼中,我們創(chuàng)建了一個(gè)名為'my_logger'的日志記錄器糊昙,并設(shè)置了其級(jí)別為DEBUG辛掠。然后,我們創(chuàng)建了一個(gè)寫入日志文件的處理器和一個(gè)輸出到控制臺(tái)的處理器释牺,并設(shè)置了他們的級(jí)別公浪。我們還定義了日志消息的格式,并將其應(yīng)用到了兩個(gè)處理器上船侧。最后欠气,我們用這個(gè)記錄器記錄了一條警告信息。
import logging
# 創(chuàng)建一個(gè)logger
logger = logging.getLogger('my_logger')
# 設(shè)置日志級(jí)別
logger.setLevel(logging.DEBUG)
# 創(chuàng)建一個(gè)Handler镜撩,用于寫入日志文件
fileHandler = logging.FileHandler('app.log')
# 設(shè)置日志級(jí)別
fileHandler.setLevel(logging.DEBUG)
# 創(chuàng)建一個(gè)Handler预柒,用于輸出到控制臺(tái)
consoleHandler = logging.StreamHandler()
# 設(shè)置日志級(jí)別
consoleHandler.setLevel(logging.INFO)
# 定義Handler的輸出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileHandler.setFormatter(formatter)
consoleHandler.setFormatter(formatter)
# 給logger添加Handler
logger.addHandler(fileHandler)
logger.addHandler(consoleHandler)
# 記錄一條日志
# 輸出:2023-09-24 20:06:26,828 - my_logger - WARNING - a warning info
logger.warn('a warning info')
日志旋轉(zhuǎn)
在logging模塊中,可以使用RotatingFileHandler和TimedRotatingFileHandler來實(shí)現(xiàn)日志旋轉(zhuǎn)袁梗。
RotatingFileHandler根據(jù)日志文件的大小來旋轉(zhuǎn)日志文件宜鸯。可以通過設(shè)置maxBytes參數(shù)來指定每個(gè)日志文件的大小遮怜,同時(shí)通過backupCount參數(shù)來指定保留的備份文件數(shù)量淋袖。當(dāng)日志文件達(dá)到設(shè)定的最大大小時(shí),原日志文件將被重命名并備份锯梁,同時(shí)開始寫入新的日志文件即碗。
TimedRotatingFileHandler則根據(jù)時(shí)間間隔來旋轉(zhuǎn)日志文件焰情。可以通過設(shè)置interval參數(shù)來指定時(shí)間間隔剥懒,同時(shí)通過backupCount參數(shù)來指定保留的備份文件數(shù)量内舟。當(dāng)達(dá)到設(shè)定的時(shí)間間隔時(shí),原日志文件將被重命名并備份初橘,同時(shí)開始寫入新的日志文件验游。
import logging
import logging.handlers
# 創(chuàng)建一個(gè)Logger對(duì)象
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# 創(chuàng)建一個(gè)RotatingFileHandler對(duì)象
maxSize = 1 << 20
handler = logging.handlers.RotatingFileHandler('app.log', maxBytes = maxSize, backupCount = 5)
# 設(shè)置日志級(jí)別和格式
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
# 記錄日志消息
logger.info('Info message')
在上面的示例代碼中,我們創(chuàng)建了一個(gè)RotatingFileHandler對(duì)象保檐,并指定了日志文件的最大大小為1MB字節(jié)耕蝉,同時(shí)保留5個(gè)備份文件。當(dāng)日志文件達(dá)到設(shè)定的最大大小時(shí)夜只,原日志文件將被重命名并備份垒在,同時(shí)開始寫入新的日志文件。
logging.Filter類
logging.Filter類用于過濾日志消息盐肃。它有一個(gè)名為filter的函數(shù),用于確定是否應(yīng)該記錄或傳遞日志消息权悟。我們可以創(chuàng)建一個(gè)Filter類的派生類砸王,并覆蓋其filter函數(shù)。該函數(shù)接受一個(gè)日志記錄對(duì)象作為參數(shù)峦阁,并返回一個(gè)布爾值谦铃,用于表示是否應(yīng)該記錄或傳遞該日志消息。如果該函數(shù)返回True榔昔,則日志消息將被記錄或傳遞驹闰,否則將被忽略。
import logging
LOG_FORMAT = '%(levelname)s %(asctime)s - %(message)s'
logging.basicConfig(filename = "app.log", level = logging.DEBUG, format = LOG_FORMAT)
my_logger = logging.getLogger('my_logger')
my_logger.setLevel(logging.DEBUG)
# 創(chuàng)建一個(gè)名為my_handler的處理器撒会,并將其添加到my_logger中
my_handler = logging.StreamHandler()
my_handler.setLevel(logging.DEBUG)
my_handler.setFormatter(logging.Formatter(LOG_FORMAT))
my_logger.addHandler(my_handler)
# 創(chuàng)建一個(gè)名為filter的過濾器嘹朗,并將其添加到my_handler中
class CustomFilter(logging.Filter):
def filter(self, record):
return 'Hope' in record.msg
filter = CustomFilter()
my_handler.addFilter(filter)
# 記錄一些消息
my_logger.debug('Hello Hope')
my_logger.info('Hello World')
my_logger.warning('Hope web site')
my_logger.error('GitHub web site')
在上面的示例代碼中,我們首先使用basicConfig方法定義了一個(gè)基本的日志配置诵肛。然后屹培,創(chuàng)建了一個(gè)名為my_logger的記錄器,并將其級(jí)別設(shè)置為DEBUG怔檩。接下來褪秀,我們創(chuàng)建了一個(gè)名為my_handler的處理器,并將其添加到my_logger中薛训。我們還創(chuàng)建了一個(gè)名為filter的過濾器媒吗,并將其添加到my_handler中,以過濾掉日志信息中不包含"Hope"字符串的日志乙埃。最后闸英,我們使用my_logger記錄了幾條不同級(jí)別的日志消息锯岖。執(zhí)行上面的代碼后,只有“Hello Hope”和“Hope web site”這兩條日志信息會(huì)被保存和輸出自阱。