Bootstrap

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("---测试结束---")
;