001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.tool.reports; 018 019import java.io.BufferedOutputStream; 020import java.io.BufferedReader; 021import java.io.File; 022import java.io.FileInputStream; 023import java.io.FileNotFoundException; 024import java.io.FileOutputStream; 025import java.io.IOException; 026import java.io.InputStreamReader; 027import java.io.PrintWriter; 028import java.util.ArrayList; 029import java.util.HashMap; 030import java.util.Iterator; 031import java.util.List; 032import java.util.Map; 033import java.util.Properties; 034import java.util.StringTokenizer; 035 036import org.apache.activemq.tool.reports.plugins.CpuReportPlugin; 037import org.apache.activemq.tool.reports.plugins.ThroughputReportPlugin; 038import org.slf4j.Logger; 039import org.slf4j.LoggerFactory; 040 041public class XmlFilePerfReportWriter extends AbstractPerfReportWriter { 042 043 private static final Logger LOG = LoggerFactory.getLogger(XmlFilePerfReportWriter.class); 044 045 private File tempLogFile; 046 private PrintWriter tempLogFileWriter; 047 048 private File xmlFile; 049 private PrintWriter xmlFileWriter; 050 051 private String reportDir; 052 private String reportName; 053 054 private Map<String, Properties> testPropsMap; 055 private List<Properties> testPropsList; 056 057 public XmlFilePerfReportWriter() { 058 this("", "PerformanceReport.xml"); 059 } 060 061 public XmlFilePerfReportWriter(String reportDir, String reportName) { 062 this.testPropsMap = new HashMap<String, Properties>(); 063 this.testPropsList = new ArrayList<Properties>(); 064 this.reportDir = reportDir; 065 this.reportName = reportName; 066 } 067 068 public void openReportWriter() { 069 if (tempLogFile == null) { 070 tempLogFile = createTempLogFile(); 071 } 072 073 try { 074 // Disable auto-flush and allocate 100kb of buffer 075 tempLogFileWriter = new PrintWriter(new BufferedOutputStream(new FileOutputStream(tempLogFile), 102400), false); 076 } catch (FileNotFoundException e) { 077 e.printStackTrace(); 078 } 079 } 080 081 public void closeReportWriter() { 082 // Flush and close log file writer 083 tempLogFileWriter.flush(); 084 tempLogFileWriter.close(); 085 086 writeToXml(); 087 } 088 089 public String getReportDir() { 090 return reportDir; 091 } 092 093 public void setReportDir(String reportDir) { 094 this.reportDir = reportDir; 095 } 096 097 public String getReportName() { 098 return reportName; 099 } 100 101 public void setReportName(String reportName) { 102 this.reportName = reportName; 103 } 104 105 public File getXmlFile() { 106 return xmlFile; 107 } 108 109 public void setXmlFile(File xmlFile) { 110 this.xmlFile = xmlFile; 111 } 112 113 public void writeInfo(String info) { 114 tempLogFileWriter.println("[INFO]" + info); 115 } 116 117 public void writeCsvData(int csvType, String csvData) { 118 if (csvType == REPORT_PLUGIN_THROUGHPUT) { 119 tempLogFileWriter.println("[TP-DATA]" + csvData); 120 } else if (csvType == REPORT_PLUGIN_CPU) { 121 tempLogFileWriter.println("[CPU-DATA]" + csvData); 122 } 123 } 124 125 public void writeProperties(String header, Properties props) { 126 testPropsMap.put(header, props); 127 } 128 129 public void writeProperties(Properties props) { 130 testPropsList.add(props); 131 } 132 133 protected File createTempLogFile() { 134 File f; 135 try { 136 f = File.createTempFile("tmpPL", null); 137 } catch (IOException e) { 138 f = new File("tmpPL" + System.currentTimeMillis() + ".tmp"); 139 } 140 f.deleteOnExit(); 141 return f; 142 } 143 144 protected File createXmlFile() { 145 String filename = getReportName().endsWith(".xml") ? getReportName() : (getReportName() + ".xml"); 146 String path = (getReportDir() == null) ? "" : getReportDir(); 147 148 return new File(path + filename); 149 } 150 151 protected void writeToXml() { 152 try { 153 xmlFile = createXmlFile(); 154 xmlFileWriter = new PrintWriter(new FileOutputStream(xmlFile)); 155 writeXmlHeader(); 156 writeXmlTestSettings(); 157 writeXmlLogFile(); 158 writeXmlPerfSummary(); 159 writeXmlFooter(); 160 xmlFileWriter.close(); 161 162 LOG.info("Created performance report: " + xmlFile.getAbsolutePath()); 163 } catch (Exception e) { 164 e.printStackTrace(); 165 } 166 } 167 168 protected void writeXmlHeader() { 169 xmlFileWriter.println("<testResult>"); 170 } 171 172 protected void writeXmlFooter() { 173 xmlFileWriter.println("</testResult>"); 174 } 175 176 protected void writeXmlTestSettings() { 177 Properties props; 178 179 // Write test settings 180 for (Iterator<String> i = testPropsMap.keySet().iterator(); i.hasNext();) { 181 String key = i.next(); 182 props = testPropsMap.get(key); 183 writeMap(key, props); 184 } 185 186 int count = 1; 187 for (Iterator<Properties> i = testPropsList.iterator(); i.hasNext();) { 188 props = i.next(); 189 writeMap("settings" + count++, props); 190 } 191 } 192 193 protected void writeXmlLogFile() throws IOException { 194 // Write throughput data 195 xmlFileWriter.println("<property name='performanceData'>"); 196 xmlFileWriter.println("<list>"); 197 198 try (FileInputStream fileInputStream = new FileInputStream(tempLogFile); 199 InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream); 200 BufferedReader reader = new BufferedReader(inputStreamReader)) { 201 202 String line; 203 while ((line = reader.readLine()) != null) { 204 if (line.startsWith("[TP-DATA]")) { 205 handleCsvData(REPORT_PLUGIN_THROUGHPUT, line.substring("[TP-DATA]".length())); 206 parsePerfCsvData("tpdata", line.substring("[TP-DATA]".length())); 207 } else if (line.startsWith("[CPU-DATA]")) { 208 handleCsvData(REPORT_PLUGIN_CPU, line.substring("[CPU-DATA]".length())); 209 parsePerfCsvData("cpudata", line.substring("[CPU-DATA]".length())); 210 } else if (line.startsWith("[INFO]")) { 211 xmlFileWriter.println("<info>" + line + "</info>"); 212 } else { 213 xmlFileWriter.println("<error>" + line + "</error>"); 214 } 215 } 216 } 217 xmlFileWriter.println("</list>"); 218 xmlFileWriter.println("</property>"); 219 } 220 221 protected void writeXmlPerfSummary() { 222 223 Map summary; 224 225 summary = getSummary(REPORT_PLUGIN_THROUGHPUT); 226 if (summary != null && summary.size() > 0) { 227 writeThroughputSummary(summary); 228 } 229 230 summary = getSummary(REPORT_PLUGIN_CPU); 231 if (summary != null && summary.size() > 0) { 232 writeCpuSummary(summary); 233 } 234 235 } 236 237 protected void writeThroughputSummary(Map summary) { 238 // Write throughput summary 239 xmlFileWriter.println("<property name='perfTpSummary'>"); 240 xmlFileWriter.println("<props>"); 241 242 String val; 243 String clientName; 244 String clientVal; 245 246 System.out.println("#########################################"); 247 System.out.println("#### SYSTEM THROUGHPUT SUMMARY ####"); 248 System.out.println("#########################################"); 249 250 val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_TOTAL_TP); 251 System.out.println("System Total Throughput: " + val); 252 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_TOTAL_TP + "'>" + val + "</prop>"); 253 254 val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_TOTAL_CLIENTS); 255 System.out.println("System Total Clients: " + val); 256 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_TOTAL_CLIENTS + "'>" + val + "</prop>"); 257 258 val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_TP); 259 System.out.println("System Average Throughput: " + val); 260 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_TP + "'>" + val + "</prop>"); 261 262 val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_EMM_TP); 263 System.out.println("System Average Throughput Excluding Min/Max: " + val); 264 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_EMM_TP + "'>" + val + "</prop>"); 265 266 val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_TP); 267 System.out.println("System Average Client Throughput: " + val); 268 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_TP + "'>" + val + "</prop>"); 269 270 val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_EMM_TP); 271 System.out.println("System Average Client Throughput Excluding Min/Max: " + val); 272 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_EMM_TP + "'>" + val + "</prop>"); 273 274 val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_TP); 275 clientName = val.substring(0, val.indexOf("=")); 276 clientVal = val.substring(val.indexOf("=") + 1); 277 System.out.println("Min Client Throughput Per Sample: clientName=" + clientName + ", value=" + clientVal); 278 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 279 280 val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_TP); 281 clientName = val.substring(0, val.indexOf("=")); 282 clientVal = val.substring(val.indexOf("=") + 1); 283 System.out.println("Max Client Throughput Per Sample: clientName=" + clientName + ", value=" + clientVal); 284 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 285 286 val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_TOTAL_TP); 287 clientName = val.substring(0, val.indexOf("=")); 288 clientVal = val.substring(val.indexOf("=") + 1); 289 System.out.println("Min Client Total Throughput: clientName=" + clientName + ", value=" + clientVal); 290 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_TOTAL_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 291 292 val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_TOTAL_TP); 293 clientName = val.substring(0, val.indexOf("=")); 294 clientVal = val.substring(val.indexOf("=") + 1); 295 System.out.println("Max Client Total Throughput: clientName=" + clientName + ", value=" + clientVal); 296 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_TOTAL_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 297 298 val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_TP); 299 clientName = val.substring(0, val.indexOf("=")); 300 clientVal = val.substring(val.indexOf("=") + 1); 301 System.out.println("Min Average Client Throughput: clientName=" + clientName + ", value=" + clientVal); 302 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 303 304 val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_TP); 305 clientName = val.substring(0, val.indexOf("=")); 306 clientVal = val.substring(val.indexOf("=") + 1); 307 System.out.println("Max Average Client Throughput: clientName=" + clientName + ", value=" + clientVal); 308 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 309 310 val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_EMM_TP); 311 clientName = val.substring(0, val.indexOf("=")); 312 clientVal = val.substring(val.indexOf("=") + 1); 313 System.out.println("Min Average Client Throughput Excluding Min/Max: clientName=" + clientName + ", value=" + clientVal); 314 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_EMM_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 315 316 val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_EMM_TP); 317 clientName = val.substring(0, val.indexOf("=")); 318 clientVal = val.substring(val.indexOf("=") + 1); 319 System.out.println("Max Average Client Throughput Excluding Min/Max: clientName=" + clientName + ", value=" + clientVal); 320 xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_EMM_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>"); 321 322 xmlFileWriter.println("</props>"); 323 xmlFileWriter.println("</property>"); 324 } 325 326 protected void writeCpuSummary(Map summary) { 327 xmlFileWriter.println("<property name='perfTpSummary'>"); 328 xmlFileWriter.println("<props>"); 329 330 System.out.println("########################################"); 331 System.out.println("#### SYSTEM CPU USAGE SUMMARY ####"); 332 System.out.println("########################################"); 333 334 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_BLOCK_RECV + "'>" + summary.get(CpuReportPlugin.KEY_BLOCK_RECV) + "</prop>"); 335 System.out.println("Total Blocks Received: " + summary.get(CpuReportPlugin.KEY_BLOCK_RECV)); 336 337 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_BLOCK_RECV + "'>" + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_RECV) + "</prop>"); 338 System.out.println("Ave Blocks Received: " + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_RECV)); 339 340 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_BLOCK_SENT + "'>" + summary.get(CpuReportPlugin.KEY_BLOCK_SENT) + "</prop>"); 341 System.out.println("Total Blocks Sent: " + summary.get(CpuReportPlugin.KEY_BLOCK_SENT)); 342 343 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_BLOCK_SENT + "'>" + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_SENT) + "</prop>"); 344 System.out.println("Ave Blocks Sent: " + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_SENT)); 345 346 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_CTX_SWITCH + "'>" + summary.get(CpuReportPlugin.KEY_CTX_SWITCH) + "</prop>"); 347 System.out.println("Total Context Switches: " + summary.get(CpuReportPlugin.KEY_CTX_SWITCH)); 348 349 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_CTX_SWITCH + "'>" + summary.get(CpuReportPlugin.KEY_AVE_CTX_SWITCH) + "</prop>"); 350 System.out.println("Ave Context Switches: " + summary.get(CpuReportPlugin.KEY_AVE_CTX_SWITCH)); 351 352 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_USER_TIME + "'>" + summary.get(CpuReportPlugin.KEY_USER_TIME) + "</prop>"); 353 System.out.println("Total User Time: " + summary.get(CpuReportPlugin.KEY_USER_TIME)); 354 355 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_USER_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_USER_TIME) + "</prop>"); 356 System.out.println("Ave User Time: " + summary.get(CpuReportPlugin.KEY_AVE_USER_TIME)); 357 358 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_SYS_TIME + "'>" + summary.get(CpuReportPlugin.KEY_SYS_TIME) + "</prop>"); 359 System.out.println("Total System Time: " + summary.get(CpuReportPlugin.KEY_SYS_TIME)); 360 361 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_SYS_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_SYS_TIME) + "</prop>"); 362 System.out.println("Ave System Time: " + summary.get(CpuReportPlugin.KEY_AVE_SYS_TIME)); 363 364 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_IDLE_TIME + "'>" + summary.get(CpuReportPlugin.KEY_IDLE_TIME) + "</prop>"); 365 System.out.println("Total Idle Time: " + summary.get(CpuReportPlugin.KEY_IDLE_TIME)); 366 367 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_IDLE_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_IDLE_TIME) + "</prop>"); 368 System.out.println("Ave Idle Time: " + summary.get(CpuReportPlugin.KEY_AVE_IDLE_TIME)); 369 370 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_WAIT_TIME + "'>" + summary.get(CpuReportPlugin.KEY_WAIT_TIME) + "</prop>"); 371 System.out.println("Total Wait Time: " + summary.get(CpuReportPlugin.KEY_WAIT_TIME)); 372 373 xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_WAIT_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_WAIT_TIME) + "</prop>"); 374 System.out.println("Ave Wait Time: " + summary.get(CpuReportPlugin.KEY_AVE_WAIT_TIME)); 375 376 xmlFileWriter.println("</props>"); 377 xmlFileWriter.println("</property>"); 378 } 379 380 protected void writeMap(String name, Map map) { 381 xmlFileWriter.println("<property name='" + name + "'>"); 382 xmlFileWriter.println("<props>"); 383 for (Iterator i = map.keySet().iterator(); i.hasNext();) { 384 String propKey = (String)i.next(); 385 Object propVal = map.get(propKey); 386 xmlFileWriter.println("<prop key='" + propKey + "'>" + propVal.toString() + "</prop>"); 387 } 388 xmlFileWriter.println("</props>"); 389 xmlFileWriter.println("</property>"); 390 } 391 392 protected void parsePerfCsvData(String elementName, String csvData) { 393 StringTokenizer tokenizer = new StringTokenizer(csvData, ",;"); 394 String xmlElement; 395 396 xmlElement = "<" + elementName; 397 String data; 398 String key; 399 String val; 400 while (tokenizer.hasMoreTokens()) { 401 data = tokenizer.nextToken(); 402 key = data.substring(0, data.indexOf("=")); 403 val = data.substring(data.indexOf("=") + 1); 404 xmlElement += " " + key + "='" + val + "'"; 405 } 406 xmlElement += " />"; 407 xmlFileWriter.println(xmlElement); 408 } 409}