官方文檔:html
https://docs.python.org/2/library/logging.htmlpython
logging模塊提供了兩種記錄日誌的方式:程序員
其實,logging所提供的模塊級別的日誌記錄函數也是對logging日誌系統相關類的封裝而已。網絡
logging模塊定義的模塊級別的經常使用函數:app
函數 | 說明 |
---|---|
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進行一次性配置 |
其中logging.basicConfig(**kwargs)
函數用於指定「要記錄的日誌級別」、「日誌格式」、「日誌輸出位置」、「日誌文件的打開模式」等信息,其餘幾個都是用於記錄各個級別日誌的函數。socket
具體以下:函數
參數名稱性能 |
描述測試 |
filenamethis |
將日誌信息寫入文件中,指定該設置項後日志信息就不會被輸出到控制檯了 |
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異常。 |
上面的時間須要使用format中包含時間段,過於format還有以下參數:
字段/屬性名稱 |
使用格式 |
描述 |
asctime |
%(asctime)s |
日誌事件發生的時間--人類可讀時間,如:2003-07-08 16:49:45,896 |
created |
%(created)f |
日誌事件發生的時間--時間戳,就是當時調用time.time()函數返回的值 |
relativeCreated |
%(relativeCreated)d |
日誌事件發生的時間相對於logging模塊加載時間的相對毫秒數(目前還不知道幹嗎用的) |
msecs |
%(msecs)d |
日誌事件發生事件的毫秒部分 |
levelname |
%(levelname)s |
該日誌記錄的文字形式的日誌級別('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') |
levelno |
%(levelno)s |
該日誌記錄的數字形式的日誌級別(10, 20, 30, 40, 50) |
name |
%(name)s |
所使用的日誌器名稱,默認是'root',由於默認使用的是 rootLogger |
message |
%(message)s |
日誌記錄的文本內容,經過 msg % args計算獲得的 |
pathname |
%(pathname)s |
調用日誌記錄函數的源碼文件的全路徑 |
filename |
%(filename)s |
pathname的文件名部分,包含文件後綴 |
module |
%(module)s |
filename的名稱部分,不包含後綴 |
lineno |
%(lineno)d |
調用日誌記錄函數的源代碼所在的行號 |
funcName |
%(funcName)s |
調用日誌記錄函數的函數名 |
process |
%(process)d |
進程ID |
processName |
%(processName)s |
進程名稱,Python 3.1新增 |
thread |
%(thread)d |
線程ID |
threadName |
%(thread)s |
線程名稱 |
1、使用logging提供的模塊級別的函數記錄日誌
logging的日誌級別由低到高分爲 debug(), info(), warning(), error() and critical() 5個級別
CRITICAL(50) > ERROR(40) > WARNING(30) > INFO(20) > DEBUG(10)
簡單使用示例:
import logging logging.basicConfig(filename="E:\\logging\\abc.log", format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %I:%M:%S %p', level=logging.WARNING) logger = logging.getLogger()
logger.debug("The debug.") logger.info("The info.") logger.warning("The warning.") logger.error("The error.") logger.critical("The critical.") print(logger.level)
運行結果:
查看E:\\logging\\abc.log文件中的內容,以下:
能夠看到,因爲設置的日誌級別爲WARNING,因此只打印了比WARNING級別更高的日誌。
2、使用logging四大組件記錄日誌
logger:提供日誌接口,供應用代碼使用。logger最長用的操做有兩類:配置和發送日誌消息。能夠經過logging.getLogger(name)獲取logger對象,
若是不指定name則返回root對象,屢次使用相同的name調用getLogger方法返回同一個logger對象 handler:將日誌記錄(log record)發送到合適的目的地(destination),好比文件,socket等。一個logger對象能夠經過addHandler方法添加多個handler,
每一個handler又能夠定義不一樣日誌級別,以實現日誌分級過濾顯示 filter:提供方式決定一個日誌記錄是否發送到handler formatter:指定日誌記錄輸出的具體格式。formatter的構造方法須要兩個參數:消息的格式字符串和日期字符串,這兩個參數都是可選的
如上面所說,logging.basicConfig()函數中可經過具體參數來更改logging模塊的行爲
日誌同時打印到屏幕和文件:
import logging # 建立一個日誌對象
logg = logging.getLogger("測試日誌") # 定義一個模板
FORMATTER = logging.Formatter("%(asctime)s - %(name)s - [%(lineno)d] - %(message)s") # 建立一個屏幕流
p_stream = logging.StreamHandler() # 建立一個文件流
f_stream = logging.FileHandler("log.log", mode="a", encoding="utf-8") # 將流綁定到模板
p_stream.setFormatter(FORMATTER) f_stream.setFormatter(FORMATTER) # 將日誌和流進行綁定
logg.addHandler(p_stream) logg.addHandler(f_stream) # 設置日誌記錄等級
logg.setLevel(logging.DEBUG) # 打印日誌信息
logg.debug("this is Debug") logg.info("this is info") logg.warning("this is warning") logg.error("this is error") logg.critical("this is critical")
運行結果:
若是想爲多個用戶建立不一樣的日誌,只須要建立流時建立不一樣的流便可,而不須要建立多個日誌對象,若是狀況特殊考慮單獨在建立一個對象。其實咱們能夠在建立流的時候直接指定日誌等級。流的等級是優先於日誌對象的。
以下建立兩個流:
import logging # 建立一個日誌對象
logg = logging.getLogger("測試日誌") # 建立一個程序員模板和老闆模板
CORE_FORMATTER = logging.Formatter("%(asctime)s - %(name)s - [%(lineno)d] - %(message)s") BOOS_FORMATTER = logging.Formatter("%(asctime)s - %(message)s") # 建立一個程序員的流和一個老闆的流
core_stream = logging.FileHandler("core.log", mode="a", encoding="utf-8") boos_stream = logging.FileHandler("boos.log", mode="a", encoding="utf-8") # 設置日誌等級(老闆的日誌等級設置WARNING)
boos_stream.setLevel(logging.WARNING) # 將流綁定到模板
core_stream.setFormatter(CORE_FORMATTER) boos_stream.setFormatter(BOOS_FORMATTER) # 將日誌和流進行綁定
logg.addHandler(core_stream) logg.addHandler(boos_stream) # 設置日誌記錄等級
logg.setLevel(logging.DEBUG) # 打印日誌信息
logg.debug("this is Debug") logg.info("this is info") logg.warning("this is warning") logg.error("this is error") logg.critical("this is critical")
運行結果:
這樣咱們便建立了兩種不一樣的日誌
三、日誌分割
將日誌信息輸出到一個單一的文件中,隨着應用程序的持續使用,該日誌文件會愈來愈龐大,進而影響系統的性能。所以,有必要對日誌文件按某種條件進行切分。
分割日誌的觸發條件:大小、日期,或者大小加上日期。
說是切分,其實是,當一個日誌文件達到觸發條件後,對日誌文件進行重命名,以後再新建原來名稱的日誌文件(此時就是空文件了),新產生的日誌就寫入新的日誌文件。
爲啥叫回滾呢?當分割的日誌文件達到指定數目的上限個數時,最老的日誌文件就會被刪除。
logging庫提供了2個能夠用於日誌滾動的class,一個是RotatingFileHandler,它主要是根據日誌文件的大小進行滾動;另外一個是TimeRotatingFileHandler,它主要是根據時間進行滾動。在實際應用中,一般根據時間進行滾動。
TimedRotatingFileHandler的構造函數定義以下:
TimedRotatingFileHandler(filename [,when [,interval [,backupCount]]]) filename 是輸出日誌文件名的前綴,好比log/myapp.log when 的定義以下: 「S」: Seconds 「M」: Minutes 「H」: Hours 「D」: Days 「W」: Week day (0=Monday) 「midnight」: Roll over at midnight interval:指等待多少個單位when的時間後,Logger會自動重建文件,固然,這個文件的建立取決於filename+suffix,若這個文件跟以前的文件有重名,則會自動覆蓋掉之前的文件,因此有些狀況suffix要定義的不能由於when而重複。 backupCount:保留日誌個數。默認的0是不會自動刪除掉日誌。若設3,則在文件的建立過程當中庫會判斷是否有超過這個3,若超過,則會從最早建立的開始刪除。
按秒切分示例:
import time import logging import logging.handlers import os # 若是日誌文件夾不存在,則建立
log_dir = "log-second" # 日誌存放文件夾名稱
log_path = os.getcwd() + os.sep + log_dir if not os.path.isdir(log_path): os.makedirs(log_path) # logging初始化工做
logging.basicConfig() # 初始化loggger
test = logging.getLogger('test') test.setLevel(logging.INFO) # 添加TimedRotatingFileHandler # 定義一個1秒換一次log文件的handler # 保留3箇舊log文件
timefilehandler = logging.handlers.TimedRotatingFileHandler( log_dir + os.sep + "log", when='S', interval=1, backupCount=3 ) # 設置後綴名稱,跟strftime的格式同樣
timefilehandler.suffix = "%Y-%m-%d_%H-%M-%S.log" formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s') timefilehandler.setFormatter(formatter) test.addHandler(timefilehandler) n = 6
while n > 0: test.info("這是一個時間分割的測試程序") time.sleep(1) n -= 1
運行結果:
注意:
timefilehandler.suffix的設置必定要和時間單位相符,不如按秒切分,就必須設置timefilehandler.suffix= "%Y-%m-%d_%H-%M-%S.log",不然就不能刪除舊文件了。按天、按分鐘切分也是如此。
RotatingFileHandler基於文件大小切分
示例:
import time # import logging
import os import logging.handlers # 若是日誌文件夾不存在,則建立
log_dir = "log-size" # 日誌存放文件夾名稱
log_path = os.getcwd() + os.sep + log_dir if not os.path.isdir(log_path): os.makedirs(log_path) # logging初始化工做
logging.basicConfig() # 初始化loggger
test_02 = logging.getLogger('test_02') test_02.setLevel(logging.INFO) # 寫入文件,若是單個文件超過100個Bytes,則寫入下一個文件,最多保留5個文件
handler = logging.handlers.RotatingFileHandler( 'log-size/test_02.log', maxBytes=100, backupCount=5) formatter = logging.Formatter('%(asctime)s|%(name)-12s: %(levelname)-8s %(message)s') handler.setFormatter(formatter) # 設置後綴名稱,跟strftime的格式同樣
test_02.addHandler(handler) n = 6
while n > 0: test_02.info("這是一個大小分割的測試程序") time.sleep(1) n -= 1
運行結果:
-----------------------------------------------------------------------------
推薦: