HTMLTestRunner_loguru下html沒有顯示日誌內容問題
阿新 • • 發佈:2021-09-05
-
前置條件
Windows 10
loguru
HTMLTestRunner
-
最近將原有logging日誌系統替換成了loguru,loguru的好處不用多說,簡單好用。配置起來也比lgging方便多了。封裝程式碼如下:
import time, os from loguru import logger from settings import LOG_DIR # 日誌儲存路徑 class Log: """輸出日誌到檔案和控制檯""" def __init__(self): # 檔案的命名 log_name = f"test_{time.strftime('%Y-%m-%d', time.localtime()).replace('-','_')}.log" log_path = os.path.join(LOG_DIR, log_name) # 判斷日誌資料夾是否存在,不存則建立 if not os.path.exists(LOG_DIR): os.mkdir(LOG_DIR) # 日誌輸出格式 formatter = "{time:YYYY-MM-DD HH:mm:ss} | {level}: {message}" # 日誌寫入檔案 logger.add(log_path, # 寫入目錄指定檔案 format=formatter, encoding='utf-8', retention='10 days', # 設定歷史保留時長 backtrace=True, # 回溯 diagnose=True, # 診斷 enqueue=True, # 非同步寫入 # rotation="5kb", # 切割,設定檔案大小,rotation="12:00",rotation="1 week" # filter="my_module" # 過濾模組 # compression="zip" # 檔案壓縮 ) def debug(self, msg): logger.debug(msg) def info(self, msg): logger.info(msg) def warning(self, msg): logger.warning(msg) def error(self, msg): logger.error(msg) log = Log()
-
將上述封裝程式碼引入,生成的html仍沒有日誌。點選
通過
無法點選檢視日誌。原來使用
HTMLTestRunner
生成html
測試報告時,報告中只有console
輸出,logging
的輸出無法儲存,如果要在報告中加入每一個測試用例執行的日誌資訊,則需要改HTMLTestRunner
原始碼。 -
修改
_TestResult
類,同時別忘了在檔案最上面import logging
。import logging
class _TestResult(TestResult): # note: _TestResult is a pure representation of results. # It lacks the output and reporting ability compares to unittest._TextTestResult. def __init__(self, verbosity=1, retry=0,save_last_try=False): TestResult.__init__(self) self.stdout0 = None self.stderr0 = None self.success_count = 0 self.failure_count = 0 self.error_count = 0 self.skip_count = 0 self.verbosity = verbosity # result is a list of result in 4 tuple # ( # result code (0: success; 1: fail; 2: error;3:skip), # TestCase object, # Test output (byte string), # stack trace, # ) self.result = [] self.retry = retry self.trys = 0 self.status = 0 self.save_last_try = save_last_try self.outputBuffer = StringIO.StringIO() self.logger = logging.getLogger() # 新增這一行
-
startTest
函式中初始化logging.Handler
def startTest(self, test): # test.imgs = [] test.imgs = getattr(test, "imgs", []) # TestResult.startTest(self, test) self.outputBuffer.seek(0) self.outputBuffer.truncate() stdout_redirector.fp = self.outputBuffer stderr_redirector.fp = self.outputBuffer self.stdout0 = sys.stdout self.stderr0 = sys.stderr sys.stdout = stdout_redirector sys.stderr = stderr_redirector # 新增如下程式碼 self.log_cap = StringIO.StringIO() self.ch = logging.StreamHandler(self.log_cap) self.ch.setLevel(logging.DEBUG) formatter = logging.Formatter('[%(levelname)s][%(asctime)s] [%(filename)s]->[%(funcName)s] line:%(lineno)d ---> %(message)s') self.ch.setFormatter(formatter) self.logger.addHandler(self.ch)
-
complete_output
函式的返回值中加入logging
存在記憶體中的輸出,用換行符隔開def complete_output(self): """ Disconnect output redirection and return buffer. Safe to call multiple times. """ if self.stdout0: sys.stdout = self.stdout0 sys.stderr = self.stderr0 self.stdout0 = None self.stderr0 = None # return self.outputBuffer.getvalue() return self.outputBuffer.getvalue()+'\n'+self.log_cap.getvalue() # 新增這一行
-
每個用例執行完後,清除handler,修改stopTest函式
def stopTest(self, test): # Usually one of addSuccess, addError or addFailure would have been called. # But there are some path in unittest that would bypass this. # We must disconnect stdout in stopTest(), which is guaranteed to be called. if self.retry and self.retry>=1: if self.status == 1: self.trys += 1 if self.trys <= self.retry: if self.save_last_try: t = self.result.pop(-1) if t[0]==1: self.failure_count -=1 else: self.error_count -= 1 test=copy.copy(test) sys.stderr.write("Retesting... ") sys.stderr.write(str(test)) sys.stderr.write('..%d \n' % self.trys) doc = getattr(test,'_testMethodDoc',u"") or u'' if doc.find('_retry')!=-1: doc = doc[:doc.find('_retry')] desc ="%s_retry:%d" %(doc, self.trys) if not PY3K: if isinstance(desc, str): desc = desc.decode("utf-8") test._testMethodDoc = desc test(self) else: self.status = 0 self.trys = 0 #self.complete_output() a = self.complete_output() # 清除log的handle,新增如下程式碼 self.logger.removeHandler(self.ch) return a
-
可能各自用的
HTMLTestRunner
版本內容不一樣,均只需按照上述修改即可。 -
按照上述修改,再次執行,生成的html報告還是沒有日誌內容,會不會是loguru和logging不相容?
-
上網苦苦找尋,終於找到了解決辦法,封裝的loguru程式碼如下:
import time, os, logging from loguru import logger from settings import LOG_DIR # 日誌儲存路徑 # 新增如下三行程式碼 class PropogateHandler(logging.Handler): def emit(self, record): logging.getLogger(record.name).handle(record) class Log: """輸出日誌到檔案和控制檯""" def __init__(self): # 檔案的命名 log_name = f"test_{time.strftime('%Y-%m-%d', time.localtime()).replace('-','_')}.log" log_path = os.path.join(LOG_DIR, log_name) # 判斷日誌資料夾是否存在,不存則建立 if not os.path.exists(LOG_DIR): os.mkdir(LOG_DIR) # 日誌輸出格式 formatter = "{time:YYYY-MM-DD HH:mm:ss} | {level}: {message}" # 日誌寫入檔案 logger.add(log_path, # 寫入目錄指定檔案 format=formatter, encoding='utf-8', retention='10 days', # 設定歷史保留時長 backtrace=True, # 回溯 diagnose=True, # 診斷 enqueue=True, # 非同步寫入 # rotation="5kb", # 切割,設定檔案大小,rotation="12:00",rotation="1 week" # filter="my_module" # 過濾模組 # compression="zip" # 檔案壓縮 ) # 新增程式碼 logger.add(PropogateHandler(), format=formatter) def debug(self, msg): logger.debug(msg) def info(self, msg): logger.info(msg) def warning(self, msg): logger.warning(msg) def error(self, msg): logger.error(msg) log = Log()