Python?內(nèi)置logging?使用詳細(xì)介紹
logging 的主要作用
提供日志記錄的接口和眾多處理模塊,供用戶(hù)存儲(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)行的一些信息(類(lèi)似于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')上面代碼中 logging 并沒(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):
| 參數(shù) | 功能 |
|---|---|
| filename | 指定保存日志的文件名,用指定文件名創(chuàng)建一個(gè)FileHandler,記錄的日志會(huì)保存到該文件中 |
| format | 指定輸出的格式和內(nèi)容,默認(rèn)是以冒號(hào)分割的levalname、name 和 message |
| datefmt | 使用指定的日期/時(shí)間格式,與 time.strftime() 所接受的格式相同。 |
| level | 指定根日志記錄器級(jí)別,默認(rèn)為 logging.WARNING |
| stream | 指定日志的輸出流,可以指定輸出到sys.stderr,std.stdout 或 文件,默認(rèn)輸出到sys.stderr。使用指定的流初始化StramHandler,注意:stream和filename參數(shù)不兼容,如果兩者同時(shí)使用,則會(huì)引發(fā)ValueError 錯(cuò)誤 |
例如下面通過(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 的四大組件(類(lèi))
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)前模塊的名稱(chēng)當(dāng)作記錄器的名字 logging.getLogger(__name__)
子級(jí)記錄器通常不需要單獨(dú)設(shè)置日志級(jí)別以及 Handler,如果子級(jí)記錄器沒(méi)有單獨(dú)設(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à),就會(huì)找到根記錄器root logger,root默認(rèn)的級(jí)別為WARGING。
logger類(lèi)的一些常用的方法
| 方法 | 功能描述 |
|---|---|
| Logger.setLevel() | 設(shè)置日志器(Logger)將會(huì)處理的日志消息級(jí)別 |
| Logger.addHandler() | 添加一個(gè)handler對(duì)象 |
| Logger.removeHandler() | 移除一個(gè)handler對(duì)象 |
| Logger.addFilter() | 添加一個(gè)filter對(duì)象 |
| Logger.removeFilter() | 移除一個(gè)filter對(duì)象 |
| Logger.debug() | 設(shè)置DEBUG級(jí)別的日志記錄 |
| Logger.info() | 設(shè)置INFO級(jí)別的日志記錄 |
| Logger.warning() | 設(shè)置WARNING級(jí)別的日志記錄 |
| Logger.error() | 設(shè)置ERROR級(jí)別的日志記錄 |
| Logger.critical() | 設(shè)置CRITICAL級(jí)別的日志記錄 |
| Logger.exception() | 輸出堆棧追蹤信息 |
| Logger.log() | 設(shè)置一個(gè)自定義的level參數(shù)來(lái)創(chuàng)建一個(gè)日志記錄 |
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è)?Python 中打印對(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 類(lèi)的一些常用的方法
| Handler.setLevel() | 設(shè)置處理器將會(huì)處理的日志消息的最低嚴(yán)重級(jí)別 |
| Handler.setFormatter() | 為處理器設(shè)置一個(gè)格式對(duì)象 |
| Handler.addFilter() | 為處理器添加一個(gè)過(guò)濾器對(duì)象 |
| Handler.removeFilter() | 為處理器刪除一個(gè)過(guò)濾器對(duì)象 |
| logging.StramHandler() | 將日志消息發(fā)送到輸出Stream,如std.out,std.err |
| logging.FilterHandler() | 將日志消息發(fā)送到磁盤(pán)文件,默認(rèn)情況文件大小會(huì)無(wú)線(xiàn)增長(zhǎng) |
| RotationFileHandler() | 將日志消息發(fā)送到磁盤(pán)文件,支持日志文件按大小切割 |
| TimeRotatingFileHandler() | 將日志消息發(fā)送到磁盤(pán)文件,并支持日志文件按時(shí)間切割 |
| logging.handers.HTTPHandler() | 將日志消息通過(guò)GET或POST的方式發(fā)送給一個(gè)HTTP服務(wù)器 |
| logging.handlers.SMTPHandler() | 將日志消息發(fā)送email地址 |
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 類(lèi)的實(shí)例化對(duì)象可以通過(guò) logging.Filter(name) 來(lái)創(chuàng)建,其中name 為 記錄器的名字,如果沒(méi)有創(chuàng)建過(guò)該名字的記錄器,就不會(huì)輸出任何日志:
filter = logging.Filter("foo.a")
基本過(guò)濾器類(lèi)只允許低于指定的日志記錄器層級(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 類(lèi) 有 三個(gè)方法 :
- addFilter(filter) : 為 logger(logger..addFilter(filter)) 或者 handler(handler..addFilter(filter)) 增加過(guò)濾器
- removeFilter(filter) : 為 logger 或者 handler 刪除一個(gè)過(guò)濾器
- filter(record) : 表示是否要記錄指定的記錄?返回零表示否,非零表示是。一般自定義Filter需要繼承Filter基類(lèi),并重寫(xiě)filter方法
Formatter
格式化日志的輸出;實(shí)例化:formatter = logging.Formatter(fmt=None,datefmt=None); 如果不指明 fmt,將默認(rèn)使用 ‘%(message)s’ ,如果不指明 datefmt,將默認(rèn)使用 ISO8601 日期格式。
其中 fmt 參數(shù) 有以下選項(xiàng):
| %(name)s | Logger的名字 |
|---|---|
| %(levelno)s | 數(shù)字形式的日志級(jí)別 |
| %(levelname)s | 文本形式的日志級(jí)別;如果是logger.debug則它是DEBUG,如果是logger.error則它是ERROR |
| %(pathname)s | 調(diào)用日志輸出函數(shù)的模塊的完整路徑名,可能沒(méi)有 |
| %(filename)s | 調(diào)用日志輸出函數(shù)的模塊的文件名 |
| %(module)s | 調(diào)用日志輸出函數(shù)的模塊名 |
| %(funcName)s | 調(diào)用日志輸出函數(shù)的函數(shù)名 |
| %(lineno)d | 調(diào)用日志輸出函數(shù)的語(yǔ)句所在的代碼行 |
| %(created)f | 當(dāng)前時(shí)間,用UNIX標(biāo)準(zhǔn)的表示時(shí)間的浮 點(diǎn)數(shù)表示 |
| %(relativeCreated)d | 輸出日志信息時(shí)的,自L(fǎng)ogger創(chuàng)建以 來(lái)的毫秒數(shù) |
| %(asctime)s | 字符串形式的當(dāng)前時(shí)間。默認(rèn)格式是 “2003-07-08 16:49:45,896”。逗號(hào)后面的是毫秒 |
| %(thread)d | 線(xiàn)程ID??赡軟](méi)有 |
| %(threadName)s | 線(xiàn)程名。可能沒(méi)有 |
| %(process)d | 進(jìn)程ID。可能沒(méi)有 |
| %(message)s | 用戶(hù)輸出的消息; 假如有l(wèi)ogger.warning("NO Good"),則在%(message)s位置上是字符串NO Good |
例如:
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s') # -表示右對(duì)齊 8表示取8位
handler.formatter = formatter
datefmt 參數(shù) 有以下選項(xiàng):
| 參數(shù) | 含義 |
|---|---|
| %y | 兩位數(shù)的年份表示(00-99) |
| %Y | 四位數(shù)的年份表示(000-9999) |
| %m | 月份(01-12) |
| %d | 月內(nèi)中的一天(0-31) |
| %H | 24小時(shí)制小時(shí)數(shù)(0-23) |
| %I | 12小時(shí)制小時(shí)數(shù)(01-12) |
| %M | 分鐘數(shù)(00=59) |
| %S 秒 | (00-59) |
例如:
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s') # -表示右對(duì)齊 8表示取8位
handler.formatter = formatter
datefmt 參數(shù) 有以下選項(xiàng):
| 參數(shù) | 含義 |
|---|---|
| %y | 兩位數(shù)的年份表示(00-99) |
| %Y | 四位數(shù)的年份表示(000-9999) |
| %m | 月份(01-12) |
| %d | 月內(nèi)中的一天(0-31) |
| %H | 24小時(shí)制小時(shí)數(shù)(0-23) |
| %I | 12小時(shí)制小時(shí)數(shù)(01-12) |
| %M | 分鐘數(shù)(00=59) |
| %S 秒 | (00-59) |
例子:
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)獲得該類(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 是線(xiàn)程安全的。(python 3中 print 也是線(xiàn)程安全的了,而python 2中的print不是)(線(xiàn)程安全是指在多線(xiàn)程時(shí)程序不會(huì)運(yùn)行混亂;而python 2 中的print 分兩步打印信息,第一打印字符串,第二打印換行符,如果在這中間發(fā)生線(xiàn)程切換就會(huì)產(chǎn)生輸出混亂。這就是為什么python2的print不是原子操作,也就是說(shuō)其不是線(xiàn)程安全的)印信息,第一打印字符串,第二打印換行符,如果在這中間發(fā)生線(xiàn)程切換就會(huì)產(chǎn)生輸出混亂。這就是為什么python2的print不是原子操作,也就是說(shuō)其不是線(xiàn)程安全的)
主要參考資料
https://blog.csdn.net/weixin_41010198/article/details/89356417
https://www.cnblogs.com/chenyibai/p/10676574.html
到此這篇關(guān)于Python 內(nèi)置logging 使用詳細(xì)講的文章就介紹到這了,更多相關(guān)Python 內(nèi)置logging內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python入門(mén)教程(三十四)Python的文件處理
這篇文章主要介紹了Python入門(mén)教程(三十四)Python的文件處理,在Python中處理文件的主要是open()函數(shù),接下來(lái)我們就來(lái)一起看看open()函數(shù)的用法吧,需要的朋友可以參考下2023-05-05
Python控制windows系統(tǒng)音量實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Python控制windows系統(tǒng)音量實(shí)現(xiàn)實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01
python實(shí)現(xiàn)小世界網(wǎng)絡(luò)生成
今天小編就為大家分享一篇python實(shí)現(xiàn)小世界網(wǎng)絡(luò)生成,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
python 實(shí)現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例
今天小編就為大家分享一篇python 實(shí)現(xiàn)圖片旋轉(zhuǎn) 上下左右 180度旋轉(zhuǎn)的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01

