Python日誌模塊01

一、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
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章