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     */
017    package org.apache.activemq.tool.reports;
018    
019    import java.io.BufferedOutputStream;
020    import java.io.BufferedReader;
021    import java.io.File;
022    import java.io.FileInputStream;
023    import java.io.FileNotFoundException;
024    import java.io.FileOutputStream;
025    import java.io.IOException;
026    import java.io.InputStreamReader;
027    import java.io.PrintWriter;
028    import java.util.ArrayList;
029    import java.util.HashMap;
030    import java.util.Iterator;
031    import java.util.List;
032    import java.util.Map;
033    import java.util.Properties;
034    import java.util.StringTokenizer;
035    
036    import org.apache.activemq.tool.reports.plugins.CpuReportPlugin;
037    import org.apache.activemq.tool.reports.plugins.ThroughputReportPlugin;
038    import org.slf4j.Logger;
039    import org.slf4j.LoggerFactory;
040    
041    public 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    }