一绍赛、日志相關(guān)概念
日志是一種可以追蹤軟件運行時所發(fā)生事件的方法骡技。軟件開發(fā)人員可以向他們的代碼中調(diào)用日志記錄相關(guān)的方法來表明發(fā)生了某些事情鸣个。一個事件可以用一個可包含可選變量數(shù)據(jù)的消息來描述羞反。此外,事件也有重要性的概念囤萤,這個重要性也可以被稱為嚴(yán)重性級別(level)昼窗。
1.日志的作用
- 調(diào)試與故障定位
方便用戶了解系統(tǒng)或軟件、應(yīng)用的運行情況涛舍;軟件程序運行故障分析與問題定位 - 數(shù)據(jù)分析
如果應(yīng)用的日志信息足夠詳細(xì)和豐富澄惊,還可以用來做用戶行為分析,如:分析用戶的操作行為富雅、類型洗好掸驱、地域分布以及其它更多的信息,由此可以實現(xiàn)改進(jìn)業(yè)務(wù)没佑、提高商業(yè)利益毕贼。
2.日志的等級
我們先來思考下下面的兩個問題:
作為開發(fā)人員,在開發(fā)一個應(yīng)用程序時需要什么日志信息蛤奢?在應(yīng)用程序正式上線后需要什么日志信息鬼癣?
作為應(yīng)用運維人員,在部署開發(fā)環(huán)境時需要什么日志信息啤贩?在部署生產(chǎn)環(huán)境時需要什么日志信息待秃?
為什么要給日志分級?瓜晤?锥余?
在軟件開發(fā)階段或部署開發(fā)環(huán)境時,為了盡可能詳細(xì)的查看應(yīng)用程序的運行狀態(tài)來保證上線后的穩(wěn)定性痢掠,我們可能需要把該應(yīng)用程序所有的運行日志全部記錄下來進(jìn)行分析驱犹,這是非常耗費機器性能的。當(dāng)應(yīng)用程序正式發(fā)布或在生產(chǎn)環(huán)境部署應(yīng)用程序時足画,我們通常只需要記錄應(yīng)用程序的異常信息雄驹、錯誤信息等憔维,這樣既可以減小服務(wù)器的I/O壓力抢蚀,也可以避免我們在排查故障時被淹沒在日志的海洋里。那么振坚,怎樣才能在不改動應(yīng)用程序代碼的情況下實現(xiàn)在不同的環(huán)境記錄不同詳細(xì)程度的日志呢象缀?這就是日志等級的作用了蔬将,我們通過配置文件指定我們需要的日志等級就可以了。
不同的應(yīng)用程序所定義的日志等級可能會有所差別央星,分的詳細(xì)點的會包含以下幾個等級:
- DEBUG
- INFO
- NOTICE
- WARNING
- ERROR
- CRITICAL
- ALERT
- EMERGENCY
3.日志字段信息與日志格式
本節(jié)開始問題提到過霞怀,一條日志信息對應(yīng)的是一個事件的發(fā)生,而一個事件通常需要包括以下幾個內(nèi)容:
事件發(fā)生時間
事件發(fā)生位置
事件的嚴(yán)重程度--日志級別
事件內(nèi)容
上面這些都是一條日志記錄中可能包含的字段信息莉给,當(dāng)然還可以包括一些其他信息毙石,如進(jìn)程ID廉沮、進(jìn)程名稱、線程ID徐矩、線程名稱等滞时。日志格式就是用來定義一條日志記錄中包含那些字段的,且日志格式通常都是可以自定義的滤灯。
4.日志功能的實現(xiàn)
幾乎所有開發(fā)語言都會內(nèi)置日志相關(guān)功能坪稽,或者會有比較優(yōu)秀的第三方庫來提供日志操作功能,比如:log4j力喷,log4php等刽漂。它們功能強大、使用簡單弟孟。Python自身也提供了一個用于記錄日志的標(biāo)準(zhǔn)庫模塊--logging。
二样悟、logging模塊簡介
logging模塊定義的函數(shù)和類為應(yīng)用程序和庫的開發(fā)實現(xiàn)了一個靈活的事件日志系統(tǒng)拂募。logging模塊是Python的一個標(biāo)準(zhǔn)庫模塊,由標(biāo)準(zhǔn)庫模塊提供日志記錄API的關(guān)鍵好處是所有Python模塊都可以使用這個日志記錄功能窟她。所以陈症,你的應(yīng)用日志可以將你自己的日志信息與來自第三方模塊的信息整合起來。
1.helloworld
學(xué)習(xí)一個新的模塊前震糖,我們先來看一個demo試試水录肯。
代碼:
import logging
logging.basicConfig(level=logging.DEBUG)
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.")
輸出結(jié)果:
DEBUG:root:This is a debug log.
INFO:root:This is a info log.
WARNING:root:This is a warning log.
ERROR:root:This is a error log.
CRITICAL:root:This is a critical log.
是不是簡單到爆炸!5跛怠论咏!對的,就是這樣颁井√埃總結(jié)來看,要使用日志功能雅宾,其實就分為3個步驟:
- 導(dǎo)入logging模塊养涮;
- 配置logging模塊的基本參數(shù)與格式;
- 輸出不同等級的日志msg眉抬;
2. logging模塊的使用方式介紹
logging模塊提供了兩種記錄日志的方式:
第一種:使用logging提供的模塊級別的函數(shù)(簡單常用)
第二種:使用Logging日志系統(tǒng)的四大組件(高級用法贯吓,定制化強)
(其實,logging所提供的模塊級別的日志記錄函數(shù)也是對logging日志系統(tǒng)相關(guān)類的封裝而已蜀变。)
這里先說說第一種簡單的:
logging模塊級別的常用函數(shù):
logging.debug(msg, *args, **kwargs)
創(chuàng)建一條嚴(yán)重級別為DEBUG的日志記錄logging.info(msg, *args, **kwargs)
創(chuàng)建一條嚴(yán)重級別為INFO的日志記錄logging.warning(msg, *args, **kwargs)
創(chuàng)建一條嚴(yán)重級別為WARNING的日志記錄logging.error(msg, *args, **kwargs)
創(chuàng)建一條嚴(yán)重級別為ERROR的日志記錄logging.critical(msg, *args, **kwargs)
創(chuàng)建一條嚴(yán)重級別為CRITICAL的日志記錄logging.log(level, *args, **kwargs)
創(chuàng)建一條嚴(yán)重級別為level的日志記錄logging.basicConfig(**kwargs)
對root logger進(jìn)行一次性配置
其中l(wèi)ogging.basicConfig(**kwargs)函數(shù)用于指定“要記錄的日志級別”悄谐、“日志格式”、“日志輸出位置”昏苏、“日志文件的打開模式”等信息尊沸,其他幾個都是用于記錄各個級別日志的函數(shù)威沫。
咦?這個log函數(shù)怎么在渾水摸魚洼专,Demo中沒見過棒掠,其實它和前面幾種按照等級輸出日志的函數(shù)功能等價,沒有區(qū)別屁商。
logging.debug("This is a debug log.")
和
logging.log(logging.DEBUG, "This is a debug log.")
沒區(qū)別烟很,看個人癖好啦!蜡镶!
3. logging模塊的日志級別
logging模塊默認(rèn)定義了以下幾個日志等級雾袱,它允許開發(fā)人員自定義其他日志級別,但是這是不被推薦的官还,尤其是在開發(fā)供別人使用的庫時芹橡,因為這會導(dǎo)致日志級別的混亂。只有級別大于或等于日志記錄器指定級別的日志記錄才會被輸出望伦,小于該級別的日志記錄將會被丟棄林说。
什么鬼?怎么設(shè)置日志記錄器的輸出級別屯伞?腿箩?嗯,你應(yīng)該猜到了劣摇,就在basicConfig函數(shù)里面設(shè)置珠移,嘻嘻,我們后面再看末融。
日志等級(level)
- DEBUG: 最詳細(xì)的日志信息钧惧,典型應(yīng)用場景是問題診斷;
- INFO: 信息詳細(xì)程度僅次于DEBUG滑潘,通常只記錄關(guān)鍵節(jié)點信息垢乙,用于確認(rèn)一切都是按照我們預(yù)期的那樣進(jìn)行工作
- WARNING: 當(dāng)某些不期望的事情發(fā)生時記錄的信息(如,磁盤可用空間較低)语卤,但是此時應(yīng)用程序還是正常運行的追逮;
- ERROR: 由于一個更嚴(yán)重的問題導(dǎo)致某些功能不能正常運行時記錄的信息;
- CRITICAL: 當(dāng)發(fā)生嚴(yán)重錯誤粹舵,導(dǎo)致應(yīng)用程序不能繼續(xù)運行時記錄的信息钮孵;
上面的日志等級是從上到下依次升高的,即:DEBUG < INFO < WARNING < ERROR < CRITICAL眼滤,而日志的信息量是依次減少的巴席;
墨跡了這么久,就為了搞明白這個等級的高低與用途诅需,現(xiàn)在我們看一下漾唉,這個日志記錄器的輸出等級怎么設(shè)置荧库,該怎么用!其實Demo中都寫了
logging.basicConfig(level=logging.DEBUG)
這條語句的作用就是赵刑,DEBUG等級以上的log都輸出分衫。修改下代碼:
代碼:
import logging
logging.basicConfig(level=logging.WARNING)
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.")
輸出結(jié)果:
WARNING:root:This is a warning log.
ERROR:root:This is a error log.
CRITICAL:root:This is a critical log.
開發(fā)應(yīng)用程序或部署開發(fā)環(huán)境時,可以使用DEBUG或INFO級別的日志獲取盡可能詳細(xì)的日志信息來進(jìn)行開發(fā)或部署調(diào)試般此;應(yīng)用上線或部署生產(chǎn)環(huán)境時蚪战,應(yīng)該使用WARNING或ERROR或CRITICAL級別的日志來降低機器的I/O壓力和提高獲取錯誤日志信息的效率。日志級別的指定通常都是在應(yīng)用程序的配置文件中進(jìn)行指定的铐懊。
4. logging.basicConfig()函數(shù)說明
寫到這邀桑,不少人就會噴水,這個配置函數(shù)就只能設(shè)置輸出等級嗎壁畸?
日志輸出的格式這么丑,不能改嗎喜喂?
為啥日志只能輸出到控制臺,怎么輸出到文件呢?
把這些問題通通丟給配置函數(shù)=薄影斑!
basicConfig()函數(shù)的關(guān)鍵參數(shù):
- filename: 指定日志輸出目標(biāo)文件的文件名,指定該設(shè)置項后日志信心就不會被輸出到控制臺了皆辽;
- filemode: 指定日志文件的打開模式空免,默認(rèn)為'a'空另。需要注意的是,該選項要在filename指定時才有效蹋砚;
- format: 指定日志格式字符串扼菠,即指定日志輸出時所包含的字段信息以及它們的順序摄杂。logging模塊定義的格式字段下面會列出。
- datefmt: 指定日期/時間格式循榆。需要注意的是析恢,該選項要在format中包含時間字段%(asctime)s時才有效
- level :指定日志器的日志級別
- stream: 指定日志輸出目標(biāo)stream,如sys.stdout冯痢、sys.stderr以及網(wǎng)絡(luò)stream氮昧。需要說明的是,stream和filename不能同時提供浦楣,否則會引發(fā) ValueError異常
- style: Python 3.2中新添加的配置項袖肥。指定format格式字符串的風(fēng)格,可取值為'%'振劳、'{'和'$'椎组,默認(rèn)為'%'
- handlers: Python 3.3中新添加的配置項。該選項如果被指定历恐,它應(yīng)該是一個創(chuàng)建了多個Handler的可迭代對象寸癌,這些handler將會被添加到root logger。需要說明的是:filename弱贼、stream和handlers這三個配置項只能有一個存在蒸苇,不能同時出現(xiàn)2個或3個,否則會引發(fā)ValueError異常吮旅。
這里面的參數(shù)比較簡單溪烤,想要重點介紹的就是format和datefmt,他們兩個控制著日志的格式化輸出庇勃,下面我們看一下檬嘀,格式化字段是怎樣的。
5. logging模塊定義的格式字符串字段
我們來列舉一下logging模塊中定義好的可以用于format格式字符串中字段有哪些:
- asctime: %(asctime)s:日志事件發(fā)生的時間--人類可讀時間责嚷,如:2003-07-08 16:49:45,896
- created: %(created)f: 日志事件發(fā)生的時間--時間戳鸳兽,就是當(dāng)時調(diào)用time.time()函數(shù)返回的值
- relativeCreated: %(relativeCreated)d: 日志事件發(fā)生的時間相對于logging模塊加載時間的相對毫秒數(shù)(目前還不知道干嘛用的)
- msecs :%(msecs)d 日志事件發(fā)生事件的毫秒部分
- levelname: %(levelname)s: 該日志記錄的文字形式的日志級別('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')
- levelno: %(levelno)s: 該日志記錄的數(shù)字形式的日志級別(10, 20, 30, 40, 50)
- name: %(name)s: 所使用的日志器名稱,默認(rèn)是'root'罕拂,因為默認(rèn)使用的是 rootLogger
- message: %(message)s: 日志記錄的文本內(nèi)容揍异,通過 msg % args計算得到的
- pathname: %(pathname)s: 調(diào)用日志記錄函數(shù)的源碼文件的全路徑
- filename: %(filename)s: pathname的文件名部分,包含文件后綴
- module: %(module)s: filename的名稱部分聂受,不包含后綴
- lineno: %(lineno)d: 調(diào)用日志記錄函數(shù)的源代碼所在的行號
- funcName: %(funcName)s: 調(diào)用日志記錄函數(shù)的函數(shù)名
- process: %(process)d: 進(jìn)程ID
- processName:%(processName)s: 進(jìn)程名稱蒿秦,Python 3.1新增
- thread: %(thread)d: 線程ID
- threadName: %(thread)s: 線程名稱
我們來看個例子,上面這些參數(shù)怎么用蛋济。
代碼:
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"
logging.basicConfig(filename='my.log', level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_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.")
輸出:
05/08/2017 14:29:04 PM - DEBUG - This is a debug log.
05/08/2017 14:29:04 PM - INFO - This is a info log.
05/08/2017 14:29:04 PM - WARNING - This is a warning log.
05/08/2017 14:29:04 PM - ERROR - This is a error log.
05/08/2017 14:29:04 PM - CRITICAL - This is a critical log.
6.添加自定義的字段
上面的例子中使用的格式化字段都是系統(tǒng)定義好的棍鳖,如果想添加一個自定義的字段,該怎么辦呢?可以借助日志輸出的extra參數(shù)來實現(xiàn)渡处。
logging.debug(), logging.info()等方法的定義中镜悉,除了msg和args參數(shù)外,還有一個**kwargs參數(shù)医瘫。它們支持3個關(guān)鍵字參數(shù): exc_info, stack_info, extra侣肄,下面對這幾個關(guān)鍵字參數(shù)作個說明。
exc_info: 其值為布爾值醇份,如果該參數(shù)的值設(shè)置為True稼锅,則會將異常異常信息添加到日志消息中。如果沒有異常信息則添加None到日志信息中僚纷。
stack_info: 其值也為布爾值矩距,默認(rèn)值為False。如果該參數(shù)的值設(shè)置為True怖竭,棧信息將會被添加到日志信息中锥债。
extra: 這是一個字典(dict)參數(shù),它可以用來自定義消息格式中所包含的字段痊臭,但是它的key不能與logging模塊定義的字段沖突哮肚。
舉個栗子:
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(user)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"
logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT)
logging.warning("Some one delete the log file." extra={'user': 'Tom'})
輸出:
05/08/2017 16:35:00 PM - WARNING - Tom - Some one delete the log file.
7.logging的作用域
logging.basicConfig()函數(shù)是一個一次性的簡單配置工具使,也就是說只有在第一次調(diào)用該函數(shù)時會起作用广匙,后續(xù)再次調(diào)用該函數(shù)時完全不會產(chǎn)生任何操作的允趟,多次調(diào)用的設(shè)置并不是累加操作。所以鸦致,在一個py文件中配置一次logging拼窥,在其他文件使用的時候,都遵循之前的設(shè)置蹋凝,不必重復(fù)設(shè)置。
(原文是非常好的日志介紹总棵,基本的內(nèi)容我就不重復(fù)寫了鳍寂,直接轉(zhuǎn)過來,本文在原文的基礎(chǔ)上融入自己的理解與總結(jié):https://www.cnblogs.com/yyds/p/6901864.html)