美文网首页
【原】【亲测】Jmeter 自定义sampler压测elk 写入

【原】【亲测】Jmeter 自定义sampler压测elk 写入

作者: 曹赫洋 | 来源:发表于2017-07-22 14:55 被阅读0次

    前提概要:本文主要讲述如何开发一个Jmeter的自定义sampler,目的是根据自己的业务场景可以自定义压测规则,本文的初衷是为了对elk做压力测试,而作者的elk的logstash数据来源是redis,所以本文所写的sampler主要其实是压测数据写入redis。

    主要参考了以下博文:

    http://www.nttpc.co.jp/technology/jmeter.html

    https://testerhome.com/topics/4522

    http://blog.csdn.net/bobchao0730/article/details/51352768

    JMeter插件实现步骤1 - 准备开发环境

    JMeter插件实现是标准的Java代码,新建一个Maven项目。我们的项目中需要引用到JMeter本身提供的一些库,包括ApacheJMeter_core和ApacheJmeter_java,并且对JMeter的版本依赖是3.1。另外,还需要对redis的类库也需要引入,pom.xml中依赖部分的代码如下。

    <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
            <jmeter-version>3.1</jmeter-version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.jmeter</groupId>
                <artifactId>ApacheJMeter_core</artifactId>
                <version>${jmeter-version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.jmeter</groupId>
                <artifactId>ApacheJMeter_java</artifactId>
                <version>${jmeter-version}</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.7</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>2.7</version>
            </dependency>
    
            <!-- log4j2-链接数据库 -->
            <dependency>
                <groupId>commons-pool</groupId>
                <artifactId>commons-pool</artifactId>
                <version>1.6</version>
            </dependency>
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.9.0</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>${project.artifactId}</finalName>
            <defaultGoal>install</defaultGoal>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.5.1</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>assemble-all</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    

    工程创建完毕之后,开始编写代码来实现插件。
    注意:这里用到了一个maven插件,这个maven插件的作用是打包maven项目的时候,连该项目依赖的所有jar包一起打包进来,因为jmter的插件打包成功之后,这些依赖都需要,如果不打包进来的话,实际上插件是会无法使用的。

    JMeter插件实现步骤2 - 自定义界面

    JMeter的插件机制会在$JMETER_HOME/lib/ext目录下去动态加载符合指定条件的JAR包,并在JMeter中显示出来。比如要扩展UI的话,扩展的Java类的包名必须是”.gui.”,同样的扩展函数的Java类的包名必须是”.function.”.
    新建一个类,com.weds.test.elk.gui.ELKSamplerGui,并指定其父类为AbstractSamplerGui。
    该类需要实现以下的功能:

    1)界面布局与控件。JMeter的界面是标准的Swing,所以里面的控件和布局都是标准的Swing写法。

    2)界面与Sampler之间的数据交换。Sampler在JMeter中继承的是TestElement,用户输入的数据都是保存在Sampler中的,因此可以认为这个是界面的模型。界面与模型(Sampler)之间的数据交换需要实现父类的下面几个方法,

    public void configure(TestElement el)
    

    该方法用于把Sampler中的数据加载到界面中。在实现自己的逻辑之前,先调用一下父类的方法super.configure(el),这样可以确保框架自动为你加载一些缺省数据,比如Sampler的名字。

    public void modifyTestElement(TestElement e)
    

    这个方法用于把界面的数据移到Sampler中,刚好与上面的方法相反。在调用自己的实现方法之前,请先调用一下super.configureTestElement(e),这个会帮助移到一些缺省的数据。

    public TestElement createTestElement()
    

    该方法创建一个新的Sampler,然后将界面中的数据设置到这个新的Sampler实例中。

    public void clearGui()
    

    该方法会在reset新界面的时候调用,这里可以填入界面控件中需要显示的一些缺省的值。

    完整代码如下:

    package com.weds.test.elk.gui;
    
    import com.weds.test.elk.ELKSampler;
    import org.apache.jmeter.config.Arguments;
    import org.apache.jmeter.gui.util.VerticalPanel;
    import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
    import org.apache.jmeter.testelement.TestElement;
    import org.apache.jorphan.gui.JLabeledTextArea;
    import org.apache.jorphan.gui.JLabeledTextField;
    
    import javax.swing.*;
    import java.awt.*;
    
    /**
     * 日志压测工具
     * <p>
     *    压测,收集数据写入到redis
     * </p>
     */
    public class ELKSamplerGui extends AbstractSamplerGui {
    
        //swing 页面主面板
        private JPanel mainPanel;
    
        private JLabeledTextField redisIP = new JLabeledTextField("redis服务器ip地址");
        private JLabeledTextField redisPort = new JLabeledTextField("redis服务器");
        private JLabeledTextField redisList = new JLabeledTextField("投递目标");
        private JLabeledTextArea redisMessage = new JLabeledTextArea("日志消息");
    
        public ELKSamplerGui() {
            setLayout(new BorderLayout(0, 5));
            setBorder(makeBorder());
            add(makeTitlePanel(), BorderLayout.NORTH); // Add the standard title
            mainPanel = new VerticalPanel();
            init();
            add(mainPanel, BorderLayout.CENTER);      //添加面板
        }
    
        /**
         * 初始化屏幕布局
         */
        protected final void init() {
            mainPanel.add(redisIP);
            mainPanel.add(redisPort);
            mainPanel.add(redisList);
            mainPanel.add(redisMessage);
            redisMessage.setPreferredSize(new Dimension(100, 25));
        }
    
        /**
         * 该方法用于把Sampler中的数据加载到界面中。
         * 在实现自己的逻辑之前,先调用一下父类的方法super.configure(el),
         * 这样可以确保框架自动为你加载一些缺省数据,比如Sampler的名字。
         *
         * @param element
         */
        @Override
        public void configure(TestElement element) {
            super.configure(element);
            if (!(element instanceof ELKSampler)) {
                return;
            }
            ELKSampler sampler = (ELKSampler) element;
            redisIP.setText(sampler.getRedisIP());
            redisPort.setText(sampler.getRedisPort());
            redisList.setText(sampler.getRedisList());
            redisMessage.setText(sampler.getRedisMessage());
        }
    
        @Override
        public String getLabelResource() {
            return null;
        }
    
        public String getStaticLabel() {
            return "Elk Sampler";
        }
    
        @Override
        public TestElement createTestElement() {
            ELKSampler sampler = new ELKSampler();
            modifyTestElement(sampler);
            return sampler;
        }
    
        /**
         * 这个方法用于把界面的数据移到Sampler中,刚好与上面的方法相反。
         * 在调用自己的实现方法之前,
         * 请先先调用一下super.configureTestElement(e),这个会帮助移掉一些缺省的数据。
         *
         * @return
         */
        @Override
        public void modifyTestElement(TestElement te) {
            ELKSampler sampler = (ELKSampler) te;
            sampler.clear();
            super.configureTestElement(sampler);
            sampler.setRedisIP(redisIP.getText());
            sampler.setRedisPort(redisPort.getText());
            sampler.setRedisList(redisList.getText());
            sampler.setRedisMessage(redisMessage.getText());
        }
    
        /**
         * 该方法会在reset新界面的时候调用,这里可以填入界面控件中需要显示的一些缺省的值。
         */
        @Override
        public void clearGui() {
            super.clearGui();
        }
    }
    
    

    JMeter插件实现步骤3 - 自定义redis Sampler
    新建一个Sampler,com.weds.test.elk.ELKSampler,并指定其父类为AbstractSampler。该类需要实现以下的功能:

    1)增加一些getter/setter方法,这些方法用于与UI之间的数据交换,这些数据在用户保存/打开脚本的时候将被自动序列化/反序列化。

    2)实现sample方法:

    public SampleResult sample(Entry entry)
    

    该方法是JMeter实现对目标系统发起请求实际工作的地方。主要的工作是记录请求处理时间,对返回结果进行处理和判断,并根据处理结果返回SampleResult,该SampleResult中需要指定返回的内容是否成功,以及消息等。
    完整代码如下:

    package com.weds.test.elk;
    
    import org.apache.jmeter.samplers.AbstractSampler;
    import org.apache.jmeter.samplers.Entry;
    import org.apache.jmeter.samplers.SampleResult;
    import org.apache.jorphan.logging.LoggingManager;
    import org.apache.log.Logger;
    import redis.clients.jedis.Jedis;
    
    
    public class ELKSampler extends AbstractSampler {
    
        //输出到日志文件
        static org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(ELKSampler.class.getName());
    
        //控制台输出类
        private static final Logger log = LoggingManager.getLoggerForClass();
        private transient Jedis jedis;
    
        private final static String redisIP = "AMQPPublisher.RedisIP";
        private final static String redisPort = "AMQPPublisher.RedisPort";
        private final static String redisList = "AMQPPublisher.RedisList";
        private final static String redisMessage = "AMQPPublisher.RedisMessage";
    
    
        public String getRedisIP() {
            return getPropertyAsString(redisIP);
        }
    
        public void setRedisIP(String content) {
            super.setProperty(redisIP, content);
        }
    
        public String getRedisPort() {
            if (getPropertyAsInt(redisPort) < 1) {
                return "6379";
            }
            return getPropertyAsString(redisPort);
        }
    
        public void setRedisPort(String content) {
            super.setProperty(redisPort, content);
        }
    
        public String getRedisList() {
            return getPropertyAsString(redisList);
        }
    
        public void setRedisList(String content) {
            super.setProperty(redisList, content);
        }
    
        public String getRedisMessage() {
            return getPropertyAsString(redisMessage);
        }
    
        public void setRedisMessage(String content) {
            super.setProperty(redisMessage, content);
        }
    
        public ELKSampler() {
        }
    
        @Override
        public SampleResult sample(Entry entry) {
    
            SampleResult result = new SampleResult();
            result.setSampleLabel(getName());
            result.setSuccessful(false);
            result.setResponseCode("500");
            result.setSampleLabel(this.getName());
            result.sampleStart(); // Start timing
            try {
                log.info("-------------------------发送消息到redis中:" + getRedisMessage() + "-------------------------");
                logger.error("-------------------------" + getRedisMessage() + "-------------------------");
                jedis = new Jedis(getRedisIP(), Integer.parseInt(getRedisPort()));
                jedis.rpush(getRedisList(), getRedisMessage()); // Sampler data)
                result.setSamplerData(getRedisMessage());
                result.setResponseData(getRedisMessage(), null);
                result.setDataType(SampleResult.TEXT);
                result.setResponseCodeOK();
                result.setResponseMessage("OK");
                result.setSuccessful(true);
            } catch (Exception ex) {
                log.debug(ex.getMessage(), ex);
                result.setResponseCode("000");
                result.setResponseMessage(ex.toString());
            } finally {
                result.sampleEnd(); // End timimg
            }
    
            return result;
        }
    }
    

    JMeter插件实现步骤4 - 打包、部署
    JMeter插件实现步骤5- 测试,查看测试结果,大功告成。

    1.png 2.png

    Paste_Image.png Paste_Image.png

    相关文章

      网友评论

          本文标题:【原】【亲测】Jmeter 自定义sampler压测elk 写入

          本文链接:https://www.haomeiwen.com/subject/pkdukxtx.html