From 192aac35a48efbe75975e438381b3e310b4faa3c Mon Sep 17 00:00:00 2001 From: Till Neunast Date: Sun, 14 Oct 2018 22:07:39 +1300 Subject: [PATCH 1/2] Fix #1 --- README.md | 26 +++++---- pom.xml | 16 ++--- .../jmeter/vizualizers/sshmon/JSchLogger.java | 34 +++++++++++ .../vizualizers/sshmon/SSHMonCollector.java | 6 ++ .../vizualizers/sshmon/SSHMonSampler.java | 58 ++++++++++++------- .../vizualizers/sshmon/SSHSessionFactory.java | 17 +++--- 6 files changed, 108 insertions(+), 49 deletions(-) create mode 100644 src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/JSchLogger.java diff --git a/README.md b/README.md index fe9f184..0914052 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,11 @@ Extract the [zip package](https://jmeter-plugins.org/files/packages/tilln-sshmon 1. Copy the [jmeter-sshmon jar file](https://github.com/tilln/jmeter-sshmon/releases/download/1.0/jmeter-sshmon-1.0.jar) into JMeter's lib/ext directory. 2. Copy the following dependencies into JMeter's lib directory: - * [kg.apc / jmeter-plugins-cmn-jmeter](https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-cmn-jmeter/0.5/jmeter-plugins-cmn-jmeter-0.5.jar) - * [commons-io / commons-io](https://search.maven.org/remotecontent?filepath=commons-io/commons-io/2.5/commons-io-2.5.jar) - * [org.apache.commons / commons-pool](https://search.maven.org/remotecontent?filepath=org/apache/commons/commons-pool2/2.4.2/commons-pool2-2.4.2.jar) + * [kg.apc / jmeter-plugins-cmn-jmeter](https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-cmn-jmeter/0.6/jmeter-plugins-cmn-jmeter-0.6.jar) * [com.jcraft.jsch / jsch](https://search.maven.org/remotecontent?filepath=com/jcraft/jsch/0.1.54/jsch-0.1.54.jar) 3. Restart JMeter. -**Important: Make sure to remove any older jar file version than `jmeter-plugins-cmn-jmeter-0.5.jar` from JMeter's lib directory!** +**Important: Make sure to remove any older jar file version than `jmeter-plugins-cmn-jmeter-0.6.jar` from JMeter's lib directory!** Usage ----- @@ -100,13 +98,21 @@ For details refer to the [JMeter-Plugins wiki](https://jmeter-plugins.org/wiki/S ### JMeter Properties The following properties control the plugin behaviour: - * `jmeter.sshmon.knownHosts`: Filename of a known_hosts file containing public keys of trusted remote servers (in OpenSSH format). If not set, no validation will be performed. - * `jmeter.sshmon.interval`: Define the metrics collection interval in milliseconds (default=1 second). - * `jmeter.sshmon.forceOutputFile` - (true/false) makes sure JMeter writes metrics to CSV file in the current directory if no filename is specified (default=false). + * `jmeter.sshmon.knownHosts`: Filename of a known_hosts file containing public keys of trusted remote servers (in OpenSSH format). + If defined, connections to unknown hosts will be rejected (via `StrictHostKeyChecking=yes`). + If undefined, connections to unknown hosts will be established (via `StrictHostKeyChecking=no`). + Default: undefined. + * `jmeter.sshmon.interval`: Metrics collection interval in milliseconds. + This is inclusive of the execution time of the remote commands. + Default: 1 second. + * `jmeter.sshmon.forceOutputFile` (true/false): Makes sure JMeter writes metrics to CSV file in the current directory if no filename is specified. + Default: false. Limitations ----------- -* Samples are collected by a single thread, so if the command takes more than an insignificant amount of time to run, the frequency of sample collection will be limited. -A separate monitor may be used in this case. -* The help link on the plugin GUI currently points to an incorrect location. This is to be resolved with the next release of `jmeter-plugins-cmn-jmeter` (see [this PR](https://github.com/undera/jmeter-plugins/pull/162)). +* Samples are collected by a single thread, so if a command takes more than an insignificant amount of time to run, the frequency of sample collection will be limited. +Even more so if more than one command is sampled. In this case, use a separate monitor for each sample command. +* When a JMeter test ends, this plugin will not interrupt the collector thread but let the current sample finish before stopping. +This may take longer than the JMeter engine [waits](https://jmeter.apache.org/usermanual/get-started.html#shutdown) in headless (non-GUI) mode. +In this case, increase the JMeter property `jmeter.exit.check.pause`. diff --git a/pom.xml b/pom.xml index 2ea62ec..547c45a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,12 +4,13 @@ co.nz.breakpoint.jmeter jmeter-sshmon jar - 1.0 + 1.1-SNAPSHOT jmeter-sshmon - http://maven.apache.org UTF-8 + 1.8 + 1.8 @@ -80,7 +81,6 @@ start - true java -cp @@ -130,7 +130,7 @@ kg.apc jmeter-plugins-cmn-jmeter - 0.5 + 0.6 com.jcraft @@ -140,12 +140,8 @@ org.apache.commons commons-pool2 - 2.4.2 - - - commons-io - commons-io - 2.5 + 2.6.0 + provided kg.apc diff --git a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/JSchLogger.java b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/JSchLogger.java new file mode 100644 index 0000000..c7eed46 --- /dev/null +++ b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/JSchLogger.java @@ -0,0 +1,34 @@ +package nz.co.breakpoint.jmeter.vizualizers.sshmon; + +import java.util.HashMap; +import java.util.Map; +import com.jcraft.jsch.Logger; +import org.apache.jorphan.logging.LoggingManager; +import org.apache.log.Priority; + +class JSchLogger implements Logger { + + private static final org.apache.log.Logger log = LoggingManager.getLoggerForClass(); + + private static final Map levels = new HashMap(); + static { + levels.put(Logger.DEBUG, Priority.DEBUG); + levels.put(Logger.INFO, Priority.INFO); + levels.put(Logger.WARN, Priority.WARN); + levels.put(Logger.ERROR, Priority.ERROR); + levels.put(Logger.FATAL, Priority.FATAL_ERROR); + } + + @Override + public boolean isEnabled(int level) { + return log.isPriorityEnabled(levels.get(level)); + } + + @Override + public void log(int level, String message) { + Priority p = levels.get(level); + if (p != null) { + log.log(p, message); + } + } +} \ No newline at end of file diff --git a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonCollector.java b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonCollector.java index 8c75073..5ebee4e 100644 --- a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonCollector.java +++ b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonCollector.java @@ -53,4 +53,10 @@ protected void initiateConnectors() { samplers.add(new SSHMonSampler(label, connectionDetails, command, isDelta)); } } + + @Override + public void testEnded(String host) { + super.testEnded(host); + SSHMonSampler.clearConnectionPool(); + } } diff --git a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonSampler.java b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonSampler.java index 3f68d88..b2f9a29 100644 --- a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonSampler.java +++ b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHMonSampler.java @@ -1,11 +1,10 @@ package nz.co.breakpoint.jmeter.vizualizers.sshmon; -import java.io.InterruptedIOException; +import java.io.ByteArrayOutputStream; import kg.apc.jmeter.vizualizers.MonitoringSampler; import kg.apc.jmeter.vizualizers.MonitoringSampleGenerator; -import org.apache.commons.io.IOUtils; import org.apache.commons.pool2.KeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPool; import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; @@ -35,12 +34,23 @@ public class SSHMonSampler */ private static KeyedObjectPool pool; static { - GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig(); + GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); config.setMinIdlePerKey(1); + config.setTestOnBorrow(true); log.debug("Creating GenericKeyedObjectPool"); pool = new GenericKeyedObjectPool(new SSHSessionFactory(), config); } + public static void clearConnectionPool() { + log.debug("Clearing connection pool"); + try { + pool.clear(); + } + catch (Exception e) { + log.error("Failed to clear connection pool: ", e); + } + } + public SSHMonSampler(String name, ConnectionDetails connectionDetails, String remoteCommand, boolean sampleDeltaValue) { this.metricName = name; this.connectionDetails = connectionDetails; @@ -52,6 +62,7 @@ public SSHMonSampler(String name, ConnectionDetails connectionDetails, String re public void generateSamples(MonitoringSampleGenerator collector) { Session session = null; ChannelExec channel = null; + ByteArrayOutputStream result = new ByteArrayOutputStream(); try { log.debug("Borrowing session for "+connectionDetails); @@ -60,10 +71,14 @@ public void generateSamples(MonitoringSampleGenerator collector) { channel = (ChannelExec)session.openChannel("exec"); channel.setCommand(remoteCommand); channel.setPty(true); + channel.setOutputStream(result); channel.connect(); - - final double val = Double.valueOf(IOUtils.toString(channel.getInputStream()).trim()); + while (!channel.isClosed()) { // wait for command execution to finish + Thread.sleep(10); + } + + final double val = Double.valueOf(result.toString()); if (sampleDeltaValue) { if (!Double.isNaN(oldValue)) { collector.generateSample(val - oldValue, metricName); @@ -73,31 +88,30 @@ public void generateSamples(MonitoringSampleGenerator collector) { collector.generateSample(val, metricName); } } - catch (InterruptedIOException ex) { // stopping the test has caused a thread interrupt - log.info(ex.toString()); + catch (JSchException ex) { + log.error("Channel failure for "+connectionDetails, ex); } - catch (Exception ex) { - log.error(ex.toString()); + catch (Exception ex) { + log.error("Sample failure for "+connectionDetails, ex); } finally { - if (channel != null && channel.isConnected()) { + if (channel != null) { + log.debug("Disconnecting channel for "+connectionDetails); channel.disconnect(); } - if (session != null) { - try { - if (session.isConnected()) { - log.debug("Returning session for "+connectionDetails); - pool.returnObject(connectionDetails, session); - } - else { - log.debug("Invalidating session for "+connectionDetails); - pool.invalidateObject(connectionDetails, session); - } + try { + if (session != null && session.isConnected()) { + log.debug("Returning session for "+connectionDetails); + pool.returnObject(connectionDetails, session); } - catch (Exception ex) { - log.warn(ex.getMessage()); + else { + log.debug("Invalidating session for "+connectionDetails); + pool.invalidateObject(connectionDetails, session); } } + catch (Exception ex) { + log.warn("Failure returning session ", ex); + } } } diff --git a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHSessionFactory.java b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHSessionFactory.java index c5675e0..624ef4f 100644 --- a/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHSessionFactory.java +++ b/src/main/java/nz/co/breakpoint/jmeter/vizualizers/sshmon/SSHSessionFactory.java @@ -17,16 +17,21 @@ public class SSHSessionFactory extends BaseKeyedPooledObjectFactory wrap(Session session) { - return new DefaultPooledObject(session); + return new DefaultPooledObject(session); } @Override From ae694c054bdfabcf9caa05ee32bb6abaf43152b7 Mon Sep 17 00:00:00 2001 From: Till Neunast Date: Sun, 21 Oct 2018 11:40:18 +1300 Subject: [PATCH 2/2] Release 1.1 --- README.md | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0914052..3eaccb2 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ Under tab "Available Plugins", select "SSHMon Samples Collector", then click "Ap ### Via Package from [JMeter-Plugins.org](https://jmeter-plugins.org/) -Extract the [zip package](https://jmeter-plugins.org/files/packages/tilln-sshmon-1.0.zip) into JMeter's lib directory, then restart JMeter. +Extract the [zip package](https://jmeter-plugins.org/files/packages/tilln-sshmon-1.1.zip) into JMeter's lib directory, then restart JMeter. ### Via Manual Download -1. Copy the [jmeter-sshmon jar file](https://github.com/tilln/jmeter-sshmon/releases/download/1.0/jmeter-sshmon-1.0.jar) into JMeter's lib/ext directory. +1. Copy the [jmeter-sshmon jar file](https://github.com/tilln/jmeter-sshmon/releases/download/1.1/jmeter-sshmon-1.1.jar) into JMeter's lib/ext directory. 2. Copy the following dependencies into JMeter's lib directory: * [kg.apc / jmeter-plugins-cmn-jmeter](https://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-cmn-jmeter/0.6/jmeter-plugins-cmn-jmeter-0.6.jar) * [com.jcraft.jsch / jsch](https://search.maven.org/remotecontent?filepath=com/jcraft/jsch/0.1.54/jsch-0.1.54.jar) diff --git a/pom.xml b/pom.xml index 547c45a..2e4b44b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ co.nz.breakpoint.jmeter jmeter-sshmon jar - 1.1-SNAPSHOT + 1.1 jmeter-sshmon