python结合logging模块编写打印日志的装饰器+python结合time模块编写计算时间装饰器【杭州多测师】【杭州多测师_王sir】
import datetime import logging import requests #获取日志记录器、配置日志等级 logger = logging.getLogger(__name__) logger.setLevel("DEBUG") #默认日志格式 formatter = logging.Formatter("%(asctime)s - [%(levelname)s] - %(message)s") #输出到控制台的handler chlr = logging.StreamHandler() #配置默认日志格式 chlr.setFormatter(formatter) #日志记录器增加此handler logger.addHandler(chlr) def log(func): """ 日志装饰器、简单记录函数的日志 :param func: 函数 :return: """ def inner(*args,**kwargs): timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") res = func(*args,**kwargs) logger.debug(f"func: {func.__name__}{args}->{res}") return res return inner @log def cms_login(userAccount=None,loginPwd=None): url = "http://cms.duoceshi.cn/cms/manage/loginJump.do?userAccount="+userAccount+"&"+"loginPwd"+"="+str(loginPwd) response = requests.get(url) return (response.json()) cms_login("admin",123456)
import logging from logging import handlers from typing import Text import colorlog from common.setting import ConfigHandler class LogHandler: """ 日志打印封装""" # 日志级别关系映射 level_relations = { 'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, 'critical': logging.CRITICAL } def __init__( self, filename: Text, level: Text = "info", when: Text = "D", fmt: Text = "%(levelname)-8s%(asctime)s%(name)s:%(filename)s:%(lineno)d %(message)s" ): self.logger = logging.getLogger(filename) formatter = self.log_color() # 设置日志格式 format_str = logging.Formatter(fmt) # 设置日志级别 self.logger.setLevel(self.level_relations.get(level)) # 往屏幕上输出 screen_output = logging.StreamHandler() # 设置屏幕上显示的格式 screen_output.setFormatter(formatter) # 往文件里写入#指定间隔时间自动生成文件的处理器 time_rotating = handlers.TimedRotatingFileHandler( filename=filename, when=when, backupCount=3, encoding='utf-8' ) # 设置文件里写入的格式 time_rotating.setFormatter(format_str) # 把对象加到logger里 self.logger.addHandler(screen_output) self.logger.addHandler(time_rotating) self.log_path = ConfigHandler.log_path @classmethod def log_color(cls): """ 设置日志颜色 """ log_colors_config = { 'DEBUG': 'cyan', 'INFO': 'green', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'red', } formatter = colorlog.ColoredFormatter( '%(log_color)s[%(asctime)s] [%(name)s] [%(levelname)s]: %(message)s', log_colors=log_colors_config ) return formatter INFO = LogHandler(ConfigHandler.info_log_path, level='info') ERROR = LogHandler(ConfigHandler.error_log_path, level='error') WARNING = LogHandler(ConfigHandler.warning_log_path, level='warning') if __name__ == '__main__': ERROR.logger.error("测试")
""" 日志装饰器,控制程序日志输入,默认为 True 如设置 False,则程序不会打印日志 """ from functools import wraps from utils.logging_tool.log_control import INFO, ERROR def log_decorator(switch: bool): """ 封装日志装饰器, 打印请求信息 :param switch: 定义日志开关 :return: """ def decorator(func): @wraps(func) def swapper(*args, **kwargs): # 判断日志为开启状态,才打印日志 res = func(*args, **kwargs) # 判断日志开关为开启状态 if switch: _log_msg = f"\n======================================================\n" \ f"用例标题: {res['detail']}\n" \ f"请求路径: {res['url']}\n" \ f"请求方式: {res['method']}\n" \ f"请求头: {res['headers']}\n" \ f"请求内容: {res['request_body']}\n" \ f"接口响应内容: {res['response_data']}\n" \ f"接口响应时长: {res['res_time']} ms\n" \ f"Http状态码: {res['status_code']}\n" \ "=====================================================" _is_run = res['is_run'] # 判断正常打印的日志,控制台输出绿色 if _is_run in (True, None) and res['status_code'] == 200: INFO.logger.info(_log_msg) else: # 失败的用例,控制台打印红色 ERROR.logger.error(_log_msg) return res return swapper return decorator
""" 统计请求运行时长装饰器,如请求响应时间超时 程序中会输入红色日志,提示时间 http 请求超时,默认时长为 3000ms """ from utils.logging_tool.log_control import ERROR def execution_duration(number: int): """ 封装统计函数执行时间装饰器 :param number: 函数预计运行时长 :return: """ def decorator(func): def swapper(*args, **kwargs): res = func(*args, **kwargs) run_time = res['res_time'] # 计算时间戳毫米级别,如果时间大于number,则打印 函数名称 和运行时间 if run_time > number: ERROR.logger.error( "\n==============================================\n" "测试用例执行时间较长,请关注.\n" "函数运行时间: %s ms\n" "测试用例相关数据: %s\n" "=================================================" , run_time, res) return res return swapper return decorator
import logging import os from testlib.common.MyConfigParser import conf from testlib.common.pathOperation import LOG_DIR # 获取配置信息 level = conf.get_str("logging", "level") f_level = conf.get_str("logging", "f_level") s_level = conf.get_str("logging", "s_level") filename = conf.get_str("logging", "filename") # 获取日志文件路径 file_path = os.path.join(LOG_DIR, filename) class Log: @staticmethod def log_collection(): """日志收集器""" # 创建日志收集器 log = logging.getLogger() # 设置日志收集器等级 log.setLevel(level) """控制台输出""" # 添加输出渠道 sh = logging.StreamHandler() # 设置输出等级 sh.setLevel(s_level) # 将输出渠道绑定在日志收集器上 log.addHandler(sh) """日志输出""" # 添加输出渠道 fh = logging.FileHandler(file_path, encoding="utf8") # 设置输出等级 fh.setLevel(f_level) # 设置日志输出格式 formatter = logging.Formatter('%(asctime)s-%(levelname)s: %(message)s') # 输出渠道和输出格式绑定 fh.setFormatter(formatter) # 输出渠道和日志收集器绑定 log.addHandler(fh) return log log = Log.log_collection() if __name__ == '__main__': log = Log.log_collection() res= log.info("DEBUE") print(res)
# coding:utf-8 import logging,time,os # 这个是日志保存本地的路径 root_path = os.path.dirname(__file__) app_path = os.path.join(root_path, "resultReport/").replace("\\", "/") log_path = app_path class Log: def __init__(self): # 文件的命名 self.logname = os.path.join(log_path, '%s.log'%time.strftime('%Y_%m_%d')) self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) # 日志输出格式 self.formatter = logging.Formatter('[%(asctime)s] - %(filename)s[line:%(lineno)d] - fuc:%(funcName)s- %(levelname)s: %(message)s') def __console(self, level, message): # 创建一个FileHandler,用于写到本地 fh = logging.FileHandler(self.logname, 'a') # 追加模式 fh.setLevel(logging.DEBUG) fh.setFormatter(self.formatter) self.logger.addHandler(fh) # 创建一个StreamHandler,用于输出到控制台 ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) ch.setFormatter(self.formatter) self.logger.addHandler(ch) if level == 'info': self.logger.info(message) elif level == 'debug': self.logger.debug(message) elif level == 'warning': self.logger.warning(message) elif level == 'error': self.logger.error(message) # 这两行代码是为了避免日志输出重复问题 self.logger.removeHandler(ch) self.logger.removeHandler(fh) # 关闭打开的文件 fh.close() def debug(self, message): self.__console('debug', message) def info(self, message): self.__console('info', message) def warning(self, message): self.__console('warning', message) def error(self, message): self.__console('error', message) if __name__ == "__main__": log = Log() log.info("---测试开始----") log.info("输入密码") log.warning("----测试结束----")
import logging, time, os BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) # 定义日志文件路径 LOG_PATH = os.path.join(BASE_PATH, "log") if not os.path.exists(LOG_PATH): os.mkdir(LOG_PATH) class Logger(): def __init__(self): self.logname = os.path.join(LOG_PATH, "{}.log".format(time.strftime("%Y%m%d"))) self.logger = logging.getLogger("log") self.logger.setLevel(logging.DEBUG) self.formater = logging.Formatter( '[%(asctime)s][%(filename)s %(lineno)d][%(levelname)s]: %(message)s') self.filelogger = logging.FileHandler(self.logname, mode='a', encoding="UTF-8") self.console = logging.StreamHandler() self.console.setLevel(logging.DEBUG) self.filelogger.setLevel(logging.DEBUG) self.filelogger.setFormatter(self.formater) self.console.setFormatter(self.formater) self.logger.addHandler(self.filelogger) self.logger.addHandler(self.console) logger = Logger().logger if __name__ == '__main__': logger.info("---测试开始---") logger.debug("---测试结束---")