FELIX-1042 Apply patch adding LogService panel (Thanks Filippo Diotalevi)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@766306 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/LogServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/LogServlet.java
new file mode 100644
index 0000000..7400801
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/LogServlet.java
@@ -0,0 +1,229 @@
+/*
+ * 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.felix.webconsole.internal.compendium;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.webconsole.internal.BaseWebConsolePlugin;
+import org.apache.felix.webconsole.internal.Util;
+import org.apache.felix.webconsole.internal.servlet.OsgiManager;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
+
+
+public class LogServlet extends BaseWebConsolePlugin
+{
+ public static final String LABEL = "logs";
+ public static final String TITLE = "Log Service";
+
+ private final static int MAX_LOGS = 200; //maximum number of log entries
+
+
+ public LogServlet()
+ {
+ }
+
+
+ public String getLabel()
+ {
+ return LABEL;
+ }
+
+
+ public String getTitle()
+ {
+ return TITLE;
+ }
+
+
+ protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException
+ {
+ final String minLevel = getParameter( req, "minLevel" );
+ resp.setContentType( "application/json" );
+ resp.setCharacterEncoding( "utf-8" );
+
+ renderJSON( resp.getWriter(), extractLogLevel( minLevel ) );
+ }
+
+
+ private void renderJSON( final PrintWriter pw, int minLogLevel ) throws IOException
+ {
+ // create status line
+ final LogReaderService logReaderService = ( LogReaderService ) this.getService( LogReaderService.class
+ .getName() );
+
+ StringBuffer statusLine = new StringBuffer();
+ if ( logReaderService == null )
+ {
+ statusLine.append( "Log Service is not installed/running." );
+ }
+ else
+ {
+ statusLine.append( "Log Service is running." );
+ }
+
+ JSONWriter jw = new JSONWriter( pw );
+ try
+ {
+ jw.object();
+
+ jw.key( "status" );
+ jw.value( statusLine );
+
+ jw.key( "data" );
+ jw.array();
+
+ int index = 0;
+ for ( Enumeration logEntries = logReaderService.getLog(); logEntries.hasMoreElements() && index < MAX_LOGS; )
+ {
+ LogEntry nextLog = ( LogEntry ) logEntries.nextElement();
+ if ( nextLog.getLevel() <= minLogLevel )
+ {
+ logJson( jw, nextLog, index++ );
+ }
+ }
+
+ jw.endArray();
+
+ jw.endObject();
+
+ }
+ catch ( JSONException je )
+ {
+ throw new IOException( je.toString() );
+ }
+
+ }
+
+
+ private int extractLogLevel( String minLevel )
+ {
+ if ( minLevel == null )
+ return LogService.LOG_DEBUG;
+
+ int minLogLevel = LogService.LOG_DEBUG;;
+ try
+ {
+ minLogLevel = Integer.parseInt( minLevel );
+ }
+ catch ( Throwable t )
+ {
+ minLogLevel = LogService.LOG_DEBUG;
+ }
+ return minLogLevel;
+ }
+
+
+ protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ final String minLevel = getParameter( request, "minLevel" );
+ final String info = request.getPathInfo();
+ if ( info.endsWith( ".json" ) )
+ {
+ response.setContentType( "application/json" );
+ response.setCharacterEncoding( "UTF-8" );
+
+ PrintWriter pw = response.getWriter();
+ this.renderJSON( pw, extractLogLevel( minLevel ) );
+ return;
+ }
+ super.doGet( request, response );
+ }
+
+
+ protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
+ IOException
+ {
+ final PrintWriter pw = response.getWriter();
+
+ final String appRoot = ( String ) request.getAttribute( OsgiManager.ATTR_APP_ROOT );
+ Util.script( pw, appRoot, "logs.js" );
+
+ pw.println( "<div id='plugin_content'/>" );
+
+ Util.startScript( pw );
+ pw.println( "renderLogs( );" );
+ Util.endScript( pw );
+ }
+
+
+ private void logJson( JSONWriter jw, LogEntry info, int index ) throws JSONException
+ {
+ jw.object();
+ jw.key( "id" );
+ jw.value( String.valueOf( index ) );
+ jw.key( "received" );
+ jw.value( info.getTime() );
+ jw.key( "level" );
+ jw.value( logLevel( info.getLevel() ) );
+ jw.key( "message" );
+ jw.value( info.getMessage() );
+ jw.key( "service" );
+ jw.value( serviceDescription( info.getServiceReference() ) );
+ jw.key( "exception" );
+ jw.value( exceptionMessage( info.getException() ) );
+ jw.endObject();
+ }
+
+
+ private String serviceDescription( ServiceReference serviceReference )
+ {
+ if ( serviceReference == null )
+ return "";
+ else
+ return serviceReference.toString();
+ }
+
+
+ private String logLevel( int level )
+ {
+ switch ( level )
+ {
+ case LogService.LOG_INFO:
+ return "INFO";
+ case LogService.LOG_WARNING:
+ return "WARNING";
+ case LogService.LOG_ERROR:
+ return "ERROR";
+ case LogService.LOG_DEBUG:
+ default:
+ return "DEBUG";
+ }
+ }
+
+
+ private String exceptionMessage( Throwable e )
+ {
+ if ( e == null )
+ return "";
+ else
+ return e.getClass().getName()+": "+e.getMessage();
+ }
+
+}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 6981d63..0a55361 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -116,6 +116,7 @@
{ "org.apache.felix.webconsole.internal.compendium.ComponentConfigurationPrinter",
"org.apache.felix.webconsole.internal.compendium.ComponentsServlet",
"org.apache.felix.webconsole.internal.compendium.ConfigManager",
+ "org.apache.felix.webconsole.internal.compendium.LogServlet",
"org.apache.felix.webconsole.internal.core.BundlesServlet",
"org.apache.felix.webconsole.internal.core.InstallAction",
"org.apache.felix.webconsole.internal.core.SetStartLevelAction",
diff --git a/webconsole/src/main/resources/res/ui/admin.css b/webconsole/src/main/resources/res/ui/admin.css
index 37f201c..a5f4aec 100644
--- a/webconsole/src/main/resources/res/ui/admin.css
+++ b/webconsole/src/main/resources/res/ui/admin.css
@@ -572,6 +572,15 @@
vertical-align: middle;
padding-right: 10px;
padding-top: 8px;
+ color: #F0F0F0;
+ font-size: 10px;
+}
+div.buttons select {
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ font-size: 9px;
+ font-weight: normal;
+ display: inline;
+ float:none;
}
div.button {
display: inline-block;
diff --git a/webconsole/src/main/resources/res/ui/logs.js b/webconsole/src/main/resources/res/ui/logs.js
new file mode 100644
index 0000000..0a3656f
--- /dev/null
+++ b/webconsole/src/main/resources/res/ui/logs.js
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+function renderStatusLine() {
+ $("#plugin_content").append( "<div class='fullwidth'><div class='statusline'/></div>" );
+}
+
+function renderView( /* Array of String */ columns, /* String */ buttons ) {
+ renderStatusLine();
+ renderButtons(buttons);
+ var txt = "<div class='table'><table id='plugin_table' class='tablelayout'><thead><tr>";
+ for ( var name in columns ) {
+ txt = txt + "<th class='col_" + columns[name] + "'>" + columns[name] + "</th>";
+ }
+ txt = txt + "</tr></thead><tbody></tbody></table></div>";
+ $("#plugin_content").append( txt );
+ renderButtons(buttons);
+ renderStatusLine();
+}
+
+function renderButtons( buttons ) {
+ $("#plugin_content").append( "<form method='post' enctype='multipart/form-data'><div class='fullwidth'><div class='buttons'>" +
+ buttons + "</div></div></form>" );
+}
+
+function renderData( eventData ) {
+ $(".statusline").empty().append(eventData.status);
+ $("#plugin_table > tbody > tr").remove();
+ for ( var idx in eventData.data ) {
+ entry( eventData.data[idx] );
+ }
+ $("#plugin_table").trigger("update");
+}
+
+function entry( /* Object */ dataEntry ) {
+ var trElement = tr( null, { id: "entry" + dataEntry.id } );
+ entryInternal( trElement, dataEntry );
+ $("#plugin_table > tbody").append(trElement);
+}
+
+function entryInternal( /* Element */ parent, /* Object */ dataEntry ) {
+ var id = dataEntry.id;
+ var message = dataEntry.message;
+ var level = dataEntry.level;
+ var exception = dataEntry.exception;
+ var service = dataEntry.service;
+
+ parent.appendChild( td( null, null, [ text( printDate(dataEntry.received) ) ] ) );
+ parent.appendChild( td( null, null, [ text( level ) ] ) );
+ parent.appendChild( td( null, null, [ text( message ) ] ) );
+ parent.appendChild( td( null, null, [ text( service ) ] ) );
+ parent.appendChild( td( null, null, [ text( exception ) ] ) );
+}
+
+/* displays a date in the user's local timezone */
+function printDate(time) {
+ var date = time ? new Date(time) : new Date();
+ return date.toLocaleString();
+}
+
+function loadData() {
+ $.get(pluginRoot + "/data.json", { "minLevel":$("#minLevel").val()}, function(data) {
+ renderData(data);
+ }, "json");
+}
+
+function renderLogs() {
+ $(document).ready(function(){
+ renderView( ["Received", "Level", "Message", "Service", "Exception"],
+ "<span>Severity at least: <select id='minLevel'><option value='1'>ERROR</option>" +
+ "<option value='2'>WARN</option><option value='3'>INFO</option><option value='4' selected='selected'>DEBUG</option></select></span> "+
+ "<button class='reloadButton' type='button' name='reload'>Reload</button>");
+ loadData();
+
+ $("#plugin_table").tablesorter();
+ $(".reloadButton").click(loadData);
+ $("#minLevel").change(function() {
+ $.post(pluginRoot, { "minLevel":$("#minLevel").val()}, function(data) {
+ renderData(data);
+ }, "json");
+ });
+ });
+}
\ No newline at end of file