/******************************************************************************* * Copyright (c) 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Jan S. Rellermeyer, IBM Research - initial API and implementation *******************************************************************************/ package org.eclipse.concierge.service.log; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Vector; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.log.LogEntry; import org.osgi.service.log.LogListener; import org.osgi.service.log.LogReaderService; import org.osgi.service.log.LogService; /** * A lightweight log service implementation. Since this is part of the * framework, the framework itself can be configured to use this log for debug * messages. This makes it easier to debug bundles on embedded and headless * devices. * * @author Jan S. Rellermeyer */ public final class LogServiceImpl implements LogReaderService { /** * the log buffer. Works like a ring buffer. The size can be configured by a * property. */ private final Vector<LogEntryImpl> logBuffer; /** * the list of subscribed listeners. */ private final List<LogListener> logListeners = new ArrayList<LogListener>( 0); /** * the size. */ private final int LOG_BUFFER_SIZE; /** * the log level. */ private final int LOG_LEVEL; /** * do not log to screen ? */ private final boolean QUIET; /** * the constants for the log levels. */ protected static final String[] LEVELS = { "NULL", "ERROR", "WARNING", "INFO", "DEBUG" }; protected static final String getLevelString(final int level) { if (level < 0 || level > 4) { return Integer.toString(level); } return LEVELS[level]; } public final ServiceFactory<LogService> factory = new LogServiceFactory(); public LogServiceImpl(final int buffersize, final int loglevel, final boolean quiet) { LOG_BUFFER_SIZE = buffersize; if (loglevel < 0) { LOG_LEVEL = 0; } else if (loglevel > 4) { LOG_LEVEL = 4; } else { LOG_LEVEL = loglevel; } QUIET = quiet; logBuffer = new Vector<LogEntryImpl>(LOG_BUFFER_SIZE); if (!QUIET) { System.out.println( "Logger initialized, loglevel is " + LEVELS[LOG_LEVEL]); } } /** * log an entry. * * @param entry * the entry. */ protected void log(final int level, final String message, final Throwable throwable, final ServiceReference<?> sref, final Bundle bundle) { if (level <= LOG_LEVEL) { final LogEntryImpl entry = LogEntryImpl.getEntry(level, message, throwable, sref, bundle); logBuffer.add(entry); if (logBuffer.size() > LOG_BUFFER_SIZE) { LogEntryImpl.releaseEntry(logBuffer.remove(0)); } for (final Iterator<LogListener> listeners = logListeners .iterator(); listeners.hasNext();) { listeners.next().logged(entry); } if (!QUIET) { System.out.println(entry); } } } /** * Add a log listener. * * @param listener * the new listener. * * @see org.osgi.service.log.LogReaderService#addLogListener(org.osgi.service.log.LogListener) */ public void addLogListener(final LogListener listener) { logListeners.add(listener); } /** * remove a log listener. * * @param listener * the listener. * * @see org.osgi.service.log.LogReaderService#removeLogListener(org.osgi.service.log.LogListener) */ public void removeLogListener(final LogListener listener) { logListeners.remove(listener); } /** * get the buffered log messages. * * @return an <code>Enumeration</code> over the buffered log messages. * * @see org.osgi.service.log.LogReaderService#getLog() */ public Enumeration<? extends LogEntry> getLog() { return logBuffer.elements(); } /** * The service factory producing per-bundle instances of the log service * facet. * * @author Jan S. Rellermeyer * */ final class LogServiceFactory implements ServiceFactory<LogService> { public LogService getService(final Bundle bundle, final ServiceRegistration<LogService> registration) { return new LogServiceInstance(bundle); } public void ungetService(final Bundle bundle, final ServiceRegistration<LogService> registration, final LogService service) { // nop } } /** * A bundle-specific instance of the log service facet. * * @author Jan S. Rellermeyer * */ @SuppressWarnings("rawtypes") private final class LogServiceInstance implements LogService { private final Bundle bundle; protected LogServiceInstance(final Bundle bundle) { this.bundle = bundle; } /** * Log a message. * * @param level * the level. * @param message * the message. * @see org.osgi.service.log.LogService#log(int, java.lang.String) */ public void log(final int level, final String message) { LogServiceImpl.this.log(level, message, null, null, bundle); } /** * Log a message. * * @param level * the level. * @param message * the message. * @param exception * an exception. * * @see org.osgi.service.log.LogService#log(int, java.lang.String, * java.lang.Throwable) */ public void log(final int level, final String message, final Throwable exception) { LogServiceImpl.this.log(level, message, exception, null, bundle); } /** * Log a message. * * @param sr * the service reference. * @param level * the level. * @param message * the message. * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, * int, java.lang.String) */ public void log(final ServiceReference sr, final int level, final String message) { LogServiceImpl.this.log(level, message, null, sr, bundle); } /** * Log a message. * * @param sr * the service reference. * @param level * the level. * @param message * the message. * * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, * int, java.lang.String, java.lang.Throwable) */ public void log(final ServiceReference sr, final int level, final String message, final Throwable exception) { LogServiceImpl.this.log(level, message, exception, sr, bundle); } } /** * A log entry. * * @author Jan S. Rellermeyer * */ final static class LogEntryImpl implements LogEntry { private int level; private String message; private ServiceReference<?> sref; private Throwable exception; private Bundle bundle; private long time; private final static List<LogEntryImpl> entryRecyclingList = new ArrayList<LogEntryImpl>( 5); private final static int THRESHOLD = 5; protected static LogEntryImpl getEntry(final int level, final String message, final Throwable throwable, final ServiceReference<?> sref, final Bundle bundle) { synchronized (entryRecyclingList) { final LogEntryImpl entry = entryRecyclingList.isEmpty() ? new LogEntryImpl() : (LogEntryImpl) entryRecyclingList.remove(0); entry.log(level, message, throwable, sref, bundle); return entry; } } protected static void releaseEntry(final LogEntryImpl entry) { synchronized (entryRecyclingList) { if (entryRecyclingList.size() < THRESHOLD) { entry.log(0, null, null, null, null); entryRecyclingList.add(entry); } } } /** * */ private LogEntryImpl() { } /** * @param sref * @param level * @param message * @param exception */ private void log(final int level, final String message, final Throwable exception, final ServiceReference<?> sref, final Bundle bundle) { this.level = level; this.message = message; this.exception = exception; this.sref = sref; this.bundle = bundle; this.time = System.currentTimeMillis(); } /** * @see org.osgi.service.log.LogEntry#getBundle() */ public Bundle getBundle() { return bundle; } /** * @see org.osgi.service.log.LogEntry#getServiceReference() */ public ServiceReference<?> getServiceReference() { return sref; } /** * @see org.osgi.service.log.LogEntry#getLevel() */ public int getLevel() { return level; } /** * @see org.osgi.service.log.LogEntry#getMessage() */ public String getMessage() { return message; } /** * @see org.osgi.service.log.LogEntry#getException() */ public Throwable getException() { return exception; } /** * @see org.osgi.service.log.LogEntry#getTime() */ public long getTime() { return time; } /** * * @see java.lang.Object#toString() */ public String toString() { final StringBuffer buffer = new StringBuffer("[") .append(new Date(time)).append("] [") .append(getLevelString(level)).append("] "); if (sref != null) { buffer.append("Bundle: "); buffer.append(sref.getBundle()); buffer.append(" "); buffer.append("ServiceReference: "); buffer.append(sref); buffer.append(" "); } buffer.append(message); if (exception != null) { buffer.append("\n\tException: "); buffer.append(exception.getMessage()); } return buffer.toString(); } } }