一、logging模塊
日誌的作用可以簡單總結爲以下3點:
1、程序調試
2、瞭解軟件程序運行情況,是否正常
3、軟件程序運行故障分析與問題定位
1、日誌的等級
不同的應用程序所定義的日誌等級可能會有所差別,分的詳細點的會包含以下幾個等級:
級別 | 何時使用 |
---|---|
DEBUG | 詳細信息,典型地調試問題時會感興趣。 詳細的debug信息。 |
INFO | 證明事情按預期工作。 關鍵事件。 |
WARNING | 表明發生了一些意外,或者不久的將來會發生問題(如‘磁盤滿了’)。軟件還是在正常工作。 |
ERROR | 由於更嚴重的問題,軟件已不能執行一些功能了。 一般錯誤消息。 |
CRITICAL | 嚴重錯誤,表明軟件已不能繼續運行了。 |
NOTICE | 不是錯誤,但是可能需要處理。普通但是重要的事件。 |
ALERT | 需要立即修復,例如系統數據庫損壞。 |
EMERGENCY | 緊急情況,系統不可用(例如系統崩潰),一般會通知所有用戶。 |
2、日誌字段信息與日誌格式
一條日誌信息對應的是一個事件的發生,而一個事件通常需要包括以下幾個內容:
事件發生時間、事件發生位置、事件的嚴重程度–日誌級別、事件內容
上面這些都是一條日誌記錄中可能包含的字段信息,當然還可以包括一些其他信息,如進程ID、進程名稱、線程ID、線程名稱等。日誌格式就是用來定義一條日誌記錄中包含那些字段的,且日誌格式通常都是可以自定義的。
3、logging模塊的日誌級別
日誌等級(level) | 描述 |
---|---|
DEBUG | 最詳細的日誌信息,典型應用場景是 問題診斷 |
INFO | 信息詳細程度僅次於DEBUG,通常只記錄關鍵節點信息,用於確認一切都是按照我們預期的那樣進行工作 |
WARNING | 當某些不期望的事情發生時記錄的信息(如,磁盤可用空間較低),但是此時應用程序還是正常運行的 |
ERROR | 由於一個更嚴重的問題導致某些功能不能正常運行時記錄的信息 |
CRITICAL | 當發生嚴重錯誤,導致應用程序不能繼續運行時記錄的信息 |
4、logging模塊定義的模塊級別的常用函數
函數 | 說明 |
---|---|
logging.debug(msg, *args, **kwargs) | 創建一條嚴重級別爲DEBUG的日誌記錄 |
logging.info(msg, *args, **kwargs) | 創建一條嚴重級別爲INFO的日誌記錄 |
logging.warning(msg, *args, **kwargs) | 創建一條嚴重級別爲WARNING的日誌記錄 |
logging.error(msg, *args, **kwargs) | 創建一條嚴重級別爲ERROR的日誌記錄 |
logging.critical(msg, *args, **kwargs) | 創建一條嚴重級別爲CRITICAL的日誌記錄 |
logging.log(level, *args, **kwargs) | 創建一條嚴重級別爲level的日誌記錄 |
logging.basicConfig(**kwargs) | 對root logger進行一次性配置 |
5、logging.basicConfig()函數包含參數說明
參數名稱 | 描述 |
---|---|
filename | 指定日誌輸出目標文件的文件名(可以寫文件名也可以寫文件的完整的絕對路徑,寫文件名日誌放執行文件目錄下,寫完整路徑按照完整路徑生成日誌文件),指定該設置項後日志信心就不會被輸出到控制檯了 |
filemode | 指定日誌文件的打開模式,默認爲’a’。需要注意的是,該選項要在filename指定時纔有效 |
format | 指定日誌格式字符串,即指定日誌輸出時所包含的字段信息以及它們的順序。logging模塊定義的格式字段下面會列出。 |
datefmt | 指定日期/時間格式。需要注意的是,該選項要在format中包含時間字段%(asctime)s時纔有效 |
level | 指定日誌器的日誌級別 |
stream | 指定日誌輸出目標stream,如sys.stdout、sys.stderr以及網絡stream。需要說明的是,stream和filename不能同時提供,否則會引發 ValueError異常 |
style | Python 3.2中新添加的配置項。指定format格式字符串的風格,可取值爲’%’、’{‘和’$’,默認爲’%’ |
handlers | Python 3.3中新添加的配置項。該選項如果被指定,它應該是一個創建了多個Handler的可迭代對象,這些handler將會被添加到root logger。需要說明的是:filename、stream和handlers這三個配置項只能有一個存在,不能同時出現2個或3個,否則會引發ValueError異常。 |
6、logging模塊中定義好的可以用於format格式字符串說明
字段/屬性名稱 | 使用格式 | 描述 |
---|---|---|
asctime | %(asctime)s | 將日誌的時間構造成可讀的形式,默認情況下是‘2016-02-08 12:00:00,123’精確到毫秒 |
name | %(name)s | 所使用的日誌器名稱,默認是’root’,因爲默認使用的是 rootLogger |
filename | %(filename)s | 調用日誌輸出函數的模塊的文件名; pathname的文件名部分,包含文件後綴 |
funcName | %(funcName)s | 由哪個function發出的log, 調用日誌輸出函數的函數名 |
levelname | %(levelname)s | 日誌的最終等級(被filter修改後的) |
message | %(message)s | 日誌信息, 日誌記錄的文本內容 |
lineno | %(lineno)d | 當前日誌的行號, 調用日誌輸出函數的語句所在的代碼行 |
levelno | %(levelno)s | 該日誌記錄的數字形式的日誌級別(10, 20, 30, 40, 50) |
pathname | %(pathname)s | 完整路徑 ,調用日誌輸出函數的模塊的完整路徑名,可能沒有 |
process | %(process)s | 當前進程, 進程ID。可能沒有 |
processName | %(processName)s | 進程名稱,Python 3.1新增 |
thread | %(thread)s | 當前線程, 線程ID。可能沒有 |
threadName | %(thread)s | 線程名稱 |
module | %(module)s | 調用日誌輸出函數的模塊名, filename的名稱部分,不包含後綴即不包含文件後綴的文件名 |
created | %(created)f | 當前時間,用UNIX標準的表示時間的浮點數表示; 日誌事件發生的時間–時間戳,就是當時調用time.time()函數返回的值 |
relativeCreated | %(relativeCreated)d | 輸出日誌信息時的,自Logger創建以 來的毫秒數; 日誌事件發生的時間相對於logging模塊加載時間的相對毫秒數 |
msecs | %(msecs)d | 日誌事件發生事件的毫秒部分。logging.basicConfig()中用了參數datefmt,將會去掉asctime中產生的毫秒部分,可以用這個加上 |
二、logging模塊運用
1、簡單配置
默認的日誌格式爲日誌級別:Logger名稱:用戶輸出消息
import logging
logging.debug("debug message") #告警級別最低,只有在診斷問題時纔有興趣的詳細信息。
logging.info("info message") #告警級別比debug要高,確認事情按預期進行。
logging.warning("warning message") #告警級別比info要高,該模式是默認的告警級別!預示着一些意想不到的事情發生,或在不久的將來出現一些問題(例如“磁盤空間低”)。該軟件仍在正常工作。
logging.error("error message") #告警級別要比warning藥膏,由於一個更嚴重的問題,該軟件還不能執行某些功能。
logging.critical("critical message") #告警級別要比error還要高,嚴重錯誤,表明程序本身可能無法繼續運行。
#以上代碼執行結果如下:
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
2、簡單配置
import logging
logging.basicConfig(level=logging.DEBUG,
format="%(asctime)s %(name)s %(levelname)s %(message)s",
datefmt = '%Y-%m-%d %H:%M:%S %a' #注意月份和天數不要搞亂了,這裏的格式化符與time模塊相同
)
logging.debug("msg1")
logging.info("msg2")
logging.warning("msg3")
logging.error("msg4")
logging.critical("msg5")
#以上代碼執行結果如下:
2018-05-09 23:37:49 Wed root DEBUG msg1
2018-05-09 23:37:49 Wed root INFO msg2
2018-05-09 23:37:49 Wed root WARNING msg3
2018-05-09 23:37:49 Wed root ERROR msg4
2018-05-09 23:37:49 Wed root CRITICAL msg5
2、升級版
import logging
LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置輸出日誌格式
DATE_FORMAT = '%Y-%m-%d %H:%M:%S %a ' #配置輸出時間的格式,注意月份和天數不要搞亂了
logging.basicConfig(level=logging.DEBUG,
format=LOG_FORMAT,
datefmt = DATE_FORMAT ,
filename=r"d:\test.log" #有了filename參數就不會直接輸出顯示到控制檯,而是直接寫入文件
)
logging.debug("msg1")
logging.info("msg2")
logging.warning("msg3")
logging.error("msg4")
logging.critical("msg5")
#日誌在d:\目錄下,日誌具體內容
2019-08-08 09:54:31 Thu root DEBUG d:\Log.py msg1
2019-08-08 09:54:31 Thu root INFO d:\Log.py msg2
2019-08-08 09:54:31 Thu root WARNING d:\Log.py msg3
2019-08-08 09:54:31 Thu root ERROR d:\Log.py msg4
2019-08-08 09:54:31 Thu root CRITICAL d:\Log.py msg5
3、日誌流處理流程
logging日誌模塊四大組件
組件名稱 | 對應類名 | 功能描述 |
---|---|---|
日誌器 | Logger | 提供了應用程序可一直使用的接口 |
處理器 | Handler | 將logger創建的日誌記錄發送到合適的目的輸出 |
過濾器 | Filter | 提供了更細粒度的控制工具來決定輸出哪條日誌記錄,丟棄哪條日誌記錄 |
格式器 | Formatter | 決定日誌記錄的最終輸出格式 |
最常用的配置方法如下:
方法 | 描述 |
---|---|
Logger.setLevel() | 設置日誌器將會處理的日誌消息的最低嚴重級別 |
Logger.addHandler() | 和 Logger.removeHandler() 爲該logger對象添加 和 移除一個handler對象 |
Logger.addFilter() | 和 Logger.removeFilter() 爲該logger對象添加 和 移除一個filter對象 |
logger對象配置完成後,可以使用下面的方法來創建日誌記錄:
方法 | 描述 |
---|---|
Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical() | 創建一個與它們的方法名對應等級的日誌記錄 |
Logger.exception() | 創建一個類似於Logger.error()的日誌消息 |
Logger.log() | 需要獲取一個明確的日誌level參數來創建一個日誌記錄 |
關於logger的層級結構與有效等級的說明:
- logger的名稱是一個以’.‘分割的層級結構,每個’.‘後面的logger都是’.'前面的logger的children,例如,有一個名稱爲 foo 的logger,其它名稱分別爲 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的後代。
- logger有一個"有效等級(effective level)"的概念。如果一個logger上沒有被明確設置一個level,那麼該logger就是使用它parent的level;如果它的parent也沒有明確設置level則繼續向上查找parent的parent的有效level,依次類推,直到找到個一個明確設置了level的祖先爲止。需要說明的是,root logger總是會有一個明確的level設置(默認爲 WARNING)。當決定是否去處理一個已發生的事件時,logger的有效等級將會被用來決定是否將該事件傳遞給該logger的handlers進行處理。
- child loggers在完成對日誌消息的處理後,默認會將日誌消息傳遞給與它們的祖先loggers相關的handlers。因此,我們不必爲一個應用程序中所使用的所有loggers定義和配置handlers,只需要爲一個頂層的logger配置handlers,然後按照需要創建child loggers就可足夠了。我們也可以通過將一個logger的propagate屬性設置爲False來關閉這種傳遞機制。
Handler類:
Handler對象的作用是(基於日誌消息的level)將消息分發到handler指定的位置(文件、網絡、郵件等)。Logger對象可以通過addHandler()方法爲自己添加0個或者更多個handler對象。比如,一個應用程序可能想要實現以下幾個日誌需求:
1)把所有日誌都發送到一個日誌文件中;
2)把所有嚴重級別大於等於error的日誌發送到stdout(標準輸出);
3)把所有嚴重級別爲critical的日誌發送到一個email郵件地址。這種場景就需要3個不同的handlers,每個handler複雜發送一個特定嚴重級別的日誌到一個特定的位置。
Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
需要說明的是,應用程序代碼不應該直接實例化和使用Handler實例。因爲Handler是一個基類,它只定義了素有handlers都應該有的接口,同時提供了一些子類可以直接使用或覆蓋的默認行爲。下面是一些常用的Handler:
Handler | 描述 |
---|---|
logging.StreamHandler | 將日誌消息發送到輸出到Stream,如std.out, std.err或任何file-like對象。 |
logging.FileHandler | 將日誌消息發送到磁盤文件,默認情況下文件大小會無限增長 |
logging.handlers.RotatingFileHandler | 將日誌消息發送到磁盤文件,並支持日誌文件按大小切割 |
logging.hanlders.TimedRotatingFileHandler | 將日誌消息發送到磁盤文件,並支持日誌文件按時間切割 |
logging.handlers.HTTPHandler | 將日誌消息以GET或POST的方式發送給一個HTTP服務器 |
logging.handlers.SMTPHandler | 將日誌消息發送給一個指定的email地址 |
logging.NullHandler | 該Handler實例會忽略error messages,通常被想使用logging的library開發者使用來避免’No handlers could be found for logger XXX’信息的出現。 |
import logging
def log():
#創建logger,如果參數爲空則返回root logger
logger = logging.getLogger("nick")
logger.setLevel(logging.DEBUG) #設置logger日誌等級
#這裏進行判斷,如果logger.handlers列表爲空,則添加,否則,直接去寫日誌
if not logger.handlers:
#創建handler
fh = logging.FileHandler("test.log",encoding="utf-8")
ch = logging.StreamHandler()
#設置輸出日誌格式
formatter = logging.Formatter(
fmt="%(asctime)s %(name)s %(filename)s %(message)s",
datefmt="%Y/%m/%d %X"
)
#爲handler指定輸出格式
fh.setFormatter(formatter)
ch.setFormatter(formatter)
#爲logger添加的日誌處理器
logger.addHandler(fh)
logger.addHandler(ch)
return logger #直接返回logger
logger = log()
logger.warning("泰拳警告")
logger.info("提示")
logger.error("錯誤")
logger.debug("查錯")
4、按照時間自動截斷並保存指定文件個數的案例
import logging
from logging import handlers
logger = logging.getLogger(__name__)
log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3) #filename定義將信息輸入到指定的文件,
# when指定單位是s(秒),interval是時間間隔的頻率,單位是when所指定的喲(所以,你可以理解頻率是5s);backupCount表示備份的文件個數,我這裏是指定的3個文件。
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s') #定義輸出格式
fh.setFormatter(formatter) #添加格式化輸出
logger.addHandler(fh)
logger.warning("test1")
logger.warning("test2")
logger.warning("test3")
logger.warning("test4")
作者:oopp8
鏈接:https://www.jianshu.com/p/e5595fd9f0e8
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。