Python日志logging模塊功能與用法詳解
本文實(shí)例講述了Python日志logging模塊功能與用法。分享給大家供大家參考,具體如下:
本文內(nèi)容:
- logging模塊的介紹
- logging模塊的基礎(chǔ)使用
- logging模塊的擴(kuò)展使用
- logging中的Filter
- 使用配置文件配置logging和logger
- 小技巧
- 想要了解更多?不如看看官方文檔。
首發(fā)日期:2018-07-05
logging模塊的介紹:
- 它是一個python標(biāo)準(zhǔn)庫,所以它的通用性很高,所有的python模塊都可以與它合作參與日志記錄。
日志級別:
基本 | 中文意義 | 觸發(fā)情況 |
DEBUG | 調(diào)試 | 調(diào)試時期 |
INFO | 提示 | 正常運(yùn)行時 |
WARINING | 警告 | 現(xiàn)在可運(yùn)行,但未來可能發(fā)生錯誤時(例如未來存儲空間可能不足) |
ERROR | 錯誤 | 當(dāng)程序發(fā)生錯誤,無法執(zhí)行某些功能時 |
CRITICAL | 嚴(yán)重的、致命的 | 當(dāng)程序發(fā)生嚴(yán)重錯誤,無法繼續(xù)運(yùn)行時 |
默認(rèn)是WARNING。
基本類:
- Loggers :日志器,負(fù)責(zé)開放接口來調(diào)用功能,比如它負(fù)責(zé)添加Handlers和Filters 。有默認(rèn)的Loggers 對象
- Handlers :負(fù)責(zé)日志記錄的傳輸目的地,比如有FileHandler(寫入目標(biāo)為文件)和StreamHandler(寫入目標(biāo)為流,默認(rèn)為標(biāo)準(zhǔn)輸出流)
- Filters :負(fù)責(zé)過濾哪些日志是要輸出的 。
- Formatters :負(fù)責(zé)對日志輸出格式的格式化。
logging模塊的基礎(chǔ)使用:
- 基礎(chǔ)使用使用就是使用默認(rèn)logger對象的使用。
- 設(shè)置logging,調(diào)用logging.basicConfig()來配置日志信息。 【由這個來看就知道,它是“通用型的,只能設(shè)置一次的”,如果不同部分想使用不同的日志記錄,需要使用logger對象(下面的擴(kuò)展使用)】
- 可設(shè)置的參數(shù):filename日志文件名,filemode打開文件的方式,format日志的輸出格式,datefmt日期輸出格式,style設(shè)置format的類型,level日志記錄的最低級別,stream輸出流(不與filename并存,filename優(yōu)先),handlers日志處理對象(默認(rèn)是根處理對象),
- 一般使用的參數(shù):filename日志文件名,format日志的輸出格式,level日志記錄的最低級別,stream設(shè)置輸出流
- filename是日志文件名,就是一個普通文件名
- format是日志的輸出格式,設(shè)置方法下面講
- level的設(shè)置值為debug等值,使用方法為logging.DEBUG,logging.INFO,logging.WARNING,logging.ERROR,logging.CRITICAL
- style影響format的類型,它的值有'%','{','$',默認(rèn)是'%',不同的style可以識別以下不同的message標(biāo)識符:%(message)s、{message}、$message
- 輸出日志信息:
- 調(diào)試級別日志信息:logging.debug(信息)
- 提示級別信息:logging.info(信息)
- 警告基本信息:loggin.warning(信息)
- 錯誤級別信息:logging.error(信息)
- 嚴(yán)重級別信息:logging.critical(信息)
信息輸出的格式化(指的是logging.info等函數(shù)里面的信息):
這個表述可能不是很清晰,但意義類似程序報錯信息,(假如)普通的異常信息只有一個報錯原因,(那么為了方便觀看)可能還需要一些如錯誤地點(diǎn),錯誤事件等信息,而這些附加的統(tǒng)一的時間不應(yīng)該由生產(chǎn)錯誤信息的部分來添加(可能有很多個模塊),而應(yīng)該將這個信息給專門做這事的部分來處理(交個formatter來處理)。
1.支持普通字符串%格式化,例如:
logging.info('Started %s'%tag)
2.支持普通字符串format格式化,例如:
logging.info('{} started '.format(tag))
3.logging自帶的,例如:
logging.info('%s start in', tag) logging.info('%s start in %s',tag,address)
format設(shè)置方法:
- 常用特殊字符:
- message是日志信息
- levelname日志信息等級
- asctime是字符串形式的日期時間
- name是logger的名字
- levelno是數(shù)字形式的日志信息等級
- module是調(diào)用日志輸出函數(shù)的模塊名
- funcName是調(diào)用日志輸出函數(shù)的函數(shù)名
- lineno是調(diào)用日志輸出函數(shù)的代碼行數(shù)
根據(jù)不同的style,可以使用%(message)s或{message}或$message類似的格式來標(biāo)注指定位置使用指定信息來取代。
- 默認(rèn)格式:
- asctime 使用
%(asctime)s
- funcName使用
%(funcName)s
- levelname使用
%(levelname)s
- message使用
%(message)s
- lineno使用
%(lineno)d
- module使用
%(module)s
- name使用
%(name)s
- asctime 使用
官方文檔:
https://docs.python.org/3.6/library/logging.html
datefmt日期輸出格式的設(shè)置方法:
設(shè)置format中特殊字符asctime(日期時間)的輸出格式
- 特殊字符:
- %y 兩位數(shù)的年份表示(00-99)
- %Y 四位數(shù)的年份表示(000-9999)
- %m 月份(01-12)
- %d 月內(nèi)中的一天(0-31)
- %H 24小時制小時數(shù)(0-23)
- %I 12小時制小時數(shù)(01-12)
- %M 分鐘數(shù)(00=59)
- %S 秒(00-59)
使用自己想要的分隔符和順序來定義日期時間的格式,例如:
datefmt='%m/%d/%Y %I:%M:%S %p'
使用小例子:
不使用format的:
import logging def show(): print("wechat running...") return "wechat" def main(): logging.basicConfig(filename='myapp.log', level=logging.INFO) tag=show() logging.info('Started %s'%tag) logging.info('Finished %s'%tag) if __name__ == '__main__' : main()
使用format和datefmt的:
import logging def show(): print("wechat running...") return "wechat" def main(): logging.basicConfig(filename='myapp.log', format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p',level=logging.INFO) tag=show() logging.info('%s start in', tag) logging.info('%s Finished',tag) if __name__ == '__main__' : main()
PS:雖然上面沒有說到logger對象,handler對象(默認(rèn)方向是標(biāo)準(zhǔn)輸出流),formatter對象,但實(shí)際上,它是有默認(rèn)的。不要因為默認(rèn)值而搞錯。所以不建議混雜基礎(chǔ)版的和擴(kuò)展版的使用。
logging模塊的擴(kuò)展使用:
1.導(dǎo)入模塊:
import logging
2.獲取logger對象:
logger = logging.getLogger("AppName")
【這里根據(jù)不同的名字定義不同的logger對象,默認(rèn)為root?!?/p>
在模塊中使用時,官方文檔中有一個這樣的代碼,有點(diǎn)意思:
logger = logging.getLogger(__name__)
3.設(shè)置最低日志輸出級別:
logger.setlevel()
例如:
logger.setLevel(logging.INFO)
4.創(chuàng)建并綁定handler:
handler用于處理日志信息的輸出方向,可以添加多個handler,代表同時向多個方向輸出信息
- 創(chuàng)建handler:
輸出方向為文件,使用FileHandler,例如:
logging.FileHandler("test.log")
輸出方向為流,使用StreamHandler,例如:
logging.StreamHandler(sys.stdout)
PS:想了解更多Handler,可以自己查看官方文檔https://docs.python.org/3.6/howto/logging.html
- 綁定handler,使用addHandler():
例如:
logger.addHandler(handler)
- 綁定后如果想解綁handler,使用removeHandler():
例如:
logger.removeHandler(handler)
5.定義handler的輸出格式formatter并綁定到handler上,formatter的設(shè)置方法類似上面基礎(chǔ)使用中的format:
- 創(chuàng)建:
例如:
formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
- 綁定:
handler.setFormatter(formatter) 或handler.formatter=formatter
6.將handle綁定到logger對象上。
logger.addHandler(file_handler) logger.addHandler(console_handler)
7.輸出日志:
調(diào)試級別: logger.debug(信息)
提示級別: logger.info(信息)
警告級別: logger.warn(信息)
錯誤級別:
logger.error(信息)
logger.exception(信息)【與error不同的是,還附帶堆棧信息,一般用在發(fā)生異常時】
嚴(yán)重級別:
logger.fatal(信息) 【fatal是critical的別名】
logger.critical(信息)
使用示例:
import logging def demo(): #獲取logger對象 logger=logging.getLogger("WeChat") #設(shè)置日志等級 logger.setLevel(logging.DEBUG) #創(chuàng)建綁定handler handler=logging.FileHandler('wechat.log') logger.addHandler(handler) # 創(chuàng)建綁定formatter formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s') formatter.datefmt = '%m/%d/%Y %I:%M:%S %p' #可選的 handler.setFormatter(formatter) #嘗試輸出錯誤信息 logger.debug("debug message") logger.info("info message") logger.warning("warining message") logger.error("error message") logger.critical("critical message") if __name__=="__main__" : demo()
補(bǔ)充:
- 如果你不想新建handler和formatter,可以使用basicConfig方式(可以使用basicConfig來配置所有的logger對象的handler和formatter),當(dāng)要注意混雜風(fēng)險。【basicConfig和handler必須至少存在一個,因為默認(rèn)的logger對象也是需要初始化的】
- logging模塊中還有一個filter,由于它涉及的內(nèi)容較多,單獨(dú)列在下面講。
logging中的Filter:
- Filter用來過濾日志信息,例如你想輸出A類信息,但不想輸出C類信息,就可以進(jìn)行過濾
- 而由于所有的信息都有經(jīng)過過濾器,也可以使用過濾器來增加一些信息。
使用方法1:建立子類
下面的例子可能不是很符合應(yīng)用,僅用于舉例:
過濾非允許用戶的日志信息:
import logging import sys class ContextFilter(logging.Filter): def filter(self, record): if record.role=="admin" : return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #創(chuàng)建綁定fiter f = ContextFilter() logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被過濾掉了
官網(wǎng)版的加信息版本:
import logging from random import choice class ContextFilter(logging.Filter): """ This is a filter which injects contextual information into the log. Rather than use actual contextual information, we just use random data in this demo. """ USERS = ['jim', 'fred', 'sheila'] IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1'] def filter(self, record): record.ip = choice(ContextFilter.IPS) record.user = choice(ContextFilter.USERS) return True if __name__ == '__main__': levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) logging.basicConfig(level=logging.DEBUG, format='%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s') a1 = logging.getLogger('a.b.c') a2 = logging.getLogger('d.e.f') f = ContextFilter() a1.addFilter(f) a2.addFilter(f) a1.debug('A debug message') a1.info('An info message with %s', 'some parameters') for x in range(10): lvl = choice(levels) lvlname = logging.getLevelName(lvl) a2.log(lvl, 'A message at %s level with %d %s', lvlname, 2, 'parameters')
使用方法2:使用filter函數(shù)
python3.2后,可以使用filter函數(shù)來做到上面方法1的效果
例子1:
import logging import sys def myfilter(record): if record.role == "admin": return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #創(chuàng)建綁定fiter f = logging.Filter() f.filter=myfilter logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被過濾掉了
例子2,利用lambda:
logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #創(chuàng)建綁定fiter # f = ContextFilter() f = logging.Filter() f.filter=lambda record: record.role=="admin" logger.addFilter(f) logger.info( 'An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被過濾掉了
使用配置文件配置logger對象:
注意:logging默認(rèn)使用的logger對象叫做root
config文件配置方式:
import logging import logging.config logging.config.fileConfig('logging.conf') # create logger logger = logging.getLogger('simpleExample') # 'application' code logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')
文件內(nèi)容:
[loggers] keys=root,simpleExample [handlers] keys=consoleHandler [formatters] keys=simpleFormatter [logger_root] level=DEBUG handlers=consoleHandler [logger_simpleExample] level=DEBUG handlers=consoleHandler qualname=simpleExample propagate=0 [handler_consoleHandler] class=StreamHandler level=DEBUG formatter=simpleFormatter args=(sys.stdout,) [formatter_simpleFormatter] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt=
PS:也支持YAML方式,這里不講述
小技巧:
如果留意到過濾器例子的話,你可以發(fā)現(xiàn)
在formatter內(nèi)可以附加參數(shù):
輸出信息時,附加一個參數(shù)extra,附加的參數(shù)可以被formatter使用
import logging import sys class ContextFilter(logging.Filter): def filter(self, record): if record.role=="admin" : return True else: return False if __name__ == '__main__': logger=logging.getLogger("Wechat") logger.setLevel(logging.DEBUG) handler=logging.StreamHandler(sys.stdout) formatter=logging.Formatter('%(asctime)s %(levelname)s: %(message)s Role: %(role)s') handler.setFormatter(formatter) logger.addHandler(handler) #創(chuàng)建綁定fiter f = ContextFilter() logger.addFilter(f) logger.info('An info message with %s', 'some parameters',extra={"role":"admin"}) logger.info('An info message with %s', 'some parameters',extra={"role":"hacker"})#hacker的被過濾掉了
想要了解更多?不如看看官方文檔。
https://docs.python.org/3.6/library/logging.html
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python日志操作技巧總結(jié)》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進(jìn)階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對大家Python程序設(shè)計有所幫助。
相關(guān)文章
Python實(shí)現(xiàn)數(shù)據(jù)可視化看如何監(jiān)控你的爬蟲狀態(tài)【推薦】
今天主要是來說一下怎么可視化來監(jiān)控你的爬蟲的狀態(tài)。文中通過實(shí)例代碼給大家分析了Python實(shí)現(xiàn)數(shù)據(jù)可視化看如何監(jiān)控你的爬蟲狀態(tài),感興趣的朋友一起看看吧2018-08-08講解Python中for循環(huán)下的索引變量的作用域
這篇文章主要介紹了講解Python中for循環(huán)下的索引變量的作用域,是Python學(xué)習(xí)當(dāng)中的基礎(chǔ)知識,本文給出了Python3的示例幫助讀者理解,需要的朋友可以參考下2015-04-04Python跑循環(huán)時內(nèi)存泄露的解決方法
這篇文章主要介紹了Python跑循環(huán)時內(nèi)存泄露的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01python使用json將字符串轉(zhuǎn)字典報錯的解決
這篇文章主要介紹了python使用json將字符串轉(zhuǎn)字典報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02Python常用標(biāo)準(zhǔn)庫詳解(pickle序列化和JSON序列化)
這篇文章主要介紹了Python常用標(biāo)準(zhǔn)庫,主要包括pickle序列化和JSON序列化模塊,通過使用場景分析給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05使用python創(chuàng)建生成動態(tài)鏈接庫dll的方法
這篇文章主要介紹了使用python創(chuàng)建生成動態(tài)鏈接庫dll的方法,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05Python+selenium 獲取瀏覽器窗口坐標(biāo)、句柄的方法
今天小編就為大家分享一篇Python+selenium 獲取瀏覽器窗口坐標(biāo)、句柄的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10Django在pycharm下修改默認(rèn)啟動端口的方法
今天小編就為大家分享一篇Django在pycharm下修改默認(rèn)啟動端口的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07