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}