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        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(tempLogFile)));
199        String line;
200        while ((line = reader.readLine()) != null) {
201            if (line.startsWith("[TP-DATA]")) {
202                handleCsvData(REPORT_PLUGIN_THROUGHPUT, line.substring("[TP-DATA]".length()));
203                parsePerfCsvData("tpdata", line.substring("[TP-DATA]".length()));
204            } else if (line.startsWith("[CPU-DATA]")) {
205                handleCsvData(REPORT_PLUGIN_CPU, line.substring("[CPU-DATA]".length()));
206                parsePerfCsvData("cpudata", line.substring("[CPU-DATA]".length()));
207            } else if (line.startsWith("[INFO]")) {
208                xmlFileWriter.println("<info>" + line + "</info>");
209            } else {
210                xmlFileWriter.println("<error>" + line + "</error>");
211            }
212        }
213
214        xmlFileWriter.println("</list>");
215        xmlFileWriter.println("</property>");
216    }
217
218    protected void writeXmlPerfSummary() {
219
220        Map summary;
221
222        summary = getSummary(REPORT_PLUGIN_THROUGHPUT);
223        if (summary != null && summary.size() > 0) {
224            writeThroughputSummary(summary);
225        }
226
227        summary = getSummary(REPORT_PLUGIN_CPU);
228        if (summary != null && summary.size() > 0) {
229            writeCpuSummary(summary);
230        }
231
232    }
233
234    protected void writeThroughputSummary(Map summary) {
235        // Write throughput summary
236        xmlFileWriter.println("<property name='perfTpSummary'>");
237        xmlFileWriter.println("<props>");
238
239        String val;
240        String clientName;
241        String clientVal;
242
243        System.out.println("#########################################");
244        System.out.println("####    SYSTEM THROUGHPUT SUMMARY    ####");
245        System.out.println("#########################################");
246
247        val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_TOTAL_TP);
248        System.out.println("System Total Throughput: " + val);
249        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_TOTAL_TP + "'>" + val + "</prop>");
250
251        val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_TOTAL_CLIENTS);
252        System.out.println("System Total Clients: " + val);
253        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_TOTAL_CLIENTS + "'>" + val + "</prop>");
254
255        val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_TP);
256        System.out.println("System Average Throughput: " + val);
257        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_TP + "'>" + val + "</prop>");
258
259        val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_EMM_TP);
260        System.out.println("System Average Throughput Excluding Min/Max: " + val);
261        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_EMM_TP + "'>" + val + "</prop>");
262
263        val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_TP);
264        System.out.println("System Average Client Throughput: " + val);
265        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_TP + "'>" + val + "</prop>");
266
267        val = (String)summary.get(ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_EMM_TP);
268        System.out.println("System Average Client Throughput Excluding Min/Max: " + val);
269        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_SYS_AVE_CLIENT_EMM_TP + "'>" + val + "</prop>");
270
271        val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_TP);
272        clientName = val.substring(0, val.indexOf("="));
273        clientVal = val.substring(val.indexOf("=") + 1);
274        System.out.println("Min Client Throughput Per Sample: clientName=" + clientName + ", value=" + clientVal);
275        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
276
277        val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_TP);
278        clientName = val.substring(0, val.indexOf("="));
279        clientVal = val.substring(val.indexOf("=") + 1);
280        System.out.println("Max Client Throughput Per Sample: clientName=" + clientName + ", value=" + clientVal);
281        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
282
283        val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_TOTAL_TP);
284        clientName = val.substring(0, val.indexOf("="));
285        clientVal = val.substring(val.indexOf("=") + 1);
286        System.out.println("Min Client Total Throughput: clientName=" + clientName + ", value=" + clientVal);
287        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_TOTAL_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
288
289        val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_TOTAL_TP);
290        clientName = val.substring(0, val.indexOf("="));
291        clientVal = val.substring(val.indexOf("=") + 1);
292        System.out.println("Max Client Total Throughput: clientName=" + clientName + ", value=" + clientVal);
293        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_TOTAL_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
294
295        val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_TP);
296        clientName = val.substring(0, val.indexOf("="));
297        clientVal = val.substring(val.indexOf("=") + 1);
298        System.out.println("Min Average Client Throughput: clientName=" + clientName + ", value=" + clientVal);
299        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
300
301        val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_TP);
302        clientName = val.substring(0, val.indexOf("="));
303        clientVal = val.substring(val.indexOf("=") + 1);
304        System.out.println("Max Average Client Throughput: clientName=" + clientName + ", value=" + clientVal);
305        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
306
307        val = (String)summary.get(ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_EMM_TP);
308        clientName = val.substring(0, val.indexOf("="));
309        clientVal = val.substring(val.indexOf("=") + 1);
310        System.out.println("Min Average Client Throughput Excluding Min/Max: clientName=" + clientName + ", value=" + clientVal);
311        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MIN_CLIENT_AVE_EMM_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
312
313        val = (String)summary.get(ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_EMM_TP);
314        clientName = val.substring(0, val.indexOf("="));
315        clientVal = val.substring(val.indexOf("=") + 1);
316        System.out.println("Max Average Client Throughput Excluding Min/Max: clientName=" + clientName + ", value=" + clientVal);
317        xmlFileWriter.println("<prop key='" + ThroughputReportPlugin.KEY_MAX_CLIENT_AVE_EMM_TP + "'>clientName=" + clientName + ",value=" + clientVal + "</prop>");
318
319        xmlFileWriter.println("</props>");
320        xmlFileWriter.println("</property>");
321    }
322
323    protected void writeCpuSummary(Map summary) {
324        xmlFileWriter.println("<property name='perfTpSummary'>");
325        xmlFileWriter.println("<props>");
326
327        System.out.println("########################################");
328        System.out.println("####    SYSTEM CPU USAGE SUMMARY    ####");
329        System.out.println("########################################");
330
331        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_BLOCK_RECV + "'>" + summary.get(CpuReportPlugin.KEY_BLOCK_RECV) + "</prop>");
332        System.out.println("Total Blocks Received: " + summary.get(CpuReportPlugin.KEY_BLOCK_RECV));
333
334        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_BLOCK_RECV + "'>" + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_RECV) + "</prop>");
335        System.out.println("Ave Blocks Received: " + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_RECV));
336
337        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_BLOCK_SENT + "'>" + summary.get(CpuReportPlugin.KEY_BLOCK_SENT) + "</prop>");
338        System.out.println("Total Blocks Sent: " + summary.get(CpuReportPlugin.KEY_BLOCK_SENT));
339
340        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_BLOCK_SENT + "'>" + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_SENT) + "</prop>");
341        System.out.println("Ave Blocks Sent: " + summary.get(CpuReportPlugin.KEY_AVE_BLOCK_SENT));
342
343        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_CTX_SWITCH + "'>" + summary.get(CpuReportPlugin.KEY_CTX_SWITCH) + "</prop>");
344        System.out.println("Total Context Switches: " + summary.get(CpuReportPlugin.KEY_CTX_SWITCH));
345
346        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_CTX_SWITCH + "'>" + summary.get(CpuReportPlugin.KEY_AVE_CTX_SWITCH) + "</prop>");
347        System.out.println("Ave Context Switches: " + summary.get(CpuReportPlugin.KEY_AVE_CTX_SWITCH));
348
349        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_USER_TIME + "'>" + summary.get(CpuReportPlugin.KEY_USER_TIME) + "</prop>");
350        System.out.println("Total User Time: " + summary.get(CpuReportPlugin.KEY_USER_TIME));
351
352        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_USER_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_USER_TIME) + "</prop>");
353        System.out.println("Ave User Time: " + summary.get(CpuReportPlugin.KEY_AVE_USER_TIME));
354
355        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_SYS_TIME + "'>" + summary.get(CpuReportPlugin.KEY_SYS_TIME) + "</prop>");
356        System.out.println("Total System Time: " + summary.get(CpuReportPlugin.KEY_SYS_TIME));
357
358        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_SYS_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_SYS_TIME) + "</prop>");
359        System.out.println("Ave System Time: " + summary.get(CpuReportPlugin.KEY_AVE_SYS_TIME));
360
361        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_IDLE_TIME + "'>" + summary.get(CpuReportPlugin.KEY_IDLE_TIME) + "</prop>");
362        System.out.println("Total Idle Time: " + summary.get(CpuReportPlugin.KEY_IDLE_TIME));
363
364        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_IDLE_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_IDLE_TIME) + "</prop>");
365        System.out.println("Ave Idle Time: " + summary.get(CpuReportPlugin.KEY_AVE_IDLE_TIME));
366
367        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_WAIT_TIME + "'>" + summary.get(CpuReportPlugin.KEY_WAIT_TIME) + "</prop>");
368        System.out.println("Total Wait Time: " + summary.get(CpuReportPlugin.KEY_WAIT_TIME));
369
370        xmlFileWriter.println("<prop key='" + CpuReportPlugin.KEY_AVE_WAIT_TIME + "'>" + summary.get(CpuReportPlugin.KEY_AVE_WAIT_TIME) + "</prop>");
371        System.out.println("Ave Wait Time: " + summary.get(CpuReportPlugin.KEY_AVE_WAIT_TIME));
372
373        xmlFileWriter.println("</props>");
374        xmlFileWriter.println("</property>");
375    }
376
377    protected void writeMap(String name, Map map) {
378        xmlFileWriter.println("<property name='" + name + "'>");
379        xmlFileWriter.println("<props>");
380        for (Iterator i = map.keySet().iterator(); i.hasNext();) {
381            String propKey = (String)i.next();
382            Object propVal = map.get(propKey);
383            xmlFileWriter.println("<prop key='" + propKey + "'>" + propVal.toString() + "</prop>");
384        }
385        xmlFileWriter.println("</props>");
386        xmlFileWriter.println("</property>");
387    }
388
389    protected void parsePerfCsvData(String elementName, String csvData) {
390        StringTokenizer tokenizer = new StringTokenizer(csvData, ",;");
391        String xmlElement;
392
393        xmlElement = "<" + elementName;
394        String data;
395        String key;
396        String val;
397        while (tokenizer.hasMoreTokens()) {
398            data = tokenizer.nextToken();
399            key = data.substring(0, data.indexOf("="));
400            val = data.substring(data.indexOf("=") + 1);
401            xmlElement += " " + key + "='" + val + "'";
402        }
403        xmlElement += " />";
404        xmlFileWriter.println(xmlElement);
405    }
406}