官方文檔:
https://docs.python.org/2/library/logging.html
logging子產品提供了兩種記錄日志的方式:
- 第一種方式是使用logging提供的子產品級别的函數
- 第二種方式是使用Logging日志系統的四大元件
其實,logging所提供的子產品級别的日志記錄函數也是對logging日志系統相關類的封裝而已。
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進行一次性配置 |
其中
logging.basicConfig(**kwargs)
函數用于指定“要記錄的日志級别”、“日志格式”、“日志輸出位置”、“日志檔案的打開模式”等資訊,其他幾個都是用于記錄各個級别日志的函數。
具體如下:
參數名稱 | 描述 |
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異常。 |
上面的時間需要使用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)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 | 線程名稱 |
一、使用logging提供的子產品級别的函數記錄日志
- 可以通過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級别更高的日志。
二、使用logging四大元件記錄日志
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
-----------------------------------------------------------------------------
推薦:
詳細全面:https://www.cnblogs.com/yyds/p/6901864.html
https://www.cnblogs.com/hanmk/p/10448963.html