小編寫(xiě)這篇文章的主要目的,就是給大家介紹下關(guān)于在Python中,有內(nèi)置的logging,那么,我們?cè)谶M(jìn)行使用它的時(shí)候,有什么使用方法呢?下面就給大家詳細(xì)介紹。
logging的主要作用
它的作用是給日志記錄的接口和眾多處理模塊,供用戶存儲(chǔ)各種格式的日志,幫助調(diào)試程序或者記錄程序運(yùn)行過(guò)程中的輸出信息。
logging日志等級(jí)
logging日志等級(jí)分為五個(gè)等級(jí),優(yōu)先級(jí)從高到低依次是:
**CRITICAL;**程序嚴(yán)重錯(cuò)誤
**ERROR;**程序錯(cuò)誤/部分功能錯(cuò)誤
**WARNING;**程序有發(fā)生錯(cuò)誤的可能
**INFO;**程序正常運(yùn)行時(shí)的信息
DEBUG程序調(diào)試信息
默認(rèn)的日志的記錄等級(jí)為WARNING,即當(dāng)日志的等級(jí)大于獲等于WARNING時(shí)才會(huì)被記錄。
一般常用的記錄等級(jí)為INFO,其用于記錄程序的正常運(yùn)行的一些信息(類似于print)。
當(dāng)日志的等級(jí)達(dá)到WARNING以上時(shí),表明此時(shí)程序不能正常運(yùn)行;
logging的基礎(chǔ)函數(shù)
logging.basicConfig(**kwargs)
在沒(méi)有顯式的進(jìn)行創(chuàng)建記錄器(logger)時(shí),會(huì)默認(rèn)創(chuàng)建一個(gè)root logger,而logging.basicConfig(**kwargs)可以創(chuàng)建帶有默認(rèn)的Formatter的streamHandle并將其添加到根日志記錄器中來(lái)初始化基本配置。
比如
import logging logging.debug('Debug code!') logging.info('Run code!') logging.warning('Watch out!') logging.error('This is an error') logging.critical('This is a ciritical')
上面代碼中l(wèi)ogging并沒(méi)有顯式的創(chuàng)建logger(logging.getLogger),其在直接使用debug(),info(),warning(),error(),critical()時(shí)會(huì)使用默認(rèn)的root logger,并會(huì)自動(dòng)調(diào)用自定義的或者默認(rèn)的logging.basicConfig(**kwargs)初始化root logger。
自定義的logging.basicConfig(**kwargs)中的參數(shù)有以下的主要的選項(xiàng):
例如下面通過(guò)自定義logging.basicConfig(**kwargs)來(lái)初始化root logger來(lái)獲得DEBUG級(jí)別及以上的日志記錄并保存到log.txt文件中。
import logging logging.basicConfig(filename='./log.txt', format='%(asctime)s-%(name)s-%(levelname)s-%(message)s-%(funcName)s:%(lineno)d', level=logging.DEBUG) logging.debug('Debug code!') logging.info('Run code!') logging.warning('Watch out!') logging.error('This is an error') logging.critical('This is a ciritical')
logging的四大組件(類)
Logger
除了根記錄器(root logger)外,最主要的是可以自己創(chuàng)建日志記錄器。
通過(guò)模塊級(jí)別的函數(shù)logging.getLogger(name)實(shí)例化記錄器
默認(rèn)情況下,記錄器采用層級(jí)結(jié)構(gòu),通過(guò).來(lái)區(qū)分不同的層級(jí)。比如有個(gè)名叫foo的記錄器則foo.a和foo.b都是foo的子級(jí)記錄器。當(dāng)然,最開(kāi)始的或者說(shuō)最上層的記錄器就是root logger。如果name=None,構(gòu)建的是root logger。
可以直接用當(dāng)前模塊的名稱當(dāng)作記錄器的名字logging.getLogger(__name__)
子級(jí)記錄器通常不需要多帶帶設(shè)置日志級(jí)別以及Handler,如果子級(jí)記錄器沒(méi)有多帶帶設(shè)置,則它的行為會(huì)委托給父級(jí)。比如說(shuō),記錄器foo的級(jí)別為INFO,而foo.a和foo.b都不設(shè)置日志級(jí)別。此時(shí)foo.a和foo.b會(huì)遵循foo的級(jí)別設(shè)置,即只記錄大于等于INFO級(jí)別的日志;而如果foo也沒(méi)設(shè)置的話,就會(huì)找到根記錄器root logger,root默認(rèn)的級(jí)別為WARGING。
logger類的一些常用的方法
logger結(jié)合后面要介紹的其他的三個(gè)組件可以實(shí)現(xiàn)以下的功能:
Logger需要通過(guò)handler將日志信息輸出到目標(biāo)位置,目標(biāo)位置可以是sys.stdout和文件等(這與logging.basicConfig(**kwargs)設(shè)置中不太一致)。
一個(gè)Logger可以設(shè)置不同的Handler,而不同的Handler可以將日志輸出到不同的位置(不同的日志文件),并且每個(gè)Handler都可以設(shè)置自己的filter從而實(shí)現(xiàn)日志過(guò)濾,保留實(shí)際項(xiàng)目中需要的日志。同時(shí)每個(gè)Handler也可以設(shè)置不同的Formatter,在每個(gè)Formatter實(shí)現(xiàn)同一條日志以不同的格式輸出到不同的地方。
Handle
處理器;其可以控制記錄的日志輸出到什么地方(標(biāo)準(zhǔn)輸出/文件/...),同時(shí)處理器也可以添加過(guò)濾器(filter)和格式控制器(formatter)來(lái)控制輸出的內(nèi)容和輸出的格式。
其具有幾種常見(jiàn)的處理器:
logging.StreamHandler標(biāo)準(zhǔn)流處理器,將消息發(fā)送到標(biāo)準(zhǔn)輸出流、錯(cuò)誤流-->logging.StreamHandler(sys.stdout)#sys.stdout表示的是指向控制臺(tái)即標(biāo)準(zhǔn)輸出;當(dāng)我們?cè)赑ython中打印對(duì)象調(diào)用print obj時(shí)候,事實(shí)上是調(diào)用了sys.stdout.write(obj+'\n')。
print將你需要的內(nèi)容打印到了控制臺(tái),然后追加了一個(gè)換行符
logging.FileHandler文件處理器,將消息發(fā)送到文件-->logging.FileHandler(log_path)
logging.RotatingFileHandler文件處理器,文件達(dá)到指定大小后,啟用新文件存儲(chǔ)日志
logging.TimedRotatingFileHandler文件處理器,日志以特定的時(shí)間間隔輪換日志文件
handle類的一些常用的方法
Filter
filter組件用來(lái)過(guò)濾logger對(duì)象,一個(gè)filter可以直接添加到logger對(duì)象上,也可以添加到handler對(duì)象上,而如果在logger和handler中都設(shè)置了filter,則日志是先通過(guò)logger的filter,再通過(guò)handler的filter。由于所有的信息都可以經(jīng)過(guò)filter,所以filter不僅可以過(guò)濾信息,還可以增加信息。
Filter類的實(shí)例化對(duì)象可以通過(guò)logging.Filter(name)來(lái)創(chuàng)建,其中name為記錄器的名字,如果沒(méi)有創(chuàng)建過(guò)該名字的記錄器,就不會(huì)輸出任何日志:
filter=logging.Filter("foo.a")
基本過(guò)濾器類只允許低于指定的日志記錄器層級(jí)結(jié)構(gòu)中低于特定層級(jí)的事件,例如這個(gè)用foo.a初始化的過(guò)濾器,則foo.a.b;foo.a.c等日志記錄器記錄的日志都可以通過(guò)過(guò)濾器,而foo.c;a.foo等就不能通過(guò)。如果name為空字符串,則所有的日志都能通過(guò)。
Filter類有三個(gè)方法:
addFilter(filter):為logger(logger..addFilter(filter))或者h(yuǎn)andler(handler..addFilter(filter))增加過(guò)濾器
removeFilter(filter):為logger或者h(yuǎn)andler刪除一個(gè)過(guò)濾器
filter(record):表示是否要記錄指定的記錄?返回零表示否,非零表示是。一般自定義Filter需要繼承Filter基類,并重寫(xiě)filter方法
Formatter
格式化日志的輸出;實(shí)例化:formatter=logging.Formatter(fmt=None,datefmt=None);如果不指明fmt,將默認(rèn)使用‘%(message)s’,如果不指明datefmt,將默認(rèn)使用ISO8601日期格式。
其中fmt參數(shù)有以下選項(xiàng):
例如:
formatter=logging.Formatter('%(asctime)s%(levelname)-8s:%(message)s')#-表示右對(duì)齊8表示取8位 handler.formatter=formatter
datefmt參數(shù)有以下選項(xiàng):
例如:
formatter=logging.Formatter('%(asctime)s%(levelname)-8s:%(message)s')#-表示右對(duì)齊8表示取8位
handler.formatter=formatter
datefmt參數(shù)有以下選項(xiàng):
例子:
formatter=logging.Formatter("%(asctime)s%(levelname)s%(message)s","%Y%m%d-%H:%M:%S") handler.formatter=formatter
logging的配置
conf形式的配置
在loguser.conf中寫(xiě)入相關(guān)的信息
[loggers] keys=root,fileLogger,rotatingFileLogger [handlers] keys=consoleHandler,fileHandler,rotatingFileHandler [formatters] keys=simpleFormatter [logger_root] level=INFO handlers=consoleHandler [logger_fileLogger] level=INFO handlers=fileHandler qualname=fileLogger propagate=0 [logger_rotatingFileLogger] level=INFO handlers=consoleHandler,rotatingFileHandler qualname=rotatingFileLogger propagate=0 [handler_consoleHandler] class=StreamHandler level=INFO formatter=simpleFormatter args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=INFO formatter=simpleFormatter args=("logs/fileHandler_test.log","a") [handler_rotatingFileHandler] class=handlers.RotatingFileHandler level=WARNING formatter=simpleFormatter args=("logs/rotatingFileHandler.log","a",10*1024*1024,50) [formatter_simpleFormatter] format=%(asctime)s-%(module)s-%(levelname)s-%(thread)d:%(message)s datefmt=%Y-%m-%d%H:%M:%S
在使用logger時(shí),直接導(dǎo)入配置文件即可
from logging import config with open('./loguser.conf','r',encoding='utf-8')as f: ##加載配置 config.fileConfig(f) ##創(chuàng)建同名Logger,其按照配置文件的handle,formatter,filter方法初始化 logger=logging.getLogger(name="fileLogger")
yaml形式配置文件
在loguser.yaml文件中配置相關(guān)信息 version:1 disable_existing_loggers:False #formatters配置了日志輸出時(shí)的樣式 #formatters定義了一組formatID,有不同的格式; formatters: brief: format:"%(asctime)s-%(message)s" simple: format:"%(asctime)s-[%(name)s]-[%(levelname)s]:%(levelno)s:%(message)s" datefmt:'%F%T' #handlers配置了需要處理的日志信息,logging模塊的handler只有streamhandler和filehandler handlers: console: class:logging.StreamHandler formatter:brief level:DEBUG stream:ext://sys.stdout info_file_handler: class:logging.FileHandler formatter:simple level:ERROR filename:./logs/debug_test.log error_file_handler: class:logging.handlers.RotatingFileHandler level:ERROR formatter:simple filename:./logs/errors.log maxBytes:10485760#10MB#1024*1024*10 backupCount:50 encoding:utf8 loggers: #fileLogger,就是在代碼中通過(guò)logger=logging.getLogger("fileLogger")來(lái)獲得該類型的logger my_testyaml: level:DEBUG handlers:[console,info_file_handler,error_file_handler] #root為默認(rèn)情況下的輸出配置,當(dāng)logging.getLogger("fileLoggername")里面的fileLoggername沒(méi)有傳值的時(shí)候, #就是用的這個(gè)默認(rèn)的root,如logging.getLogger(__name__)或logging.getLogger() root: level:DEBUG handlers:[console]
同樣的可以通過(guò)導(dǎo)入yaml文件加載配置
with open('./loguser.yaml','r',encoding='utf-8')as f: yaml_config=yaml.load(stream=f,Loader=yaml.FullLoader) config.dictConfig(config=yaml_config) root=logging.getLogger() #子記錄器的名字與配置文件中l(wèi)oggers字段內(nèi)的保持一致 #loggers: #my_testyaml: #level:DEBUG #handlers:[console,info_file_handler,error_file_handler] my_testyaml=logging.getLogger("my_testyaml")
logging和print的區(qū)別
看起來(lái)logging要比print復(fù)雜多了,那么為什么推薦在項(xiàng)目中使用logging記錄日志而不是使用print輸出程序信息呢。
相比與print logging具有以下優(yōu)點(diǎn):
可以通過(guò)設(shè)置不同的日志等級(jí),在release版本中只輸出重要信息,而不必顯示大量的調(diào)試信息;
print將所有信息都輸出到標(biāo)準(zhǔn)輸出中,嚴(yán)重影響開(kāi)發(fā)者從標(biāo)準(zhǔn)輸出中查看其它數(shù)據(jù);logging則可以由開(kāi)發(fā)者決定將信息輸出到什么地方,以及怎么輸出;
和print相比,logging是線程安全的。(python 3中print也是線程安全的了,而python 2中的print不是)(線程安全是指在多線程時(shí)程序不會(huì)運(yùn)行混亂;而python 2中的print分兩步打印信息,第一打印字符串,第二打印換行符,如果在這中間發(fā)生線程切換就會(huì)產(chǎn)生輸出混亂。這就是為什么python2的print不是原子操作,也就是說(shuō)其不是線程安全的)印信息,第一打印字符串,第二打印換行符,如果在這中間發(fā)生線程切換就會(huì)產(chǎn)生輸出混亂。這就是為什么python2的print不是原子操作,也就是說(shuō)其不是線程安全的)
綜上所述,具體的詳細(xì)內(nèi)容,小編就給大家介紹完畢了,希望可以給大家?guī)?lái)幫助。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/127992.html
摘要:每一條日志記錄也包含級(jí)別,代表對(duì)應(yīng)消息的嚴(yán)重程度。即格式化器,主要功能是確定最終輸出的形式和內(nèi)容。最好是日志能夠按自然天進(jìn)行記錄和分割。 上一章學(xué)習(xí)了自動(dòng)化測(cè)試,很好,現(xiàn)在我們可以絞盡腦汁寫(xiě)出一份全面的測(cè)試,來(lái)保證代碼永遠(yuǎn)健康了。 話雖如此,但是作為一個(gè)獨(dú)立開(kāi)發(fā)者很難寫(xiě)出真正全面的測(cè)試代碼。這是因?yàn)橛脩粼谑褂媚愕木W(wǎng)站時(shí)可不會(huì)循規(guī)蹈矩,而是會(huì)以各種怪異的姿勢(shì)瀏覽網(wǎng)頁(yè)、上傳數(shù)據(jù)。但這也不是...
Python的三種主要模塊介紹 小編寫(xiě)這篇文章的主要目的,給大家介紹三種主要的模塊,包括系統(tǒng)內(nèi)的幾種模塊,對(duì)其做個(gè)具體的介紹,下面就給大家詳細(xì)的解答下?! ≡趐ython中,一個(gè)文件(以.py為后綴名的文件)就叫做一個(gè)模塊,每一個(gè)模塊在python里都被看做是一個(gè)獨(dú)立的文件?! ∧K可以被項(xiàng)目中的其他模塊、一些腳本甚至是交互式的解析器所使用,它可以被其他程序引用,從而使用該模塊里的函數(shù)等功能...
摘要:盡量使用內(nèi)置的異常處理語(yǔ)句來(lái)替換語(yǔ)句,比如語(yǔ)句,方法。以上是最簡(jiǎn)單的重新拋出異常的做法,也是推薦的做法。除了包含所有的外還包含了,和三個(gè)異常。避免在語(yǔ)句塊中干一些沒(méi)意義的事情,捕獲異常也是需要成本的。 異常處理在任何一門編程語(yǔ)言里都是值得關(guān)注的一個(gè)話題,良好的異常處理可以讓你的程序更加健壯,清晰的錯(cuò)誤信息更能幫助你快速修復(fù)問(wèn)題。在Python中,和不部分高級(jí)語(yǔ)言一樣,使用了try/ex...
摘要:下載器負(fù)責(zé)獲取頁(yè)面,然后將它們交給引擎來(lái)處理。內(nèi)置了一些下載器中間件,這些中間件將在后面介紹。下載器中間件下載器中間件可以在引擎和爬蟲(chóng)之間操縱請(qǐng)求和響應(yīng)對(duì)象。爬蟲(chóng)中間件與下載器中間件類似,啟用爬蟲(chóng)中間件需要一個(gè)字典來(lái)配置。 前段時(shí)間我寫(xiě)了一篇《scrapy快速入門》,簡(jiǎn)單介紹了一點(diǎn)scrapy的知識(shí)。最近我的搬瓦工讓墻了,而且我又學(xué)了一點(diǎn)mongodb的知識(shí),所以這次就來(lái)介紹一些scr...
閱讀 1170·2023-01-14 11:38
閱讀 1160·2023-01-14 11:04
閱讀 987·2023-01-14 10:48
閱讀 2538·2023-01-14 10:34
閱讀 1241·2023-01-14 10:24
閱讀 1124·2023-01-14 10:18
閱讀 736·2023-01-14 10:09
閱讀 818·2023-01-14 10:02