Coverage Report - kg.apc.jmeter.perfmon.PerfMonCollector
 
Classes in this File Line Coverage Branch Coverage Complexity
PerfMonCollector
45%
89/196
24%
14/58
3.368
 
 1  
 package kg.apc.jmeter.perfmon;
 2  
 
 3  
 import kg.apc.jmeter.JMeterPluginsUtils;
 4  
 import kg.apc.jmeter.reporters.LoadosophiaUploadingNotifier;
 5  
 import kg.apc.jmeter.vizualizers.CorrectedResultCollector;
 6  
 import kg.apc.perfmon.PerfMonMetricGetter;
 7  
 import kg.apc.perfmon.client.Transport;
 8  
 import kg.apc.perfmon.client.TransportFactory;
 9  
 import kg.apc.perfmon.metrics.MetricParams;
 10  
 import org.apache.jmeter.samplers.SampleEvent;
 11  
 import org.apache.jmeter.samplers.SampleSaveConfiguration;
 12  
 import org.apache.jmeter.testelement.property.CollectionProperty;
 13  
 import org.apache.jmeter.testelement.property.JMeterProperty;
 14  
 import org.apache.jmeter.util.JMeterUtils;
 15  
 import org.apache.jorphan.logging.LoggingManager;
 16  
 import org.apache.log.Logger;
 17  
 
 18  
 import java.io.File;
 19  
 import java.io.IOException;
 20  
 import java.net.InetSocketAddress;
 21  
 import java.net.SocketAddress;
 22  
 import java.text.SimpleDateFormat;
 23  
 import java.util.*;
 24  
 import java.util.concurrent.ConcurrentHashMap;
 25  
 
 26  
 public class PerfMonCollector
 27  
         extends CorrectedResultCollector
 28  
         implements Runnable, PerfMonSampleGenerator {
 29  
 
 30  1
     private static boolean autoGenerateFiles = false;
 31  
     public static final long MEGABYTE = 1024L * 1024L;
 32  
     private static final String PERFMON = "PerfMon";
 33  1
     private static final Logger log = LoggingManager.getLoggerForClass();
 34  
     public static final String DATA_PROPERTY = "metricConnections";
 35  
     private int interval;
 36  15
     private Thread workerThread = null;
 37  15
     private Map<Object, PerfMonAgentConnector> connectors = new ConcurrentHashMap<Object, PerfMonAgentConnector>();
 38  15
     private HashMap<String, Long> oldValues = new HashMap<String, Long>();
 39  1
     private static String autoFileBaseName = null;
 40  1
     private static int counter = 0;
 41  15
     private LoadosophiaUploadingNotifier perfMonNotifier = LoadosophiaUploadingNotifier.getInstance();
 42  1
     private static String workerHost = null;
 43  
 
 44  
     static {
 45  1
         autoGenerateFiles = (JMeterUtils.getPropDefault("forcePerfmonFile", "false")).trim().equalsIgnoreCase("true");
 46  1
     }
 47  
 
 48  
     private static synchronized String getAutoFileName() {
 49  0
         String ret = "";
 50  0
         counter++;
 51  0
         if (autoFileBaseName == null) {
 52  0
             Calendar now = Calendar.getInstance();
 53  0
             SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HHmmss");
 54  0
             autoFileBaseName = "perfMon_" + formatter.format(now.getTime());
 55  
         }
 56  0
         ret = ret + autoFileBaseName;
 57  0
         if (counter > 1) {
 58  0
             ret = ret + "_" + counter;
 59  
         }
 60  0
         ret = ret + ".csv";
 61  
 
 62  0
         return ret;
 63  
     }
 64  
 
 65  15
     public PerfMonCollector() {
 66  
         // TODO: document it
 67  15
         interval = JMeterUtils.getPropDefault("jmeterPlugin.perfmon.interval", 1000);
 68  15
     }
 69  
 
 70  
     public void setData(CollectionProperty rows) {
 71  4
         setProperty(rows);
 72  4
     }
 73  
 
 74  
     public JMeterProperty getMetricSettings() {
 75  3
         return getProperty(DATA_PROPERTY);
 76  
     }
 77  
 
 78  
     public void sampleOccurred(SampleEvent event) {
 79  
         // just dropping regular test samples
 80  1
     }
 81  
 
 82  
     @Override
 83  
     public synchronized void run() {
 84  
         while (true) {
 85  24
             processConnectors();
 86  
             try {
 87  24
                 this.wait(interval);
 88  0
             } catch (InterruptedException ex) {
 89  0
                 log.debug("Monitoring thread was interrupted", ex);
 90  0
                 break;
 91  23
             }
 92  
         }
 93  0
     }
 94  
 
 95  
     //ensure we start only on one host (if multiple slaves)
 96  
     private synchronized static boolean isWorkingHost(String host) {
 97  2
         if (workerHost == null) {
 98  1
             workerHost = host;
 99  1
             return true;
 100  
         } else {
 101  1
             return host.equals(workerHost);
 102  
         }
 103  
     }
 104  
 
 105  
     @Override
 106  
     public void testStarted(String host) {
 107  
 
 108  2
         if (!isWorkingHost(host)) {
 109  1
             return;
 110  
         }
 111  
 
 112  
         //ensure the data will be saved
 113  1
         if (getProperty(FILENAME) == null || getProperty(FILENAME).getStringValue().trim().length() == 0) {
 114  1
             if (autoGenerateFiles) {
 115  0
                 setupSaving(getAutoFileName());
 116  
             } else {
 117  
                 try {
 118  1
                     File tmpFile = File.createTempFile("perfmon_", ".jtl");
 119  1
                     tmpFile.delete(); // required to have CSV header
 120  1
                     setupSaving(tmpFile.getAbsolutePath());
 121  0
                 } catch (IOException ex) {
 122  0
                     log.info("PerfMon metrics will not be recorded! Please run the test with -JforcePerfmonFile=true", ex);
 123  1
                 }
 124  
             }
 125  
         }
 126  
 
 127  1
         log.debug("PerfMon metrics will be stored in " + getPropertyAsString(FILENAME));
 128  1
         if (!getSaveConfig().saveAsXml() && getSaveConfig().saveFieldNames()) {
 129  1
             perfMonNotifier.addFile(getPropertyAsString(FILENAME));
 130  
         } else {
 131  0
             log.warn("Perfmon file saving setting is not CSV with header line, cannot upload it to Loadosophia.org: " + getPropertyAsString(FILENAME));
 132  
         }
 133  1
         initiateConnectors();
 134  
 
 135  1
         workerThread = new Thread(this);
 136  1
         workerThread.start();
 137  
 
 138  1
         super.testStarted(host);
 139  1
     }
 140  
 
 141  
     private void setupSaving(String fileName) {
 142  1
         SampleSaveConfiguration config = getSaveConfig();
 143  1
         JMeterPluginsUtils.doBestCSVSetup(config);
 144  1
         setSaveConfig(config);
 145  1
         setFilename(fileName);
 146  1
         log.info("PerfMon metrics will be stored in " + new File(fileName).getAbsolutePath());
 147  1
     }
 148  
 
 149  
     @Override
 150  
     public void testEnded(String host) {
 151  2
         if (workerThread == null) {
 152  2
             return;
 153  
         }
 154  0
         workerHost = null;
 155  0
         workerThread.interrupt();
 156  0
         shutdownConnectors();
 157  
 
 158  
         //reset autoFileName for next test run
 159  0
         autoFileBaseName = null;
 160  0
         counter = 0;
 161  0
         super.testEnded(host);
 162  0
     }
 163  
 
 164  
     private void initiateConnectors() {
 165  1
         oldValues.clear();
 166  1
         JMeterProperty prop = getMetricSettings();
 167  1
         connectors.clear();
 168  1
         if (!(prop instanceof CollectionProperty)) {
 169  1
             log.warn("Got unexpected property: " + prop);
 170  1
             return;
 171  
         }
 172  0
         CollectionProperty rows = (CollectionProperty) prop;
 173  
 
 174  0
         for (int i = 0; i < rows.size(); i++) {
 175  0
             ArrayList<Object> row = (ArrayList<Object>) rows.get(i).getObjectValue();
 176  0
             String host = ((JMeterProperty) row.get(0)).getStringValue();
 177  0
             int port = ((JMeterProperty) row.get(1)).getIntValue();
 178  0
             String metric = ((JMeterProperty) row.get(2)).getStringValue();
 179  0
             String params = ((JMeterProperty) row.get(3)).getStringValue();
 180  0
             initiateConnector(host, port, i, metric, params);
 181  
         }
 182  
 
 183  0
         Iterator<Object> it = connectors.keySet().iterator();
 184  0
         while (it.hasNext()) {
 185  0
             Object key = it.next();
 186  
             try {
 187  0
                 connectors.get(key).connect();
 188  0
             } catch (IOException ex) {
 189  0
                 log.error("Error connecting to agent", ex);
 190  0
                 connectors.put(key, new UnavailableAgentConnector(ex));
 191  0
             }
 192  0
         }
 193  0
     }
 194  
 
 195  
     private void initiateConnector(String host, int port, int index, String metric, String params) {
 196  0
         InetSocketAddress addr = new InetSocketAddress(host, port);
 197  0
         String stringKey = addr.toString() + "#" + index;
 198  0
         String labelHostname = host;
 199  
 
 200  0
         String useHostnameProp = JMeterUtils.getProperty("jmeterPlugin.perfmon.label.useHostname");
 201  0
         if (useHostnameProp != null && Boolean.parseBoolean(useHostnameProp)) {
 202  0
             labelHostname = JMeterPluginsUtils.getShortHostname(host);
 203  
         }
 204  
 
 205  
         // handle label parameter
 206  0
         MetricParams paramsParsed = MetricParams.createFromString(params);
 207  
         String label;
 208  0
         if (paramsParsed.getLabel().isEmpty()) {
 209  0
             label = labelHostname + " " + metric;
 210  0
             if (params != null && !params.isEmpty()) {
 211  0
                 label = label + " " + params;
 212  
             }
 213  
         } else {
 214  0
             label = labelHostname + " " + metric + " " + paramsParsed.getLabel();
 215  
 
 216  0
             String[] tokens = params.split("(?<!\\\\)" + PerfMonMetricGetter.DVOETOCHIE);
 217  
 
 218  0
             params = "";
 219  
 
 220  0
             for (int i = 0; i < tokens.length; i++) {
 221  0
                 if (!tokens[i].startsWith("label=")) {
 222  0
                     if (params.length() != 0) {
 223  0
                         params = params + PerfMonMetricGetter.DVOETOCHIE;
 224  
                     }
 225  0
                     params = params + tokens[i];
 226  
                 }
 227  
             }
 228  
         }
 229  
 
 230  
         try {
 231  0
             if (connectors.containsKey(addr)) {
 232  0
                 connectors.get(addr).addMetric(metric, params, label);
 233  
             } else {
 234  0
                 PerfMonAgentConnector connector = getConnector(host, port);
 235  0
                 connector.addMetric(metric, params, label);
 236  0
                 connectors.put(addr, connector);
 237  
             }
 238  0
         } catch (IOException e) {
 239  0
             log.error("Problems creating connector", e);
 240  0
             connectors.put(stringKey, new UnavailableAgentConnector(e));
 241  0
         }
 242  0
     }
 243  
 
 244  
     protected PerfMonAgentConnector getConnector(String host, int port) throws IOException {
 245  1
         log.debug("Trying new connector");
 246  1
         SocketAddress addr = new InetSocketAddress(host, port);
 247  1
         Transport transport = null;
 248  
         try {
 249  1
             transport = TransportFactory.TCPInstance(addr);
 250  0
             if (!transport.test()) {
 251  0
                 throw new IOException("Agent is unreachable via TCP");
 252  
             }
 253  1
         } catch (IOException e) {
 254  1
             log.info("Can't connect TCP transport for host: " + addr.toString(), e);
 255  1
             boolean useUDP = JMeterUtils.getPropDefault("jmeterPlugin.perfmon.useUDP", false);
 256  1
             if (!useUDP) {
 257  1
                 throw e;
 258  
             } else {
 259  
                 try {
 260  0
                     log.debug("Connecting UDP");
 261  0
                     transport = TransportFactory.UDPInstance(addr);
 262  0
                     if (!transport.test()) {
 263  0
                         throw new IOException("Agent is unreachable via UDP");
 264  
                     }
 265  0
                 } catch (IOException ex) {
 266  0
                     log.info("Can't connect UDP transport for host: " + addr.toString(), ex);
 267  0
                     throw ex;
 268  0
                 }
 269  
             }
 270  0
         }
 271  0
         NewAgentConnector conn = new NewAgentConnector();
 272  0
         conn.setTransport(transport);
 273  0
         return conn;
 274  
     }
 275  
 
 276  
     private void shutdownConnectors() {
 277  0
         log.debug("Shutting down connectors");
 278  0
         Iterator<Object> it = connectors.keySet().iterator();
 279  0
         while (it.hasNext()) {
 280  0
             Object key = it.next();
 281  0
             final PerfMonAgentConnector conn = connectors.get(key);
 282  0
             log.debug("Shutting down " + conn.toString());
 283  
             //Fix ConcurrentModificationException if more than one host
 284  
             //connectors.remove(key);
 285  0
             it.remove();
 286  0
             conn.disconnect();
 287  0
         }
 288  0
     }
 289  
 
 290  
     private void processConnectors() {
 291  24
         Iterator<Object> it = connectors.keySet().iterator();
 292  24
         while (it.hasNext()) {
 293  0
             Object key = it.next();
 294  0
             PerfMonAgentConnector connector = connectors.get(key);
 295  
             try {
 296  0
                 connector.generateSamples(this);
 297  0
             } catch (IOException e) {
 298  0
                 log.error(e.getMessage());
 299  0
                 connectors.put(key, new UnavailableAgentConnector(e));
 300  0
             }
 301  0
         }
 302  24
     }
 303  
 
 304  
     //need floating point precision for memory and cpu
 305  
     @Override
 306  
     public void generateSample(double value, String label) {
 307  1
         PerfMonSampleResult res = new PerfMonSampleResult();
 308  1
         res.setSampleLabel(label);
 309  1
         res.setValue(value);
 310  1
         res.setSuccessful(true);
 311  1
         SampleEvent e = new SampleEvent(res, PERFMON);
 312  1
         super.sampleOccurred(e);
 313  1
     }
 314  
 
 315  
     @Override
 316  
     public void generateErrorSample(String label, String errorMsg) {
 317  1
         PerfMonSampleResult res = new PerfMonSampleResult();
 318  1
         res.setSampleLabel(label);
 319  1
         res.setValue(-1L);
 320  1
         res.setResponseMessage(errorMsg);
 321  1
         res.setSuccessful(false);
 322  1
         SampleEvent e = new SampleEvent(res, PERFMON);
 323  1
         super.sampleOccurred(e);
 324  1
         log.error("Perfmon plugin error: " + errorMsg);
 325  1
     }
 326  
 
 327  
     @Override
 328  
     public void generate2Samples(long[] values, String label1, String label2) {
 329  1
         generate2Samples(values, label1, label2, 1d);
 330  1
     }
 331  
 
 332  
     //float precision required for net io
 333  
     @Override
 334  
     public void generate2Samples(long[] values, String label1, String label2, double dividingFactor) {
 335  2
         if (oldValues.containsKey(label1) && oldValues.containsKey(label2)) {
 336  0
             generateSample(((double) (values[0] - oldValues.get(label1).longValue())) / dividingFactor, label1);
 337  0
             generateSample(((double) (values[1] - oldValues.get(label2).longValue())) / dividingFactor, label2);
 338  
         }
 339  2
         oldValues.put(label1, new Long(values[0]));
 340  2
         oldValues.put(label2, new Long(values[1]));
 341  2
     }
 342  
 }