You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2013/09/24 09:58:42 UTC
svn commit: r1525810 - in /sling/trunk/contrib/extensions/reqanalyzer: ./
src/main/java/org/apache/sling/reqanalyzer/impl/
src/main/java/org/apache/sling/reqanalyzer/impl/gui/
Author: fmeschbe
Date: Tue Sep 24 07:58:42 2013
New Revision: 1525810
URL: http://svn.apache.org/r1525810
Log:
SLING-3099 Expose the request analyzer log file through the Web Console
- Allow for plain text download
- Allow for zipped download
- Support launching the Swing GUI
Added:
sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalyzerWebConsole.java
Modified:
sling/trunk/contrib/extensions/reqanalyzer/pom.xml
sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java
sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java
sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java
Modified: sling/trunk/contrib/extensions/reqanalyzer/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/pom.xml?rev=1525810&r1=1525809&r2=1525810&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/reqanalyzer/pom.xml (original)
+++ sling/trunk/contrib/extensions/reqanalyzer/pom.xml Tue Sep 24 07:58:42 2013
@@ -132,6 +132,12 @@
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.2</version>
Modified: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java?rev=1525810&r1=1525809&r2=1525810&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java (original)
+++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalysisLogger.java Tue Sep 24 07:58:42 2013
@@ -23,6 +23,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.util.Hashtable;
import java.util.Iterator;
import javax.servlet.Filter;
@@ -45,7 +46,9 @@ import org.apache.sling.api.SlingHttpSer
import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
import org.apache.sling.engine.EngineConstants;
import org.apache.sling.settings.SlingSettingsService;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
@Component(metatype = false)
@Service
@@ -59,18 +62,40 @@ public class RequestAnalysisLogger imple
private BufferedWriter logFile;
- @SuppressWarnings("unused")
+ private RequestAnalyzerWebConsole requestAnalyzerWebConsole;
+ private ServiceRegistration webConsolePlugin;
+
+ @SuppressWarnings({ "serial" })
@Activate
- private void activate() throws IOException {
+ private void activate(final BundleContext ctx) throws IOException {
final File logFile = new File(settings.getSlingHomePath(), "logs/requesttracker.txt");
logFile.getParentFile().mkdirs();
final FileOutputStream out = new FileOutputStream(logFile, true);
this.logFile = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
+
+ this.requestAnalyzerWebConsole = new RequestAnalyzerWebConsole(logFile);
+ this.webConsolePlugin = ctx.registerService("javax.servlet.Servlet", this.requestAnalyzerWebConsole,
+ new Hashtable<String, Object>() {
+ {
+ put("felix.webconsole.label", "requestanalyzer");
+ put("felix.webconsole.title", "Request Analyzer");
+ put("felix.webconsole.category", "Sling");
+ }
+ });
}
- @SuppressWarnings("unused")
@Deactivate
private void deactivate() throws IOException {
+ if (this.webConsolePlugin != null) {
+ this.webConsolePlugin.unregister();
+ this.webConsolePlugin = null;
+ }
+
+ if (this.requestAnalyzerWebConsole != null) {
+ this.requestAnalyzerWebConsole.dispose();
+ this.requestAnalyzerWebConsole = null;
+ }
+
if (this.logFile != null) {
this.logFile.close();
this.logFile = null;
Added: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalyzerWebConsole.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalyzerWebConsole.java?rev=1525810&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalyzerWebConsole.java (added)
+++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/RequestAnalyzerWebConsole.java Tue Sep 24 07:58:42 2013
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.reqanalyzer.impl;
+
+import java.awt.AWTEvent;
+import java.awt.Dimension;
+import java.awt.GraphicsEnvironment;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.reqanalyzer.impl.gui.MainFrame;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("serial")
+public class RequestAnalyzerWebConsole extends HttpServlet {
+
+ private static final String WINDOW_MARKER = ".showWindow";
+
+ private static final String RAW_FILE_MARKER = ".txt";
+
+ private static final String ZIP_FILE_MARKER = ".txt.zip";
+
+ /** default log */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private final File logFile;
+
+ private final Set<MainFrame> frames;
+
+ RequestAnalyzerWebConsole(final File logFile) {
+ this.logFile = logFile;
+ this.frames = new HashSet<MainFrame>();
+ }
+
+ void dispose() {
+ final Set<MainFrame> frames = new HashSet<MainFrame>(this.frames);
+ this.frames.clear();
+ for (MainFrame mainFrame : frames) {
+ AWTEvent e = new WindowEvent(mainFrame, WindowEvent.WINDOW_CLOSING);
+ Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e);
+ }
+ }
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ if (req.getRequestURI().endsWith(RAW_FILE_MARKER) || req.getRequestURI().endsWith(ZIP_FILE_MARKER)) {
+
+ InputStream input = null;
+ OutputStream output = null;
+ try {
+ input = new FileInputStream(this.logFile);
+ output = resp.getOutputStream();
+
+ if (req.getRequestURI().endsWith(ZIP_FILE_MARKER)) {
+ ZipOutputStream zip = new ZipOutputStream(output);
+ zip.setLevel(Deflater.BEST_SPEED);
+
+ ZipEntry entry = new ZipEntry(this.logFile.getName());
+ entry.setTime(this.logFile.lastModified());
+ entry.setMethod(ZipEntry.DEFLATED);
+
+ zip.putNextEntry(entry);
+
+ output = zip;
+ resp.setContentType("application/zip");
+ } else {
+ resp.setContentType("text/plain");
+ resp.setCharacterEncoding("UTF-8");
+ resp.setHeader("Content-Length", String.valueOf(this.logFile.length())); // might be bigger than
+ }
+ resp.setDateHeader("Last-Modified", this.logFile.lastModified());
+
+ IOUtils.copy(input, output);
+ } catch (IOException ioe) {
+ throw new ServletException("Cannot create copy of log file", ioe);
+ } finally {
+ IOUtils.closeQuietly(input);
+
+ if (output instanceof ZipOutputStream) {
+ ((ZipOutputStream) output).closeEntry();
+ ((ZipOutputStream) output).finish();
+ }
+ }
+
+ resp.flushBuffer();
+
+ } else if (req.getRequestURI().endsWith(WINDOW_MARKER) && !GraphicsEnvironment.isHeadless()) {
+
+ String target = req.getRequestURI();
+ target = target.substring(0, target.length() - WINDOW_MARKER.length());
+
+ showWindow();
+ resp.sendRedirect(target);
+ resp.flushBuffer();
+
+ } else {
+
+ super.service(req, resp);
+
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ PrintWriter pw = resp.getWriter();
+
+ final String fileSize = this.formatByteSize(this.logFile.length());
+ pw.printf("<p class='statline ui-state-highlight'>Request Log Size %s</p>%n", fileSize);
+
+ pw.println("<table class='nicetable ui-widget'>");
+ pw.println(" <thead>");
+ pw.println(" <tr>");
+ pw.println(" <th class='ui-widget-header'>Name</th>");
+ pw.println(" <th class='ui-widget-header'>Last Update</th>");
+ pw.println(" <th class='ui-widget-header'>Size</th>");
+ pw.println(" <th class='ui-widget-header'>Action</th>");
+ pw.println(" </tr>");
+ pw.println("</thead>");
+ pw.println("<tbody>");
+
+ pw.println("<tr>");
+
+ pw.printf("<td><a href='${pluginRoot}%s'>%s</a> (<a href='${pluginRoot}%s'>zipped</a>)</td>%n", RAW_FILE_MARKER, this.logFile.getName(), ZIP_FILE_MARKER);
+ pw.printf("<td>%s</td><td>%s</td>", new Date(this.logFile.lastModified()), fileSize);
+
+ pw.println("<td><ul class='icons ui-widget'>");
+ if (!GraphicsEnvironment.isHeadless()) {
+ pw.printf(
+ "<li title='Analyze Now' class='dynhover ui-state-default ui-corner-all'><a href='${pluginRoot}%s'><span class='ui-icon ui-icon-wrench'></span></a></li>%n",
+ WINDOW_MARKER);
+ // pw.printf(" (<a href='${pluginRoot}%s'>Analyze Now</a>)", WINDOW_MARKER);
+ }
+ // pw.println("<li title='Remove File' class='dynhover ui-state-default ui-corner-all'><span class='ui-icon ui-icon-trash'></span></li>");
+ pw.println("</ul></td>");
+
+ pw.println("</tr></tbody>");
+ pw.println("</table>");
+
+ }
+
+ private void showWindow() throws ServletException, IOException {
+ final File toAnalyze = this.getLogFileCopy();
+
+ final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ MainFrame frame = new MainFrame(toAnalyze, Integer.MAX_VALUE, screenSize);
+ frame.setVisible(true);
+ frame.toFront();
+
+ // exit the application if the main frame is closed
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ if (toAnalyze.exists()) {
+ toAnalyze.delete();
+ }
+ }
+ });
+
+ this.frames.add(frame);
+ }
+
+ private final File getLogFileCopy() throws ServletException {
+ File result = null;
+ InputStream input = null;
+ OutputStream output = null;
+ try {
+ result = File.createTempFile(getServletName(), ".tmp");
+ input = new FileInputStream(this.logFile);
+ output = new FileOutputStream(result);
+ IOUtils.copy(input, output);
+ return result;
+ } catch (IOException ioe) {
+ throw new ServletException("Cannot create copy of log file", ioe);
+ } finally {
+ IOUtils.closeQuietly(input);
+ IOUtils.closeQuietly(output);
+ }
+ }
+
+ private String formatByteSize(final long value) {
+ final String suffix;
+ final String suffixedValue;
+
+ if (value >= 0) {
+ final BigDecimal KB = new BigDecimal(1000L);
+ final BigDecimal MB = new BigDecimal(1000L * 1000);
+ final BigDecimal GB = new BigDecimal(1000L * 1000 * 1000);
+
+ BigDecimal bd = new BigDecimal(value);
+ if (bd.compareTo(GB) > 0) {
+ bd = bd.divide(GB);
+ suffix = "GB";
+ } else if (bd.compareTo(MB) > 0) {
+ bd = bd.divide(MB);
+ suffix = "MB";
+ } else if (bd.compareTo(KB) > 0) {
+ bd = bd.divide(KB);
+ suffix = "kB";
+ } else {
+ suffix = "B";
+ }
+ suffixedValue = bd.setScale(2, RoundingMode.UP).toString();
+ } else {
+ suffixedValue = "n/a";
+ suffix = "";
+ }
+
+ return suffixedValue + suffix;
+ }
+
+}
Modified: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java?rev=1525810&r1=1525809&r2=1525810&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java (original)
+++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/Main.java Tue Sep 24 07:58:42 2013
@@ -21,6 +21,8 @@ package org.apache.sling.reqanalyzer.imp
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
@@ -54,6 +56,14 @@ public class Main {
MainFrame frame = new MainFrame(file, limit, screenSize);
frame.setVisible(true);
+
+ // exit the application if the main frame is closed
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
}
}
Modified: sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java?rev=1525810&r1=1525809&r2=1525810&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java (original)
+++ sling/trunk/contrib/extensions/reqanalyzer/src/main/java/org/apache/sling/reqanalyzer/impl/gui/MainFrame.java Tue Sep 24 07:58:42 2013
@@ -20,8 +20,6 @@ package org.apache.sling.reqanalyzer.imp
import java.awt.Color;
import java.awt.Dimension;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -49,7 +47,7 @@ public class MainFrame extends JFrame {
JTextPane text = Util.showStartupDialog("Reading from " + file, screenSize);
final RequestTrackerFile dm = new RequestTrackerFile(file, limit, text);
-
+
final JTable table = new JTable(dm);
table.setAutoCreateRowSorter(true);
table.setGridColor(Color.GRAY);
@@ -65,14 +63,6 @@ public class MainFrame extends JFrame {
setTitle(file.getPath());
- // exit the application if the main frame is closed
- addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- System.exit(0);
- }
- });
-
// setup location and size and ensure updating preferences
Util.setupComponentLocationSize(this, MAIN_X, MAIN_Y, MAIN_WIDTH, MAIN_HEIGHT, (int) screenSize.getWidth() / 4,
0, (int) screenSize.getWidth() / 2, (int) screenSize.getHeight() / 4);