Author: bdelacretaz Date: Tue Sep 15 14:52:13 2009 New Revision: 815351 URL: http://svn.apache.org/viewvc?rev=815351&view=rev Log: SLING-1109 - OSGi events recorder and console plugin
Added: sling/trunk/contrib/extensions/osgi-profiler/ (with props) sling/trunk/contrib/extensions/osgi-profiler/pom.xml (with props) sling/trunk/contrib/extensions/osgi-profiler/src/ sling/trunk/contrib/extensions/osgi-profiler/src/main/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/impl/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java (with props) sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java (with props) sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java (with props) sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java (with props) sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/ sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/ sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/ sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties (with props) Propchange: sling/trunk/contrib/extensions/osgi-profiler/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Tue Sep 15 14:52:13 2009 @@ -0,0 +1,15 @@ +target +sling +bin +logs +jackrabbit-repository +derby.log +*.iml +*.ipr +*.iws +.settings +.project +.classpath +.externalToolBuilders +maven-eclipse.xml + Added: sling/trunk/contrib/extensions/osgi-profiler/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/pom.xml?rev=815351&view=auto ============================================================================== --- sling/trunk/contrib/extensions/osgi-profiler/pom.xml (added) +++ sling/trunk/contrib/extensions/osgi-profiler/pom.xml Tue Sep 15 14:52:13 2009 @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>6</version> + <relativePath>../../../parent/pom.xml</relativePath> + </parent> + + <artifactId>org.apache.sling.osgi.event.recorder</artifactId> + <packaging>bundle</packaging> + <version>0.1-SNAPSHOT</version> + + <name>Apache Sling OSGi events recorder</name> + <description> + Records OSGi events and displays a simple graph of events times + on the Felix Webconsole. + </description> + + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/event-recorder</connection> + <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/event-recorder</developerConnection> + <url>http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/event-recorder</url> + </scm> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Export-Package> + org.apache.sling.osgi.event.recorder + </Export-Package> + <Private-Package> + org.apache.sling.osgi.event.recorder.impl.* + </Private-Package> + <DynamicImport-Package> + org.apache.felix.webconsole + </DynamicImport-Package> + <Bundle-Activator> + org.apache.sling.osgi.event.recorder.impl.Activator + </Bundle-Activator> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <excludePackageNames> + org.apache.sling.osgi.event.recorder.impl + </excludePackageNames> + </configuration> + </plugin> + </plugins> + </reporting> + + <dependencies> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.osgi.core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.osgi.compendium</artifactId> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.webconsole</artifactId> + <version>1.2.0</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + <scope>provided</scope> + </dependency> + </dependencies> +</project> Propchange: sling/trunk/contrib/extensions/osgi-profiler/pom.xml ------------------------------------------------------------------------------ svn:eol-style = native Added: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java?rev=815351&view=auto ============================================================================== --- sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java (added) +++ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java Tue Sep 15 14:52:13 2009 @@ -0,0 +1,62 @@ +/* + * 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.osgi.event.recorder; + +import java.util.Iterator; + +/** Record OSGi events and give access to them for display, profiling, etc. */ +public interface OsgiEventsRecorder { + + public static class RecordedEvent { + public RecordedEvent(String entity, String id, String action) { + this.entity = entity; + this.id = id; + this.action = action; + this.timestamp = System.currentTimeMillis(); + } + + /** The OSGi "entity" (framework, bundle, service, etc.) + * that this event refers to */ + public final String entity; + + /** The entiy ID (bundle symbolic name, etc.) */ + public final String id; + + /** What happened to the entity (STARTED, etc) */ + public final String action; + + /** Event timestamp (clock time) */ + public final long timestamp; + } + + /** When the service started */ + long getStartupTimestamp(); + + /** Timestamp of latest event (used to compute graph scales) */ + long getLastTimestamp(); + + /** Clear the list of events and reset startup time */ + void clear(); + + /** True if recording is enabled */ + boolean isActive(); + + /** Return an Iterator on our recorded events */ + Iterator<RecordedEvent> getEvents(); +} Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/OsgiEventsRecorder.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java?rev=815351&view=auto ============================================================================== --- sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java (added) +++ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java Tue Sep 15 14:52:13 2009 @@ -0,0 +1,33 @@ +/* + * 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.osgi.event.recorder.impl; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + public void start(BundleContext ctx) throws Exception { + FelixConsolePlugin.initPlugin(ctx); + } + + public void stop(BundleContext ctx) throws Exception { + FelixConsolePlugin.destroyPlugin(); + } +} Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/Activator.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java?rev=815351&view=auto ============================================================================== --- sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java (added) +++ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java Tue Sep 15 14:52:13 2009 @@ -0,0 +1,202 @@ +/* + * 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.osgi.event.recorder.impl; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.felix.webconsole.AbstractWebConsolePlugin; +import org.apache.felix.webconsole.WebConsoleConstants; +import org.apache.sling.osgi.event.recorder.OsgiEventsRecorder; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +/** Display recorded events as a simple graph on the Felix web console */ +...@suppresswarnings("serial") +public class FelixConsolePlugin extends AbstractWebConsolePlugin { + + public static final String LABEL = "OSGiEventsRecorder"; + public static final String TITLE = "OSGi Events Recorder"; + + private static FelixConsolePlugin instance; + private ServiceRegistration serviceRegistration; + private ServiceTracker osgiEventsRecorderTracker; + private String lastClearString = "" + System.currentTimeMillis(); + + private static final String S = "overflow:visible; white-space:nowrap; text-align:right; padding: 2px; margin: 2px; "; + private static Map<String, String> styles = new HashMap<String, String>(); + static { + styles.put(OsgiEventsRecorderImpl.ENTITY_BUNDLE, S + "background-color:#FFCACD; "); + styles.put(OsgiEventsRecorderImpl.ENTITY_FRAMEWORK, S + "background-color:#DCDCDC; "); + styles.put(OsgiEventsRecorderImpl.ENTITY_CONFIG, S + "background-color:#FFD700; "); + styles.put(OsgiEventsRecorderImpl.ENTITY_SERVICE, S + "background-color:#ADFF2F; "); + } + + public void activate(BundleContext ctx) { + super.activate(ctx); + + Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put(Constants.SERVICE_DESCRIPTION, "Web Console Plugin to display/profile OSGi events"); + props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); + props.put(Constants.SERVICE_PID, getClass().getName()); + props.put(WebConsoleConstants.PLUGIN_LABEL, LABEL); + + serviceRegistration = ctx.registerService(WebConsoleConstants.SERVICE_NAME, this, props); + osgiEventsRecorderTracker = new ServiceTracker(ctx, OsgiEventsRecorder.class.getName(), null); + osgiEventsRecorderTracker.open(); + } + + public void deactivate() { + if(serviceRegistration != null) { + serviceRegistration.unregister(); + serviceRegistration = null; + } + + if(osgiEventsRecorderTracker != null) { + osgiEventsRecorderTracker.close(); + } + super.deactivate(); + } + + public static void initPlugin(BundleContext context) { + if (instance == null) { + FelixConsolePlugin tmp = new FelixConsolePlugin(); + tmp.activate(context); + instance = tmp; + } + } + + public static void destroyPlugin() { + if (instance != null) { + try { + instance.deactivate(); + } finally { + instance = null; + } + } + } + + @Override + public String getLabel() { + return LABEL; + } + + @Override + public String getTitle() { + return TITLE; + } + + @Override + protected void renderContent(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + if(osgiEventsRecorderTracker == null) { + throw new ServletException("ServiceTracker not found"); + } + + final OsgiEventsRecorder rec = (OsgiEventsRecorder)osgiEventsRecorderTracker.getService(); + if(rec == null) { + throw new ServletException("OsgiEventsRecorder not found"); + } + + // Use unique numbers to clear, to avoid clearing again if the browser is refreshed + final String clear = request.getParameter("clear"); + if(clear != null && !clear.equals(lastClearString)) { + lastClearString = clear; + rec.clear(); + } + + final Iterator<OsgiEventsRecorder.RecordedEvent> it = rec.getEvents(); + final PrintWriter w = response.getWriter(); + + w.println("<div class='fullwidth'><div class='statusline'>"); + w.println("This plugin displays a timeline of OSGi events."); + w.println("<br/>"); + w.println("Times in brackets are milliseconds since the first event was received."); + w.println("<br/>"); + w.println("To profile system startup, install the recorder bundle with start level 1 to have it start early."); + w.println("</div></div>"); + + // Compute scale: startTime is 0, lastTimestamp is 100% + final long startTime = rec.getStartupTimestamp(); + final long endTime = rec.getLastTimestamp(); + final float scale = 100.0f / (endTime - startTime); + + final String clearURL = "./" + LABEL + "?clear=" + System.currentTimeMillis(); + w.println("<h3>OSGi Events Timeline (<a href='" + clearURL + "'>Clear</a>)</h3>"); + w.println("<div class='fullwidth'>"); + if(rec.isActive()) { + int count = 0; + while(it.hasNext()) { + count++; + renderEvent(w, it.next(), startTime, scale); + } + w.println("</div>"); + w.println("<div class='fullwidth'><div class='statusline'>"); + w.println(count); + w.println(" OSGi events displayed."); + w.println("</div>"); + } else { + w.println("<div class='fullwidth'><div class='statusline'>"); + w.println("OSGi Event Recorder is currently <b>disabled</b> by configuration."); + w.println("</div>"); + } + } + + private void renderEvent(PrintWriter w, OsgiEventsRecorder.RecordedEvent e, long start, float scale) { + final long msec = e.timestamp - start; + + // Compute color bar size and make sure the bar is visible + int percent = (int)((msec) * scale); + percent = Math.max(percent, 2); + + // Get style according to entity + String style = styles.get(e.entity); + if(style == null) { + style = ""; + } + + w.print("<div style='"); + w.print(style); + w.print("width:"); + w.print(percent); + w.print("%'>"); + if(e.id != null) { + w.print("<b>"); + w.print(e.id); + w.print("</b> "); + } + w.print(e.entity); + w.print(" "); + w.print(e.action); + w.print(" <b>("); + w.print(msec); + w.println(")</b></div>"); + } +} Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/FelixConsolePlugin.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java?rev=815351&view=auto ============================================================================== --- sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java (added) +++ sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java Tue Sep 15 14:52:13 2009 @@ -0,0 +1,253 @@ +/* + * 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.osgi.event.recorder.impl; + +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.apache.sling.osgi.event.recorder.OsgiEventsRecorder; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleListener; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cm.ConfigurationEvent; +import org.osgi.service.cm.ConfigurationListener; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Events recorder service implementation. + * + * @scr.component immediate="true" + * @scr.property name="service.vendor" value="The Apache Software Foundation" + * @scr.property name="service.description" value="OSGi events recorder" + * @scr.service + */ +public class OsgiEventsRecorderImpl + implements OsgiEventsRecorder, BundleListener, FrameworkListener, ServiceListener, ConfigurationListener { + + private final Logger log = LoggerFactory.getLogger(getClass()); + private ServiceRegistration configReg; + private BundleContext ctx; + private long startupTime; + private long lastTimestamp; + private List<RecordedEvent> events; + + static final String ENTITY_FRAMEWORK = "Framework"; + static final String ENTITY_BUNDLE = "Bundle"; + static final String ENTITY_CONFIG = "Config"; + static final String ENTITY_SERVICE = "Service"; + + /** @scr.property type="Integer" valueRef="DEFAULT_MAX_EVENTS_RECORDED" */ + public static final String PROP_MAX_EVENTS_RECORDED = "max.events.recorded"; + public static final int DEFAULT_MAX_EVENTS_RECORDED = 5000; + private int maxEvents; + + /** @scr.property type="Boolean" valueRef="DEFAULT_ACTIVE" */ + public static final String PROP_ACTIVE = "recorder.active"; + public static final boolean DEFAULT_ACTIVE = false; + private boolean active; + + public void activate(ComponentContext cc) { + Dictionary<?, ?> cfg = cc.getProperties(); + Object o = cfg.get(PROP_ACTIVE); + if(o != null) { + active = ((Boolean)o).booleanValue(); + } else { + active = DEFAULT_ACTIVE; + } + o = cfg.get(PROP_MAX_EVENTS_RECORDED); + if(o != null) { + maxEvents = ((Integer)o).intValue(); + } else { + maxEvents = DEFAULT_MAX_EVENTS_RECORDED; + } + + if(!active) { + log.info("Recorder deactivated by configuration"); + return; + } + log.info("Activating recorder, a maximum of {} events will be recorded", maxEvents); + + startupTime = System.currentTimeMillis(); + ctx = cc.getBundleContext(); + ctx.addBundleListener(this); + ctx.addFrameworkListener(this); + ctx.addServiceListener(this); + configReg = ctx.registerService(ConfigurationListener.class.getName(), + this, null); + + events = new LinkedList<RecordedEvent>(); + + log.warn("The OSGi event recorder consumes resources when recording events, turn it off if not using it"); + } + + public void deactivate(ComponentContext cc) { + configReg.unregister(); + ctx.removeServiceListener(this); + ctx.removeFrameworkListener(this); + ctx.removeBundleListener(this); + events = null; + } + + public Iterator<RecordedEvent> getEvents() { + if(events == null) { + return new LinkedList<RecordedEvent>().iterator(); + } + return events.iterator(); + } + + public void clear() { + if(events != null) { + synchronized (events) { + events.clear(); + startupTime = System.currentTimeMillis(); + } + } + } + + public long getStartupTimestamp() { + return startupTime; + } + + public long getLastTimestamp() { + return lastTimestamp; + } + + public boolean isActive() { + return active; + } + + private void recordEvent(String entity, String id, String action) { + final RecordedEvent r = new RecordedEvent(entity, id, action); + synchronized (events) { + while(events.size() > maxEvents) { + events.remove(0); + } + // First event resets start time + if(events.size() == 0) { + startupTime = System.currentTimeMillis(); + } + events.add(r); + lastTimestamp = r.timestamp; + } + } + + public void frameworkEvent(FrameworkEvent e) { + if(events != null) { + recordEvent(ENTITY_FRAMEWORK, null, getFrameworkEventType(e.getType())); + } + } + + public void bundleChanged(BundleEvent e) { + if(events != null) { + recordEvent(ENTITY_BUNDLE, e.getBundle().getSymbolicName(), getBundleEventType(e.getType())); + } + } + + public void configurationEvent(ConfigurationEvent e) { + if(events != null) { + recordEvent(ENTITY_CONFIG, e.getPid(), "CHANGED"); + } + } + + public void serviceChanged(ServiceEvent e) { + if(events != null) { + final ServiceReference ref = e.getServiceReference(); + final StringBuilder id = new StringBuilder(); + final Object pid = ref.getProperty("service.pid"); + final Object sid = ref.getProperty("service.id"); + if(pid != null) { + id.append(pid.toString()); + } else { + final Object o = ref.getProperty("objectClass"); + if(o instanceof String []) { + id.append(Arrays.asList((String[])o).toString()); + } else { + id.append(o.toString()); + } + id.append(" ("); + id.append(ref.getBundle().getSymbolicName()); + id.append(" bundle)"); + } + if(sid != null) { + id.append(" (id="); + id.append(sid); + id.append(")"); + } + recordEvent(ENTITY_SERVICE, id.toString(), getServiceEventType(e.getType())); + } + } + + private static String getBundleEventType(int t) { + if(t == BundleEvent.STARTED) { + return "STARTED"; + } else if(t == BundleEvent.RESOLVED) { + return "RESOLVED"; + } else if(t == BundleEvent.STOPPED) { + return "STOPPED"; + } else if(t == BundleEvent.UNRESOLVED) { + return "UNRESOLVED"; + } else if(t == BundleEvent.UNINSTALLED) { + return "UNINSTALLED"; + } else if(t == BundleEvent.INSTALLED) { + return "INSTALLED"; + } else if(t == BundleEvent.UPDATED) { + return "UPDATED"; + } + return String.valueOf(t); + } + + private static String getFrameworkEventType(int t) { + if(t == FrameworkEvent.STARTED) { + return "STARTED"; + } else if(t == FrameworkEvent.ERROR) { + return "ERROR"; + } else if(t == FrameworkEvent.INFO) { + return "INFO"; + } else if(t == FrameworkEvent.PACKAGES_REFRESHED) { + return "PACKAGES_REFRESHED"; + } else if(t == FrameworkEvent.STARTLEVEL_CHANGED) { + return "STARTLEVEL_CHANGED"; + } else if(t == FrameworkEvent.WARNING) { + return "WARNING"; + } + return String.valueOf(t); + } + + private static String getServiceEventType(int t) { + if(t == ServiceEvent.MODIFIED) { + return "MODIFIED"; + } else if(t == ServiceEvent.REGISTERED) { + return "REGISTERED"; + } else if(t == ServiceEvent.UNREGISTERING) { + return "UNREGISTERING"; + } + return String.valueOf(t); + } + +} \ No newline at end of file Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/java/org/apache/sling/osgi/event/recorder/impl/OsgiEventsRecorderImpl.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Added: sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=815351&view=auto ============================================================================== --- sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties (added) +++ sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties Tue Sep 15 14:52:13 2009 @@ -0,0 +1,30 @@ +# +# 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. +# + +org.apache.sling.osgi.event.recorder.impl.OsgiEventsRecorderImpl.name = Apache Sling OSGi Events Recorder + +max.events.recorded.name = Max.events recorded +max.events.recorded.description = The maximum number of events \ + to record. If more events are received, the oldest ones are \ + deleted to make room. + +recorder.active.name = Recorder active? +recorder.active.description = Enable/disable events recording + + \ No newline at end of file Propchange: sling/trunk/contrib/extensions/osgi-profiler/src/main/resources/OSGI-INF/metatype/metatype.properties ------------------------------------------------------------------------------ svn:eol-style = native