/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.monitor.client; import java.util.Map; import org.osgi.framework.Bundle; import org.osgi.service.log.LogEntry; import org.osgi.service.log.LogListener; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.ContributorFactoryOSGi; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.log.ExtendedLogEntry; import org.eclipse.equinox.log.ExtendedLogReaderService; import org.eclipse.riena.core.logging.SynchronousLogListenerAdapter; import org.eclipse.riena.core.util.Literal; import org.eclipse.riena.core.util.PropertiesUtils; import org.eclipse.riena.core.wire.InjectService; import org.eclipse.riena.internal.monitor.client.Activator; import org.eclipse.riena.monitor.common.LogEntryTransferObject; /** * Collects logs that are delivered by the * {@code org.osgi.service.log.LogListener}. * <p> * Example extensions: * * <pre> * <extension point="org.eclipse.riena.monitor.client.collectors"> * <collector * category="LogCollector" * class="org.eclipse.riena.monitor.client.LogServiceCollector: collectRange=1,2; triggerRange=1,2; async=false" * maxItems="50"> * </collector> * <collector * category="CustomCollector" * class="org.eclipse.riena.monitor.client.LogServiceCollector: collectRange=-2..0; triggerRange=-2" * maxItems="250"> * </collector> * </extension> * </pre> * * In the example above there are two parameters collectRange and triggerRange. * Both parameters are of type range. A range defines a set of integers (see * org.eclipse.riena.monitor.client.Range), e.g. * <ul> * <li>1..3 - is a interval containing 1, 2 and 3</li> * <li>1,2 - are simply the values 1 and 2</li> * <li>1..3, 5,7 - is a interval containing 1, 2, 3, 5 and 7</li> * </ul> * These integers are the log levels defined by org.osgi.service.log.LogService. * So, for the above defined LogServiceCollector this means collect * (collectRange) all logs that are INFO (3), WARNING (2) or ERROR (1) and * trigger transmission (triggerRange) on WARNING (2) or ERROR (1). <br> * The optional parameter async allows to attach the LogServiceCollector either * synchronously or asynchronously. The default is asynchronously. The advantage * of attaching synchronously is that the LogServiceCollector can access thread * information. * <p> * The collectRange is quiet limited. For a more fine grained control of what * should be collected, a filter class may by specified: * * <pre> * <extension point="org.eclipse.riena.monitor.client.collectors"> * <collector * category="LogCollector" * class="org.eclipse.riena.monitor.client.LogServiceCollector: triggerRange=1,2; async=false; filterClass=org.eclipse.riena.example.client.monitor.LogServiceCollectorFilter" * maxItems="50"> * </collector> * </extension> * </pre> * * The filter class has to implement the interface * <code>ILogServiceCollectorFilter</code>. With this the collectRange is no * longer necessary but can still be used. If used its filtering is applied * before the filter class. * <p> * See also <a href= * "http://wiki.eclipse.org/Riena/Getting_Started_with_Client_Monitoring#LogServiceCollector" * >Riena Wiki LogServiceCollector</a> */ public class LogServiceCollector extends AbstractCollector implements IExecutableExtension { private Range collectRange; private Range triggerRange; private ILogServiceCollectorFilter filter; private boolean async; private ExtendedLogReaderService extendedLogReaderService; private LogListener logListener; private static final String TRIGGER_RANGE = "triggerRange"; //$NON-NLS-1$ private static final String COLLECT_RANGE = "collectRange"; //$NON-NLS-1$ private static final String FILTER_CLASS = "filterClass"; //$NON-NLS-1$ private static final String ASYNC_EXEC = "async"; //$NON-NLS-1$ private static final String ASYNC_EXEC_DEFAULT = Boolean.TRUE.toString(); public void setInitializationData(final IConfigurationElement config, final String propertyName, final Object data) throws CoreException { Map<String, String> properties = null; try { properties = PropertiesUtils.asMap(data, Literal.map(ASYNC_EXEC, ASYNC_EXEC_DEFAULT), TRIGGER_RANGE); final String collectRangeString = properties.get(COLLECT_RANGE); collectRange = new Range(collectRangeString != null ? collectRangeString : Range.ALL); triggerRange = new Range(properties.get(TRIGGER_RANGE)); filter = newFilter(config, properties.get(FILTER_CLASS)); async = Boolean.parseBoolean(properties.get(ASYNC_EXEC)); logListener = newLogListener(); } catch (final IllegalArgumentException e) { throw configurationException("Bad configuration.", e); //$NON-NLS-1$ } } private ILogServiceCollectorFilter newFilter(final IConfigurationElement configurationElement, final String filterClassName) { if (filterClassName == null) { return null; } final Bundle bundle = ContributorFactoryOSGi.resolve(configurationElement.getContributor()); Assert.isLegal(bundle != null, "Could not get bundle for filter class " + filterClassName); //$NON-NLS-1$ try { return (ILogServiceCollectorFilter) bundle.loadClass(filterClassName).newInstance(); } catch (final Throwable t) { throw new IllegalArgumentException("Could not create filter instance for class " + filterClassName, t); //$NON-NLS-1$ } } @Override protected void doStart() { if (extendedLogReaderService == null) { return; } extendedLogReaderService.addLogListener(logListener); } @Override protected void doStop() { if (extendedLogReaderService == null) { return; } extendedLogReaderService.removeLogListener(logListener); } @InjectService(useRanking = true) public void bind(final ExtendedLogReaderService extendedLogReaderService) { this.extendedLogReaderService = extendedLogReaderService; } public void unbind(final ExtendedLogReaderService extendedLogReaderService) { extendedLogReaderService.removeLogListener(logListener); this.extendedLogReaderService = null; } private LogListener newLogListener() { final LogListener listener = new LogListener() { public void logged(final LogEntry entry) { if (!collectRange.matches(entry.getLevel())) { return; } if (filter != null && !filter.isCollectible((ExtendedLogEntry) entry)) { return; } collect(new LogEntryTransferObject((ExtendedLogEntry) entry)); if (triggerRange.matches(entry.getLevel())) { triggerTransfer(); } } }; return async ? listener : new SynchronousLogListenerAdapter(listener); } private CoreException configurationException(final String message, final Exception e) { return new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, message, e)); } }