windows將 任意裝置(win mac ipad Android)作為 擴充套件螢幕~SpaceDesk
logging
日誌處理流程:
-
建立
logger
記錄器物件,預設root#推薦使用 getLogger方式獲取一個具有指定名稱的記錄器例項,如果此名稱記錄器例項已存在,則返回現有的logger物件 logger = logging.getLogger(logname) 記錄器是可以用名稱(句點分割的層級值)如'a.b'設值有效層級概念,子記錄器可以將訊息逐級向上傳播直到跟記錄器,其中遇到的每個直接上級如果有處理程式,都會記錄一次,包括跟記錄器。所以僅將處理程式附加到根記錄器,通過傳播來處理子記錄器的所有記錄器事件。不推薦給層級記錄器中的子記錄器個體新增處理程式,因為這會傳播導致兩個記錄器都記錄日誌,可以通過將單個記錄器的 propagate 屬性設定 False 來關閉傳播。 #常用的記錄器配置 Logger.setLevel() 指定記錄器將處理的最低日誌級別 從記錄器物件中新增和刪除處理程式物件 Logger.addHandler() 記錄器 新增 處理程式物件 Logger.removeHandler() 記錄器 刪除 處理程式物件 新增或移除記錄器物件中的過濾器Filter物件 Logger.addFilter() Logger.removeFilter() # 記錄日誌方法 Logger.debug() Logger.info() Logger.warning() Logger.error() Logger.critical() 以上都是普通的記錄方法,異常資訊也會正常記錄異常字串,可以傳遞引數 exec_info=True,也可以實現日誌中記錄異常堆疊資訊 Logger.exception() 專用於異常處理中記錄日誌,包含錯誤追蹤資訊
-
建立處理程式檔案
Handler
物件Handler 物件負責將適當的日誌訊息(基於日誌訊息的嚴重性)分派給處理程式的指定目標。Logger 物件可以使用 addHandler() 方法向自己新增零個或多個處理程式物件
常見處理程式如檔案操作符
FileHandler
或 螢幕操作符streamHandler
。logging標準庫提供的可用處理程式# 處理程式常見配置 setFormatter() 配置處理程式使用的 Formatter 格式化物件 處理程式上配置和取消 過濾器物件 addFilter() removeFilter() # 常用handler #1.終端日誌: (預設)輸出到 sys.stderr StreamHandler = logging.StreamHandler() #2.無限制的檔案日誌處理: filehandler = logging.FileHandler(filename, mode='a', encoding=None, delay=False, errors=None) #3.檔案大小及備份數量限制的日誌處理程式: from logging import handlers rotafilehd = handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False, errors=None) maxBytes 日誌檔案最大位元組 backupCount 日誌檔案最多儲存數量,名字時log log.1 log.2,其中最新的寫入log,log滿後寫入改名log1,其他的依次改,最大字尾為最早資料 注意:如果 maxBytes 或 backupCount 任一為零,就不會發生檔案切換 #4.時間間隔檔案切換日誌 timefhd = handlers.TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None, errors=None) when 指定間隔單位,'秒S 分M 時H 天D 星期W0-6' 預設使用本地時間,設值utc=True 使用UTC時間 時間切換日誌會根據間隔粒度單位給檔案新增事件字尾,注意即使間隔小,也只會在有日誌時建立檔案,而不會有很多空檔案
-
設定日誌記錄格式
Formatter
格式化程式物件格式化程式物件配置日誌訊息的最終順序、結構和內容
handler.setFormatter(logging.Formatter('[ %(levelname)-8s] %(asctime)s - < %(filename)-20s> - <%(lineno)3d> - %(name)s : \n\t%(message)s'))
-
記錄器logger物件使用
addHandler() 方法
繫結 處理程式(記錄格式) -
呼叫logger物件記錄方法
logging.error('記錄內容')
import logging # 1.create logger logger = logging.getLogger('simple_example') logger.setLevel(logging.DEBUG) # 2.createhandler and set level to debug hd = logging.StreamHandler() hd.setLevel(logging.DEBUG) hd.setLevel(getattr(logging,'D')) # 3.create formatter and add formatter to handler hd.setFormatter(logging.Formatter('[ %(levelname)-8s ] %(asctime)s - %(filename)s - %(lineno)3d - %(name)s : \n\t%(message)s')) # 4.add handler to logger logger.addHandler(hd) # 5.logging logger.debug('debug message') logger.info('info message') logger.warning('warn message') logger.error('error message') logger.critical('critical message')
多模組使用日誌:在同一個 Python 直譯器程序中,無論在同一個模組還是多個模組中,只會有一個logger 記錄器物件,多次呼叫 logging.getLogger('name')
都會返回對同一個 logger 物件的引用,即使在多個模組中建立不同等級logger,在不配置其他處理程式時,對子 logger 的所有呼叫都將傳給父 logger處理程式執行。
注意:如果同一個python直譯器程序中,有層級命名的多級記錄器物件,且多個處理程式,記錄器預設logger.propagate=True
,當某個記錄器的遇到記錄事件時,會發送給此記錄器及其到跟記錄器的所有直接上級記錄器中的所有處理程式handler,此時所有處理器都會同時記錄。
建議:如果使用層級命名的多級日誌記錄器物件且多個處理程式,建議使用單獨處理程式的單個記錄器物件配置logger.propagate=False
,則只會在當前記錄器及其指定handler記錄,而不再傳遞到上級記錄器處理程式。
logging模組提供一個基本配置的日誌記錄器物件:logging.basicConfig()
logging.basicConfig(__) 使用預設的 Formatter 建立一個 StreamHandler 並將其加入根日誌記錄器,都是日誌記錄系統執行基本配置
#可通過關鍵字引數來更改返回一個定製的記錄器
filename 用指定的檔名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被儲存在指定的檔案中。
filemode 檔案開啟方式,在指定了filename時使用這個引數,預設值為a追加模式,還可指定為w覆蓋模式
encoding 建立 FileHandler 時指定檔案讀寫方式
format 指定handler使用的日誌顯示格式。
datefmt 指定日期時間格式。
level 記錄日誌的最低日誌級別,預設warning,(debug/info不輸出)
stream 用指定的stream建立StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者檔案,預設為sys.stderr。若同時列出了filename和stream兩個引數,則stream引數會被忽略。
#日誌格式 format引數中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 數字形式的日誌級別
%(levelname)s 文字形式的日誌級別
%(pathname)s 呼叫日誌輸出函式的模組的完整路徑名,可能沒有
%(filename)s 呼叫日誌輸出函式的模組的檔名
%(module)s 呼叫日誌輸出函式的模組名
%(funcName)s 呼叫日誌輸出函式的函式名
%(lineno)d 呼叫日誌輸出函式的語句所在的程式碼行
%(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌資訊時的,自Logger建立以 來的毫秒數
%(asctime)s 字串形式的當前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(thread)d 執行緒ID。可能沒有
%(threadName)s 執行緒名。可能沒有
%(process)d 程序ID。可能沒有
%(message)s 使用者輸出的訊息
格式化輸出時,可以固定資訊長度, 如 %(name)20s name都佔20字元, 預設內容靠右, 可以使用-表示靠左 %(name)-20s
#日誌級別LEVEL:
CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
propagete引數 :
propagete=True 預設,會在輸出日誌,當前記錄器處理器記錄日誌,並傳遞給每層直接上級記錄器處理程式,這會導致重複記錄
propagate=False 僅在當前記錄器處理器記錄日誌,不傳遞
handlers
import logging,time
from logging import handlers
# 預設的終端日誌
sthd = logging.StreamHandler()
# 無限制的檔案日誌處理:
filehandler = logging.FileHandler('filename', mode='a', encoding='utf-8',)
# 按檔案大小切割,指定儲存數量
rotafhd = handlers.RotatingFileHandler('rotfhd', mode='a', maxBytes=10, backupCount=3, encoding='utf-8',)
# 按時間切割,指定儲存數量
timefhd = handlers.TimedRotatingFileHandler('tfhd',when='S',interval=1,backupCount=3)
logging.basicConfig(
# 時間 -觸發檔案 -函式:行 \n -記錄者 - 日誌等級:日誌內容
format="%(asctime)s -%(pathname)s -%(funcName)s:%(lineno)d \n %(name)s - %(levelname)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S %p",
handlers=[sthd,filehandler,rotafhd,timefhd],
level=logging.INFO,
)
logger0 = logging.getLogger('t0')
for i in range(10):
time.sleep(1)
logger0.info(time.localtime())
整合式日誌
# log.py 需要把檔案在專案啟動時匯入初始化一次
import logging
from logging import handlers
# 定義專案日誌根, 其他記錄器以在它後面加點, 使用當前配置
rootlogger = logging.getLogger("dd")
# 每7天一個日誌(必須先在執行環境的根目錄建立log目錄)
timefilehd = handlers.TimedRotatingFileHandler(
"log/ddserver.log", when="D", interval=7, backupCount=12
)
timefilehd.setFormatter(
logging.Formatter(
"[ %(levelname)-8s] %(asctime)s -> %(name)-20s -> %(filename)-20s -> %(lineno)3d ->>> %(message)s"
)
)
rootlogger.addHandler(timefilehd)
rootlogger.setLevel(logging.INFO)
rootlogger.info("Start Dingding appServer")
# 在同一程序的其他檔案中使用日誌
import logging
# 這裡的檔名是 日誌根.xxx, 會預設使用根記錄器
logger = logging.getLogger("dd.callback_event")