logging 模塊是一個較龐大的模塊。具備較完備的日誌體系。
主要分爲:主體 Logger - 處理器 - 格式器logging 爲 python 內置模塊,無需安裝。
導入方式: import logging 便可html
DEBUG < INFO < WARNING < ERROR < FATAL DEBUG : 開發調試的一些信息(print調試。。。) INFO: 程序運行過程的重要信息(不宜過多) WARNING: 不影響程序運行的小問題,警告一下。記錄下來以備之後解決。 ERROR: 影響程序, 有點嚴重。須要處理, 否則程序 (可能,可能)就掛了。 FATAL: 嚴重影響程序,馬上從新排查,修改代碼吧。
經常使用分爲: (由外到裏的包含關係)python
爲了方便說明,接下來,我會把上面的組件「由裏到外」講解。git
格式器:用來定義一些打印信息的字符串格式化的語法。
初始化一個 格式器:github
fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 console_formatter = logging.Formatter(fmt=fmt) # 實例化格式器,並把格式傳進來
理解方式:服務器
我把上例結果貼一下,你可能會看明白些:函數
>>> [2019-09-10 18:23:19,347] [logging11.py: 15] [WARNING] => 哈哈哈 asctime 是日期 filename 是文件名 lineno 是代碼行 levelname 是日誌等級名 (就是上面說的 INFO WARNING ERROR之類的) message 是 你要打印的日誌信息 (下面會講到,這裏先小小埋一個點)
處理器:用來裝載上面說的 「格式器」,並處理日誌 (處理器有不少種,按需選1個便可,下面說2種經常使用的):
初始化一個 「流處理器」 (比較經常使用):線程
handler = logging.StreamHandler()
或初始化一個 「文件處理器」 (源碼明確寫了, 它繼承的是 上面的 「流處理器」。一般用來日誌持久化):debug
handler = logging.FileHandler('mylog.log', mode='a', encoding='utf-8') # 沒必要解釋了吧。 這API語法很熟悉了吧。 這不就是咱們經常使用的文件 open 語法麼。。。。
裝載「格式器」 (差點忘了吧。實例化的格式器,還沒用呢, 就是在這裏裝載)調試
handler.setFormatter(fmt=file_formatter)
注意: 雖然 handler對象就能夠用 setLevel()設置日誌等級,但我不推薦在這裏設置。繼續往下看日誌
Logger: 用來裝載 「處理器的」。
實例化Logger有兩種方法:
方法1:(非共享式建立, 不推薦)
log= logging.Logger(name='my_log', level='INFO') # name 是給 Logger 起的名 # level是 日誌等級(注意要大寫), 開篇咱們講到過, WARNING, INFO, ERROR 這些。
方法2:(Log池共享式建立, 推薦)
log = logging.getLogger(name='console') # 有則取出,無則建立 # name若是不傳,則取出root Logger (root Logger是logging默認給咱們提供的,我通常不用)
說一下這兩種方法的區別:
裝載 "處理器" :(差點忘了吧, 上面定義的 處理器,還沒用呢, 就是在這裏用的):
log.addHandler(handler)
設置日誌等級 (這步可忽略)
log.setLevel('ERROR') 其實上面咱們實例化Logger的時候,咱們就已經傳了一個 level參數,設置好了 日誌等級。 因此 log.setLevel() 這個能夠不設置 (包括前面提到,handler也有 setLevel) handler.setLevel()
開始輸出日誌信息,有如下日誌等級相對應的API:
log.debug ("這是一條 調試 日誌") log.info ("這是一條 顯示主要信息 日誌") log.warning('這是一條 警告 日誌') log.error ("這是一條 錯誤 日誌") log.fatal ("這是一條 致命錯誤 日誌") ### 回顧咱們前面講的 Formatter 格式器 咱們第一個講的就是格式器, 並說了一下經常使用格式。 其中有個 %(message)s, 它就是佔位上面這些API裏面的參數 eg: log.info('哈哈哈') %(message)s格式 佔位輸出的就是 哈哈哈 還有個 %(levelname)s,它就是佔位上面這些API的方法名 eg: log.info('xxx') %(levelname)s 格式佔位輸出的就是 info
若是你對日誌等級與日誌的做用感到模糊,你必定要看我接下來的例子!!!!!!!!
開篇時我就提過: 日誌等級排序(弱=>強) => (DEBUG < INFO < WARNING < ERROR < FATAL)你設置了一個日誌等級 。那麼你所用上面API對應的等級若「強於或等於」 此設定的等級,日誌纔會被處理
emmmmm, 若是沒聽懂,就當我放P了。。。 說的越正式,越不容易理解。 咱們仍是看下面的例子吧~~
日誌等級理解的小例子:
log.setLevel('WARNING') 你看咱們設置的日誌等級是 WARNING log.debug("這是一條 調試 日誌") # 這個 debug(), 你能夠去開篇列的"日誌等級排序"那裏瞅一眼。 # debug 比 warning 弱, 因此 這條日誌是 不會 被處理的。 # (白話理解:"我給的界限是warning, 你一個 debug等級過低了,問題不嚴重。不配被記錄。") log.info("這是一條 顯示主要信息 日誌") # 同理, info 也比 warning 弱, 此條日誌也 不會 被處理 log.warning('這是一條 警告 日誌') # warning == warning (我前面說了,強於 或 等於) 因此此條日誌會被處理 log.error("這是一條 錯誤 日誌") # error 比 warning 強, 因此此條日誌 會 被處理 log.fatal("這是一條 致命錯誤 日誌") # fatal 比 warning 強, 因此此條日誌 會 被處理 # 再白話一下:"你給個人容忍程度是 warning, 而你的這條日誌都致命錯誤了,我確定處理你啊"
思考!上例我一直說一句話 「xxxxx, 此條日誌纔會被處理」。
那麼這個「 處理」 ,究竟是處理什麼呢???
這時不妨回頭看看,上面講的 「處理器」, 嗯, 沒錯。 這些日誌就是 「處理器」 處理的。
業務需求以下(隨便舉個案例,不必定有用):
代碼以下(本身使用的話,封裝一下比較好):
import logging # 日誌等級排序(弱-> 強): DEBUG < INFO < WARNING < ERROR < FATAL fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 file_formatter = logging.Formatter(fmt=fmt) # 定義格式器, 把格式塞進來 file_handler = logging.FileHandler('mylog.log', mode='a', encoding='utf-8') # 定義文件處理器 file_handler.setFormatter(fmt=file_formatter) # 給文件處理器設置 一個 格式器 file_handler.setLevel('WARNING') # 給此處理器設置 日誌等級 console_handler = logging.StreamHandler() # 定義流處理器,用於輸出到終端 # StreamHandler未設置格式器,它會默認給你設置一個 %(message)s,即只有日誌內容,沒有日期文件名等 console_handler.setLevel('DEBUG') # 給流處理器設置 日誌等級 log = logging.getLogger(name='file_log') # log池中取出一個log(若沒有則新建) log.addHandler(file_handler) # 添加一個文件處理器(格式化 輸出到 文件) log.addHandler(console_handler) # 再添加一個流處理器(無格式 輸出到 終端) log.info('我只會輸出到終端') # 由於 info只比 console_handler 設置的 DEBUG強 log.error('我既會輸出到終端, 又會輸出到文件') # 由於error 比 console_handler 設置的 DEBUG 強, 同時 error 也比 file_handler 設置的 WARNING 強
運行結果:
終端輸出: >> 我只會輸出到終端 我既會輸出到終端, 又會輸出到文件 mylog.log 文件中: [2019-09-10 23:54:59,055] [logging11.py: 20] [ERROR] => 我既會輸出到終端, 又會輸出到文件
這種方式只方便了一點點,但不靈活。
前面咱們花了好大力氣,
其實 logging體系中, 有一個默認初始的 Logger, 叫作 root Logger.
咱們不須要實例化它,也不須要實例化"格式器", 也不須要實例化控制器。
一行API就可使用它 (默認是輸出到終端的):
import logging fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 logging.basicConfig( # 默認使用的就是 root Logger level='DEBUG', # 設置日誌等級爲DEBUG format=fmt, # 設置格式 ) logging.info('我只會輸出到終端') 運行結果: >> [2019-09-11 00:15:55,219] [logging11.py: 30] [INFO] => 我只會輸出到終端
若是想輸出到文件,那麼只需加 filename 和 filemode 兩個參數便可:
import logging fmt = '[%(asctime)s] [%(filename)s: %(lineno)d] [%(levelname)s] => %(message)s' # 格式 logging.basicConfig( level='DEBUG', format=fmt, filename='mylog.log', # 文件名 filemode='a' # 文件操做符 ) 運行結果: mylog.log文件: [2019-09-11 00:20:22,396] [logging11.py: 32] [INFO] => ��ֻ��������ն�
但你發現沒,往文件裏面輸出亂碼了, 用耳朵都能想出來,咱們沒有配置 encoding。。。
可是,我告訴你, basicConfig() 是沒有 encoding參數的。 那咋整 ??
但它有個參數叫作 handlers,handlers熟悉吧,沒錯就是咱們上面講的 "處理器", 複數說明能夠傳多個
logging.basicConfig( level='DEBUG', format=fmt, handlers=[ logging.FileHandler(filename='mylog.log',mode='a',encoding='utf-8') ] # 看這裏這個處理器的定義方法,和以前講過的如出一轍。在這裏咱們能夠配 encoding ) # 這樣就不會亂碼了
Note: 以上就是用 logging.baseConfig() 簡單日誌實現
說了它是投機取巧,由於除了文件亂碼有問題以外, 它還欠缺靈活性。
好比你想一想對不一樣級別的日誌,用不一樣格式輸出出來。這時你單用basicConfig一行是搞不定的。
因此仍是推薦用 getLogger()那套組合。
logging模塊其實還有不少不少功能:
過濾器:(其實還有個這個組件,但我沒用過,就沒說)
格式器:(前面給了官檔大全,裏面還有根據進程、線程的(PID,TID, tName,pName)等格式來輸出日誌。)
控制器:(我只說了 stream 和 file),其實還有不少,它們都在logging.handlers模塊下:
from logging.handlers import ( RotatingFileHandler, # 經過設置文件大小閾值,超出這個閾值,就會將日誌轉存新文件 TimedRotatingFileHandler, # 設置時間間隔,每過這個間隔,就會將日誌轉存新文件 HTTPHandler, # 經過HTTP協議將日誌輸出到遠程服務器,(只支持 GET 和 POST) SMTPHandler, # 經過SMTP協議,將日誌輸出到遠程郵箱了 SocketHandler, # 經過TCP協議發送到遠程服務器。。。 DatagramHandler, # 經過UDP協議發送到遠程服務器。。。 QueueHandler, # 發到隊列中(若是想發RabbitMQ之類的,能夠去github找別人寫的成品) ) # 這些用法也很簡單,看官檔,或者用Pycharm ctrl+左鍵點進源碼,看一下__init__()參數實例化便可 # 實例化後,用 xxx.addHandler() 添加到 logger便可使用 (和前面講的 file和stream用法同樣)
還可作成各種型配置文件使用:https://docs.python.org/3/lib...
官檔案例大全:https://docs.python.org/3/how...