示例代碼
import logging
LOG_FORMAT = "%(asctime)s====%(levelname)s++++%(message)s"
logging.basicConfig(filename="tulingxueyuan.log", level=logging.DEBUG, format=LOG_FORMAT)
logging.debug("This is a debug log .")
logging.info("This is a info log .")
logging.warning("This is a warning log .")
logging.error("This is a error log .")
logging.critical("This is a critical log .")
# 另一種寫法
logging.log(logging.DEBUG, "This is a debug log .")
logging.log(logging.INFO, "This is a info log .")
logging.log(logging.WARNING, "This is a warning log .")
logging.log(logging.ERROR, "This is a error log .")
logging.log(logging.CRITICAL, "This is a critical log .")
logging模塊的使用方式
logging模塊提供兩種記錄日志的方式:
- 第一種 使用logging提供的模塊級別的函數(shù)
-
第二種 使用logging日志系統(tǒng)的四大組件
其中l(wèi)ogging.basicConfig(**kwargs)函數(shù)用于指定“要記錄的日志級別”瓦胎、“日志格式”赖条、“日志輸出位置”痹束、“日志文件的打開模式”等信息铅忿,其他幾個都是用于記錄各個級別日志的函數(shù)。
logging.basicConfig函數(shù)說明
關(guān)鍵字參數(shù):
- filename,指定日志輸目標(biāo)文件的文件名,指定后日志不會在控制臺輸出第煮。
- filemode,指定日志文件的打開模式抑党,默認(rèn)為‘a(chǎn)’空盼,此項必須在filename指定才有效。
- format新荤,指定日志格式字符串揽趾。
- datefmt,指定日期時間格式苛骨。
- level篱瞎,指定日志器的日志級別。
- stream痒芝,指定日志輸出目標(biāo)stream俐筋,如sys.stdout、sys.stderr以及網(wǎng)絡(luò)stream严衬。需要說明的是澄者,stream和filename不能同時提供,否則會引發(fā) ValueError異常。
- style粱挡,指定format格式字符串的風(fēng)格赠幕,可取值為'%'、'{'和'$'询筏,默認(rèn)為'%'榕堰。
- handlers,該選項如果被指定嫌套,它應(yīng)該是一個創(chuàng)建了多個Handler的可迭代對象逆屡,這些handler將會被添加到root logger。需要說明的是:filename踱讨、stream和handlers這三個配置項只能有一個存在满力,不能同時出現(xiàn)2個或3個铡羡,否則會引發(fā)ValueError異常筏餐。
logging模塊定義的格式字符串字段
logging模塊的處理流程
四大組件
- 日志器(Logger):產(chǎn)生日志的一個接口
- 處理器(Handler):把產(chǎn)生的日志發(fā)送到相應(yīng)的目的地
- 過濾器(Filter):更精細(xì)的控制那些日志輸出
- 格式器(Formatter):對輸出信息進(jìn)行格式化
組件直接的關(guān)系如下:
- 日志器(logger)需要通過處理器(handler)將日志信息輸出到目標(biāo)位置综液,如:文件、sys.stdout味混、網(wǎng)絡(luò)等;
- 不同的處理器(handler)可以將日志輸出到不同的位置诫惭;
- 日志器(logger)可以設(shè)置多個處理器(handler)將同一條日志記錄輸出到不同的位置翁锡;
- 每個處理器(handler)都可以設(shè)置自己的過濾器(filter)實現(xiàn)日志過濾,從而只保留感興趣的日志夕土;
- 每個處理器(handler)都可以設(shè)置自己的格式器(formatter)實現(xiàn)同一條日志以不同的格式輸出到不同的地方馆衔。
日志器(logger)是入口,真正干活兒的是處理器(handler)怨绣,處理器(handler)還可以通過過濾器(filter)和格式器(formatter)對要輸出的日志內(nèi)容做過濾和格式化等處理操作角溃。
logging模塊相關(guān)類及常用方法
下面介紹下與logging四大組件相關(guān)的類:Logger, Handler, Filter, Formatter。
Logger類
Logger對象有3個任務(wù):
- 使應(yīng)用程序可以在運(yùn)行時記錄日志消息
- 基于日志嚴(yán)重等級或filter對象決定對哪些日志進(jìn)行后續(xù)處理
- 將日志消息傳給所有感興趣的handlers
logger對象最常用的方法分為兩類:
配置方法和消息發(fā)送方法篮撑。
常用配置方法:
方法 | 描述 |
---|---|
Logger.setLevel() | 設(shè)置日志器將會處理的日志消息的最低嚴(yán)重級別 |
Logger.addHandler() 和 Logger.removeHandler() | 為該logger對象添加 和 移除一個handler對象 |
Logger.addFilter() 和 Logger.removeFilter() | 為該logger對象添加 和 移除一個filter對象 |
創(chuàng)建日志方法:
方法 | 描述 |
---|---|
Logger.debug(), Logger.info()等 | 用來創(chuàng)建指定等級的日志記錄 |
Logger.exception() | 創(chuàng)建一個類似于Logger.error()的日志消息 |
Logger.log() | 需要獲取一個明確的日志level參數(shù)來創(chuàng)建一個日志記錄 |
- Logger.exception()與Logger.error()的區(qū)別在于:Logger.exception()將會輸出堆棧追蹤信息减细,另外通常只是在一個exception handler中調(diào)用該方法。
- Logger.log()與Logger.debug()赢笨、Logger.info()等方法相比未蝌,雖然需要多傳一個level參數(shù),顯得不是那么方便茧妒,但是當(dāng)需要記錄自定義level的日志時還是需要該方法來完成萧吠。
通過logging.getLogger方法來得到Logger對象,logging.getLogger()方法有一個可選參數(shù)name桐筏,該參數(shù)表示將要返回的日志器的名稱標(biāo)識纸型,如果不提供該參數(shù),則其值為'root'。若以相同的name參數(shù)值多次調(diào)用getLogger()方法狰腌,將會返回指向同一個logger對象的引用除破。
Handler類
Handler對象的作用是(基于日志消息的level)將消息分發(fā)到handler指定的位置(文件、網(wǎng)絡(luò)癌别、郵件等)皂岔。Logger對象可以通過addHandler()方法為自己添加0個或者更多個handler對象。比如展姐,一個應(yīng)用程序可能想要實現(xiàn)以下幾個日志需求:
- 把所有日志都發(fā)送到一個日志文件中躁垛;
- 把所有嚴(yán)重級別大于等于error的日志發(fā)送到stdout(標(biāo)準(zhǔn)輸出);
- 把所有嚴(yán)重級別為critical的日志發(fā)送到一個email郵件地址圾笨。這種場景就需要3個不同的handlers教馆,每個handler復(fù)雜發(fā)送一個特定嚴(yán)重級別的日志到一個特定的位置。
配置方法:
方法 | 描述 |
---|---|
Handler.setLevel() | 設(shè)置handler將會處理的日志消息的最低嚴(yán)重級別 |
Handler.setFormatter() | 為handler設(shè)置一個格式器對象 |
Handler.addFilter() 和 Handler.removeFilter() | 為handler添加 和 刪除一個過濾器對象 |
需要說明的是擂达,應(yīng)用程序代碼不應(yīng)該直接實例化和使用Handler實例土铺。因為Handler是一個基類,它只定義了素有handlers都應(yīng)該有的接口板鬓,同時提供了一些子類可以直接使用或覆蓋的默認(rèn)行為悲敷。
常用的Handler:
Handler | 描述 |
---|---|
logging.StreamHandler | 將日志消息發(fā)送到輸出到Stream,如std.out, std.err或任何file-like對象俭令。 |
logging.FileHandler | 將日志消息發(fā)送到磁盤文件后德,默認(rèn)情況下文件大小會無限增長 |
logging.handlers.RotatingFileHandler | 將日志消息發(fā)送到磁盤文件,并支持日志文件按大小切割 |
logging.hanlders.TimedRotatingFileHandler | 將日志消息發(fā)送到磁盤文件抄腔,并支持日志文件按時間切割 |
logging.handlers.HTTPHandler | 將日志消息以GET或POST的方式發(fā)送給一個HTTP服務(wù)器 |
logging.handlers.SMTPHandler | 將日志消息發(fā)送給一個指定的email地址 |
logging.NullHandler | 該Handler實例會忽略error messages瓢湃,通常被想使用logging的library開發(fā)者使用來避免'No handlers could be found for logger XXX'信息的出現(xiàn)。 |
Formater類
Formater對象用于配置日志信息的最終順序赫蛇、結(jié)構(gòu)和內(nèi)容绵患。與logging.Handler基類不同的是,應(yīng)用代碼可以直接實例化Formatter類悟耘。另外落蝙,如果你的應(yīng)用程序需要一些特殊的處理行為,也可以實現(xiàn)一個Formatter的子類來完成暂幼。
Formatter類構(gòu)造方法如下:
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
Filter類
定義如下:
class logging.Filter(name=“”)
filter(record)
比如掘殴,一個filter實例化時傳遞的name參數(shù)值為'A.B',那么該filter實例將只允許名稱為類似如下規(guī)則的loggers產(chǎn)生的日志記錄通過過濾:'A.B'粟誓,'A.B,C'奏寨,'A.B.C.D','A.B.D'鹰服,而名稱為'A.BB', 'B.A.B'的loggers產(chǎn)生的日志則會被過濾掉病瞳。如果name的值為空字符串揽咕,則允許所有的日志事件通過過濾。
filter方法用于具體控制傳遞的record記錄是否能通過過濾套菜,如果該方法返回值為0表示不能通過過濾亲善,返回值為非0表示可以通過過濾。
使用logging四大組件記錄日志
1.需求
- 將所有級別的所有日志寫入磁盤文件
- all.log中記錄所有的日志信息逗柴,格式為:日期時間-級別-內(nèi)容
- error.log單獨(dú)記錄error及以上的日志信息蛹头,日期和時間 - 日志級別 - 文件名[:行號] - 日志信息
- all.log在每天凌晨進(jìn)行日志切割
2.分析
- 記錄所有級別的日志,level設(shè)置為DEBUG
- 日志被發(fā)送給兩個不同的目的地戏溺,需要設(shè)置兩個handler渣蜗,都需要寫入磁盤,都跟filehandler有關(guān)
- all.log要求按照時間進(jìn)行日志分割旷祸,需要用到logging.handlers.TimedRotatingFileHandler耕拷,而error.log沒有要求日志分割,可以使用FileHandler
- 兩個日志文件格式不同托享,設(shè)置不同的格式器
3.代碼實現(xiàn)
import logging
import logging.handlers
import datetime
logger = logging.getLogger('mylogger')
logger.setLevel(logging.DEBUG)
rf_handler = logging.handlers.TimedRotatingFileHandler('all.log', when='midnight',
interval=1, backupCount=7,
atTime=datetime.time(0, 0, 0, 0))
rf_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
f_handler = logging.FileHandler('error.log')
f_handler.setLevel(logging.ERROR)
f_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(filename)s[:%(lineno)d] - %(message)s"))
logger.addHandler(rf_handler)
logger.addHandler(f_handler)
logger.debug('debug message')
logger.info('info message')
logger.warning('warning message')
logger.error('error message')
logger.critical('critical message')
配置logging的幾種方式
作為開發(fā)者骚烧,我們可以通過以下3中方式來配置logging:
- 使用python代碼顯式的創(chuàng)建loggers,handlers和formatters并分別調(diào)用他們的配置函數(shù)闰围。
- 創(chuàng)建日志配置文件赃绊,然后使用fileConfig函數(shù)來讀取該文件的內(nèi)容
- 創(chuàng)建一個包含配置信息的dict,然后把它傳遞給dictConfig函數(shù)
可以參考博客《Python之配置日志的幾種方式》
向日志輸出中添加上下文信息
除了傳遞給日志記錄函數(shù)的參數(shù)外羡榴,有時候我們還想在日志輸出中包含一些額外的上下文信息碧查。比如,在一個網(wǎng)絡(luò)應(yīng)用中炕矮,可能希望在日志中記錄客戶端的特定信息,如:遠(yuǎn)程客戶端的IP地址和用戶名者冤。這里我們來介紹以下幾種實現(xiàn)方式:
- 通過日志記錄函數(shù)傳遞一個extra參數(shù)引入上下文信息
- 使LoggerAdapter引入上下文信息
- 使用Filters引入上下文信息
具體說明請參考另一篇博文《Python之向日志輸出中添加上下文信息》