• Locust 测试结果通过Matplotlib生成趋势图


    目的:

    相信大家对于使用Loadrunner测试后的结果分析详细程度还是有比较深刻的感受的,每个请求,每个事务点等都会有各自的趋势指标,在同一张图标中展示。如下图:

     

    而Locust自身提供的chart趋势图缺很简单,如下图:

    那么要达到Loadrunner对于每个请求的详细的描述,用locust能否实现呢?

    答案是肯定的,那么我们想到就开始做!

    思路:

    我们整理一下思路,按照步骤去达到我们的目的:

    1. 首先我们需要知道每个请求的响应时间

    2. 我们需要把每个请求的响应时间进行数据整理和拆分

    3. 我们需要把整理好的数据生成图表

    实施:

    按照初步的思路,我们来按步骤进行实施:

    1. 抓取每个请求的响应时间。

    我们需要获取每个请求的响应时间,可以通过Locust本身自带的钩子函数打印成日志文件。

    具体代码如下:

    #!/usr/bin/python3.6
    # -*- coding: UTF-8 -*-
    # author:Lucien
    # 基础包: 压力Log日志封装
    from locust import events
    import os
    import time
    import logging
    from logging.handlers import RotatingFileHandler
    
    
    class loadLogger():
        def __init__(self, filePath, fileName):
            self.filePath = filePath  # 存放文件的路径
            self.fileName = fileName  # 存放文件的名字
            self.BACK_UP_COUNT = 5000  # 文件分割上限数
            self.MAX_LOG_BYTES = 1024 * 1024 * 1  # 单个文件最大记录数1M
            self.create_handler()  # 初始化创建日志handler
            self.create_logger()  # 初始化创建Logger
    
        def create_handler(self):  # 建立handler
            self.success_handler = RotatingFileHandler(filename=os.path.join(self.filePath, self.fileName),
                                                       maxBytes=self.MAX_LOG_BYTES * 100, backupCount=self.BACK_UP_COUNT,
                                                       delay=1)  # 分割文件处理按100m分割
            formatter = logging.Formatter('%(asctime)s | %(name)s | %(levelname)s | %(message)s')  # 设定输出格式
            formatter.converter = time.gmtime  # 时间转换
            self.success_handler.setFormatter(formatter)  # 格式加载到handler
    
        def create_logger(self):  # 建立Logger
            self.success_logger = logging.getLogger('request_success')
            self.success_logger.propagate = False
            self.success_logger.addHandler(self.success_handler)
    
        def success_request(self, request_type, name, response_time, response_length):  # 成功日志输出格式加载到Logger中
            msg = ' | '.join([str(request_type), name, str(response_time), str(response_length)])
            self.success_logger.info(msg)
    
        def get_locust_Hook(self):  # 钩子挂载到Locust中
            events.request_success += self.success_request

    以上为封装好的Log日志输出

    在并发时带入log日志输出为本地文件存放,代码如下:

    # !/usr/bin/python3.6
    # -*- coding: UTF-8 -*-
    # author: lucien
    # 基础包: locust趋势图生成包
    from locust import TaskSet, task, HttpLocust
    from Performance_Core.performance_log import loadLogger
    import os
    
    
    class file_server_stress(TaskSet):
        def on_start(self):
            '''警号,部门编号等'''
            self.deptID = '520'
            self.pcMemberID = '10000001'
            self.phoneMemberID = '10000004'
            self.logger = loadLogger(filePath='E:\PrintLog', fileName='11-12-logs')
    
        # 上传文件
        @task(1)
        def update_file(self):
            payload = "xxx"
            url = ':6061/file/upload/file'
            headers = {
                'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
                'Cache-Control': "no-cache",
                'Postman-Token': "9889c0b4-b91c-4b23-a713-cae4d60e623a"
            }
            response = self.client.post(url=url, data=payload, headers=headers, name='update_file', catch_response=True,
                                        timeout=20)
            print(response.text)
            # 验证请求成功与失败
            if response.status_code == 200:
                self.logger.get_locust_Hook() #重点!此处挂载Log日志钩子
                response.success()
            else:
                self.logger.get_locust_Hook()
                response.failure('上传文件失败')
    
    class userbehavior(HttpLocust):
        host = 'http://192.168.1.222'
        task_set = file_server_stress
        min_wait = 3000
        max_wait = 5000
    
    if __name__ == '__main__':
        '''网页启动,在网页中输入127.0.0.1:8089'''
        os.system('locust -f file_server_stress.py --web-host=127.0.0.1')  

    运行完测试后,我们将会得到一组log日志文件,样式如下:

    第一步顺利完成!

    2. 对日志文件进行数据分析和拆分

    我们所得到的所有日志记录都会混合在日志文件中,我们需要把它提取出来,并且通过groupby来拆分不同的请求

    提取日志文件,我们可以用到python的强项,数据分析支持库Pandas和Numpy

    首先,我们通过Pandas提取日志文件:

    headers = ['time', 'label', 'loglevel', 'method', 'name', 'response_time', 'size']  
    self.data = pandas.read_csv(filename, sep='|', names=headers)

    读取日志文件后生成DATAFRAME的pandas数据独有格式

    其次,我们通过对读取的文件处理后进行排序

    self.sorted_data = self.data.sort_values(by=['time', 'name'], ascending=[True, True])

    按时间和请求名称,将序排列

    最后,我们对排序后的数据进行分组

    self.grouped_data = self.sorted_data.groupby('name')

    自此,我们数据处理工作大体准备完成

    3.把数据生成图表

    需要把数据生成图表,自然离不开matplotlib了

    按照matplolib里,plot方法,把x轴和y轴 按照time 和 response_time 生成相应的折线图,最后生成的趋势图如下:

    大功告成!

    最后附上实际代码,供有需要的同学参考,也可以自行改良:

    # !/usr/bin/python3.6
    # -*- coding: UTF-8 -*-
    # author: lucien
    # 基础包: locust趋势图生成包
    import pandas as pd
    from datetime import datetime
    import matplotlib.pyplot as plt
    import numpy as np
    from matplotlib import dates
    
    hex_colors = [
        '#FF7500',
        '#F00056',
        '#0EB83A',
        '#00BC12',
        '#1BD1A5',
        '#0C8918',
        '#0AA344',
        '#2ADD9C',
        '#3DE1AD',
        '#424C50',
        '#DB5A6B',
        '#FF4E20',
        '#3EEDE7',
        '#4B5CC4',
        '#70F3FF',
        '#2E4E7E',
        '#3B2E7E',
        '#425066',
        '#8D4BBB',
        '#815476',
        '#808080',
        '#161823',
        '#50616D',
        '#725E82',
        '#A78E44',
        '#8C4356',
        '#F47983',
        '#B36D61',
        '#C93756',
        '#FF2121',
        '#C83C23',
        '#9D2933',
        '#FFF143',
        '#FF0097',
        '#A98175',
        '#C32136',
        '#6E511E',
        '#F20C00',
        '#F9906F',
        '#FF8936',
        '#DC3023',
        '#EAFF56',
        '#FFA400',
        '#60281E',
        '#44CEF6',
        '#F0C239',
        '#A88462',
        '#B35C44',
        '#B25D25',
        '#C89B40',
        '#D9B611',
        '#827100',
        '#C3272B',
        '#7C4B00',
        '#BDDD22',
        '#789262',
        '#FF8C31',
        '#C91F37',
        '#00E500',
        '#177CB0',
        '#065279',
    ]
    
    
    class data_analyse():
        def __init__(self, filename):
            self.filename = filename
            self.xfmt = dates.DateFormatter('%m/%d %H:%M')
            self._init_graph()  # 初始化趋势图大小
            self._set_graph()  # 初始化趋势图样式
    
            headers = ['time', 'label', 'loglevel', 'method', 'name', 'response_time', 'size']  # 命名字段标题
            self.data = pd.read_csv(filename, sep='|', names=headers)  # 从文件获取内容为DATAFRAME格式
            for col in headers[-2:]:  # 转换response_time和size为int型
                self.data[col] = self.data[col].apply(lambda x: int(x))
            for col in headers[0:-2]:  # 取消掉所有非int型的空格
                self.data[col] = self.data[col].apply(lambda x: x.strip())
            self.data['time'] = self.data['time'].apply(
                lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S,%f'))  # time转化为时间格式
            self.sorted_data = self.data.sort_values(by=['time', 'name'], ascending=[True, True])  # 对数据按照time和name进行降序排列
            self.grouped_data = self.sorted_data.groupby('name')  # 对降序排列的数据,按名称分组
            self.requests_counts = np.array([[key, len(group)] for key, group in self.grouped_data])  # 构建请求名和请求次数数组
    
        def _init_graph(self):  # 设定趋势图大小
            left, width = 0.1, 0.8
            bottom, height = 0.1, 0.8
            self.trend_scatter = [left, bottom, width, height]
    
        def _set_graph(self):  # 生成基本趋势图样式
            plt.clf()  # 清除figure中所有axes
            self.ax_plot = plt.axes(self.trend_scatter)  # 套用axes大小
            self.ax_plot.grid(True)  # 打开网格
            self.ax_plot.set_ylabel('Response Time(ms)')  # 纵坐标标题
            self.ax_plot.set_xlabel('time')  # 横坐标标题
            self.ax_plot.figure.set_size_inches(15, 8)  # 画板大小
            self.ax_plot.xaxis.set_major_locator(dates.MinuteLocator(interval=5))  # 设定横坐标日期格式为5min间隔
            self.ax_plot.xaxis.set_major_formatter(self.xfmt)  # 设定横坐标格式
    
        def generate_trend(self):  # 生成趋势图
            start_index = 0
            legend_list = []
            for index, request in enumerate(self.requests_counts):  # 为数组添加index标签
                name, count = request[0], int(request[1])  # 获取请求名和请求次数
                end_index = start_index + count
                x = self.grouped_data.get_group(name)['time'][start_index: end_index]  # 设置x轴数据
                y = self.grouped_data.get_group(name)['response_time'][start_index:end_index]  # 设置y轴数据
                self.ax_plot.plot(x, y, '-', color=hex_colors[index + 1])  # 画图
                legend_list.append(name)  # 添加请求名到legend中
            plt.legend(legend_list)  # 打印legend
            # plt.show()  # 打印趋势图
            plt.title(self.filename)
            plt.savefig(fname='.'.join([self.filename, 'png']), dpi=300, bbox_inches='tight')  # 保存趋势图
    
    
    if __name__ == '__main__':
        data = data_analyse('E:\PrintLog\logs')
        print(data.sorted_data.info())
        # data.generate_trend()

     如要转载,请标明出处

  • 相关阅读:
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_9_常用的函数式接口_Consumer接口
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_6_函数式接口作为方法的返回值类
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_5_函数式接口作为方法的参数案例
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_4_使用Lambda优化日志案例
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_3_性能浪费的日志案例
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_2_函数式接口的使用
    阶段1 语言基础+高级_1-3-Java语言高级_08-JDK8新特性_第1节 常用函数接口_1_函数式接口的概念&函数式接口的定义
    I2C通讯协议
    C语言函数不定参数实现方式
    ARM中断处理过程
  • 原文地址:https://www.cnblogs.com/grandlulu/p/10001945.html
Copyright © 2020-2023  润新知