呈上次使用logging來撰寫日誌,利用類別包裝的方式,可實現多個日誌紀錄器,但發現這樣就失去它原先,可以回傳是誰呼叫他並記錄行數的功能。
若開啟函式名稱、行數及訊息的功能,就會像這樣,幾乎都是記錄到,我定義中類別的函式,兩個檔案都是寫一樣的內容,就達不到,我們想要的結果。
若不是要實現多個logging紀錄器,加上以下程式碼,不要用類別包裝,直接用logging這樣就可以很方便地去使用logging的套件就好。
# 設定日誌格式,包含日期時間、日誌等級、函式名稱、行數及訊息
log_format = "%(asctime)s - %(levelname)s - %(funcName)s - %(lineno)d - %(message)s"
在 Python 中,可以使用 inspect
模組來取得目前被呼叫的函式名稱和行數。
我們利用inspect
模組來實現追蹤呼叫logging的檔案名稱及行數。
import os
import re
import logging
import inspect
from datetime import datetime
class WriteLogTxt:
'''
setup_logger 設置logging格式及創立文件夾
write_log_info 指定檔案名稱及log內容輸入
write_log_warning
'''
def __init__(self,file_path,file_name):
self.file_path = file_path
self.file_name = file_name
def setup_logger(self):
'''
設置logging格式及創立文件夾
'''
now = datetime.now()
year_month = now.strftime("%Y-%m") #取得字符串
log_folder = os.path.join(self.file_path, year_month)
# 檢查文件夾與文件是否存在
if not os.path.exists(log_folder):
os.makedirs(log_folder)
# 設置格式
# 設定日誌格式,包含日期時間、日誌等級、函式名稱、行數及訊息
log_format = "%(asctime)s - %(levelname)s - %(message)s"
file_handler = logging.FileHandler(os.path.join(log_folder, f"{self.file_name}_{now.date()}.log"))
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter(log_format))
# 設置logger
self.logger = logging.getLogger(self.file_name)
self.logger.setLevel(logging.INFO)
self.logger.addHandler(file_handler)
# 指定檔案名稱及log內容輸入
def write_log_info(self,log_content):
'''
log_content : Log
'''
# 寫入log
# 獲取呼叫者的資訊
caller_frame = inspect.currentframe().f_back
frame_info = inspect.getframeinfo(caller_frame)
file_path = frame_info.filename
line_number = frame_info.lineno
pattern = r'[^\\]+$'
file_name = re.search(pattern, file_path).group(0)
self.logger.info(f"file_name: [{file_name}],line_number: [{line_number}] {log_content}")
額外開啟兩個py,來呼叫WriteLogTxt撰寫日誌紀錄
取名為module_1.py與module_2.py
from test import WriteLogTxt
#調用第一個log_obj寫入log
log_obj = WriteLogTxt('D:/CRABpy/write/log','sample_1')
log_obj.setup_logger()
log_obj.write_log_info('test_1')
from test import WriteLogTxt
#調用第二個log_obj寫入log
log_obj_2 = WriteLogTxt('D:/CRABpy/write/log','sample_2')
log_obj_2.setup_logger()
log_obj_2.write_log_info('test_2')
主要是新增了以下程式碼
# 獲取呼叫者的資訊
caller_frame = inspect.currentframe().f_back
frame_info = inspect.getframeinfo(caller_frame)
file_path = frame_info.filename
line_number = frame_info.lineno
pattern = r'[^\\]+$'
file_name = re.search(pattern, file_path).group(0)
caller_frame = inspect.currentframe().f_back
inspect.currentframe()
函式返回當前的堆疊框架物件。f_back
屬性指向上一個堆疊框架,這裡的 caller_frame
即為呼叫當前函式的框架。frame_info = inspect.getframeinfo(caller_frame)
inspect.getframeinfo(frame)
函式接收一個框架物件並返回一個包含檔案名稱、行數、函式名稱等資訊的物件。這裡的 frame_info
包含呼叫函式所在的檔案名稱和行數。python複製程式碼file_path = frame_info.filename
frame_info.filename
返回呼叫函式的檔案路徑。line_number = frame_info.lineno
frame_info.lineno
返回呼叫函式所在的行數。pattern = r'[^\\]+$'這個正規表達式模式
[^\\]+$
匹配最後一個反斜杠(\
)之後的所有字符,直到字符串的結尾。具體來說:[^\\]
匹配任何不是反斜杠的字符。+
匹配前一個字符集合的一次或多次出現。$
匹配字符串的結尾。file_name = re.search(pattern, file_path).group(0)
re.search(pattern, file_path)
尋找符合模式的第一個匹配,返回一個 Match
物件。group(0)
返回整個匹配的字符串,即檔案名稱。這段程式碼的目的是從呼叫函式的框架中提取檔案名稱和行數,並使用正規表達式從完整檔案路徑中擷取出檔案名稱。例如,給定完整路徑 'f:\\python\\opencv\\pathinputdata\\module_1.py'
,它會提取出 module_1.py