diff options
author | Thomas Watson | 2016-03-04 14:30:44 +0000 |
---|---|---|
committer | Thomas Watson | 2017-06-16 12:38:08 +0000 |
commit | c7fae461022cd049802023f56bb518b8a81ad02a (patch) | |
tree | 87276855dc7fc1b82f10c56d1a24af4fd25df758 /bundles/org.eclipse.osgi | |
parent | f31b2c1056822bdc2e77b22f558a087943f7a22d (diff) | |
download | rt.equinox.framework-c7fae461022cd049802023f56bb518b8a81ad02a.tar.gz rt.equinox.framework-c7fae461022cd049802023f56bb518b8a81ad02a.tar.xz rt.equinox.framework-c7fae461022cd049802023f56bb518b8a81ad02a.zip |
Bug 486950 - [osgi R7] log service is being updated
- Add support for LoggerAdmin
Change-Id: Iecd2675cfb7ddf7f7a10fbaa8a7f35e4f59d5615
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
Diffstat (limited to 'bundles/org.eclipse.osgi')
26 files changed, 909 insertions, 115 deletions
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF index 5ec09bbff..65ff2ba2e 100644 --- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF @@ -68,6 +68,7 @@ Export-Package: org.eclipse.core.runtime.adaptor;x-friends:="org.eclipse.core.ru org.osgi.resource.dto;version="1.0";uses:="org.osgi.dto", org.osgi.service.condpermadmin;version="1.1.1";uses:="org.osgi.framework", org.osgi.service.log;version="1.3";uses:="org.osgi.framework", + org.osgi.service.log.admin;version="1.0", org.osgi.service.packageadmin;version="1.2";uses:="org.osgi.framework", org.osgi.service.permissionadmin;version="1.2", org.osgi.service.resolver;version="1.0.1";uses:="org.osgi.resource", @@ -80,6 +81,7 @@ Export-Service: org.osgi.service.packageadmin.PackageAdmin, org.eclipse.osgi.service.debug.DebugOptions Provide-Capability: osgi.service; objectClass:List<String>="org.osgi.service.log.LogReaderService, org.eclipse.equinox.log.ExtendedLogReaderService", osgi.service; objectClass:List<String>="org.osgi.service.log.LogService, org.eclipse.equinox.log.ExtendedLogService", + osgi.service; objectClass:List<String>="org.osgi.service.log.admin.LoggerAdmin", osgi.service; objectClass:List<String>="org.eclipse.osgi.framework.log.FrameworkLog", osgi.service; objectClass:List<String>="org.eclipse.osgi.service.datalocation.Location"; type="osgi.user.area", osgi.service; objectClass:List<String>="org.eclipse.osgi.service.datalocation.Location"; type="osgi.instance.area", diff --git a/bundles/org.eclipse.osgi/build.properties b/bundles/org.eclipse.osgi/build.properties index 6cb7c3dcf..9ddb3ad0b 100644 --- a/bundles/org.eclipse.osgi/build.properties +++ b/bundles/org.eclipse.osgi/build.properties @@ -32,5 +32,6 @@ output.. = bin/ # customBuildCallbacks=customBuildCallbacks.xml javacWarnings..=-raw,unchecked,hiding,unused,warningToken -jars.extra.classpath = osgi/osgi.annotation.jar +jars.extra.classpath = osgi/osgi.annotation.jar,\ + osgi/function.interface.jar jre.compilation.profile = JavaSE-1.7 diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/SecureAction.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/SecureAction.java index bb12a4c4a..795ab9e84 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/SecureAction.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/framework/util/SecureAction.java @@ -493,4 +493,15 @@ public class SecureAction { } }, controlContext); } + + public String getLocation(final Bundle bundle) { + if (System.getSecurityManager() == null) { + return bundle.getLocation(); + } + return AccessController.doPrivileged(new PrivilegedAction<String>() { + public String run() { + return bundle.getLocation(); + } + }, controlContext); + } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/Arguments.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/Arguments.java index 187b7b2a5..9eeb9883b 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/Arguments.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/Arguments.java @@ -1,3 +1,10 @@ +/******************************************************************************* + * Copyright (c) 2016 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 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ package org.eclipse.osgi.internal.log; import org.osgi.framework.ServiceReference; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogServices.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogServices.java index de64ca670..985356d35 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogServices.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogServices.java @@ -84,6 +84,9 @@ public class EquinoxLogServices { logServiceManager = new LogServiceManager(logHistoryMax, logWriter, perfWriter); eclipseLogFactory = new EquinoxLogFactory(logWriter, logServiceManager); rootFrameworkLog = eclipseLogFactory.createFrameworkLog(null, logWriter); + + logWriter.setLoggerAdmin(logServiceManager.getLoggerAdmin()); + perfWriter.setLoggerAdmin(logServiceManager.getLoggerAdmin()); } private ServiceRegistration<?> frameworkLogReg; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogWriter.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogWriter.java index 1520ab158..c07307a3e 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogWriter.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/EquinoxLogWriter.java @@ -12,18 +12,16 @@ package org.eclipse.osgi.internal.log; import java.io.*; import java.lang.reflect.InvocationTargetException; -import java.security.AccessController; -import java.util.Calendar; -import java.util.Date; +import java.util.*; import org.eclipse.core.runtime.adaptor.EclipseStarter; import org.eclipse.equinox.log.*; import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.framework.util.SecureAction; import org.eclipse.osgi.internal.framework.EquinoxConfiguration; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; -import org.osgi.service.log.LogEntry; -import org.osgi.service.log.LogService; +import org.osgi.service.log.*; +import org.osgi.service.log.admin.LoggerAdmin; +import org.osgi.service.log.admin.LoggerContext; class EquinoxLogWriter implements SynchronousLogListener, LogFilter { private static final String PASSWORD = "-password"; //$NON-NLS-1$ @@ -67,8 +65,6 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { /** The system property used to specify command line args should be omitted from the log */ private static final String PROP_LOG_INCLUDE_COMMAND_LINE = "eclipse.log.include.commandline"; //$NON-NLS-1$ - private static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction()); - /** Indicates if the console messages should be printed to the console (System.out) */ private boolean consoleLog = false; /** Indicates if the next log message is part of a new session */ @@ -94,6 +90,8 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { private int logLevel = FrameworkLogEntry.OK; private boolean includeCommandLine = true; + private LoggerAdmin loggerAdmin = null; + /** * Constructs an EclipseLog which uses the specified File to log messages to * @param outFile a file to log messages to @@ -244,7 +242,7 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { if (writer == null) { if (outFile != null) { try { - writer = logForStream(secureAction.getFileOutputStream(outFile, true)); + writer = logForStream(ExtendedLogServiceFactory.secureAction.getFileOutputStream(outFile, true)); } catch (IOException e) { writer = logForErrorStream(); } @@ -321,6 +319,11 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { environmentInfo.setConfiguration(EclipseStarter.PROP_LOGFILE, newFile == null ? "" : newFile.getAbsolutePath()); //$NON-NLS-1$ } + synchronized void setLoggerAdmin(LoggerAdmin loggerAdmin) { + this.loggerAdmin = loggerAdmin; + applyLogLevel(); + } + public synchronized File getFile() { return outFile; } @@ -350,7 +353,7 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { Reader fileIn = null; try { openFile(); - fileIn = new InputStreamReader(secureAction.getFileInputStream(oldOutFile), "UTF-8"); //$NON-NLS-1$ + fileIn = new InputStreamReader(ExtendedLogServiceFactory.secureAction.getFileInputStream(oldOutFile), "UTF-8"); //$NON-NLS-1$ copyReader(fileIn, this.writer); } catch (IOException e) { copyFailed = true; @@ -583,7 +586,7 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { boolean isBackupOK = true; if (outFile != null) { - if ((secureAction.length(outFile) >> 10) > maxLogSize) { // Use KB as file size unit. + if ((ExtendedLogServiceFactory.secureAction.length(outFile) >> 10) > maxLogSize) { // Use KB as file size unit. String logFilename = outFile.getAbsolutePath(); // Delete old backup file that will be replaced. @@ -669,6 +672,34 @@ class EquinoxLogWriter implements SynchronousLogListener, LogFilter { } includeCommandLine = "true".equals(environmentInfo.getConfiguration(PROP_LOG_INCLUDE_COMMAND_LINE, "true")); //$NON-NLS-1$//$NON-NLS-2$ + applyLogLevel(); + } + + void applyLogLevel() { + if (loggerAdmin == null) { + return; + } + LoggerContext rootContext = loggerAdmin.getLoggerContext(null); + Map<String, LogLevel> rootLevels = rootContext.getLogLevels(); + rootLevels.put(loggerName, getLogLevel()); + rootContext.setLogLevels(rootLevels); + } + + private LogLevel getLogLevel() { + if (logLevel == 0) { + return LogLevel.TRACE; + } + if ((logLevel & FrameworkLogEntry.INFO) != 0) { + return LogLevel.INFO; + } + if ((logLevel & FrameworkLogEntry.WARNING) != 0) { + return LogLevel.WARN; + } + if ((logLevel & FrameworkLogEntry.ERROR) != 0) { + return LogLevel.ERROR; + } + // not sure what to do here; it seems it would be an error + return LogLevel.AUDIT; } /** diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogEntryImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogEntryImpl.java index ee492f5f6..335acf19a 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogEntryImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogEntryImpl.java @@ -24,6 +24,7 @@ public class ExtendedLogEntryImpl implements ExtendedLogEntry, LogEntry { private final String loggerName; private final Bundle bundle; private final int level; + private final LogLevel logLevelEnum; private final String message; private final Throwable throwable; private final Object contextObject; @@ -54,11 +55,12 @@ public class ExtendedLogEntryImpl implements ExtendedLogEntry, LogEntry { return threadId.longValue(); } - public ExtendedLogEntryImpl(Bundle bundle, String loggerName, Object contextObject, int level, String message, Throwable throwable) { + public ExtendedLogEntryImpl(Bundle bundle, String loggerName, Object contextObject, LogLevel logLevelEnum, int level, String message, Throwable throwable) { this.time = System.currentTimeMillis(); this.loggerName = loggerName; this.bundle = bundle; this.level = level; + this.logLevelEnum = logLevelEnum; this.message = message; this.throwable = throwable; this.contextObject = contextObject; @@ -71,6 +73,7 @@ public class ExtendedLogEntryImpl implements ExtendedLogEntry, LogEntry { this.sequenceNumber = nextSequenceNumber++; } + // TODO need to find the calling stack here not just 2 up. stackTraceElement = currentThread.getStackTrace()[2]; } @@ -98,6 +101,7 @@ public class ExtendedLogEntryImpl implements ExtendedLogEntry, LogEntry { return throwable; } + @SuppressWarnings("deprecation") public int getLevel() { return level; } @@ -106,10 +110,9 @@ public class ExtendedLogEntryImpl implements ExtendedLogEntry, LogEntry { return message; } - @SuppressWarnings("rawtypes") - public ServiceReference getServiceReference() { + public ServiceReference<?> getServiceReference() { if (contextObject != null && contextObject instanceof ServiceReference) - return (ServiceReference) contextObject; + return (ServiceReference<?>) contextObject; return null; } @@ -124,7 +127,7 @@ public class ExtendedLogEntryImpl implements ExtendedLogEntry, LogEntry { @Override public LogLevel getLogLevel() { - return LogLevel.values()[getLevel()]; + return logLevelEnum; } @Override diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogReaderServiceFactory.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogReaderServiceFactory.java index e018dd084..b6ef95760 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogReaderServiceFactory.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogReaderServiceFactory.java @@ -15,8 +15,7 @@ import org.eclipse.equinox.log.LogFilter; import org.eclipse.equinox.log.SynchronousLogListener; import org.eclipse.osgi.framework.util.ArrayMap; import org.osgi.framework.*; -import org.osgi.service.log.LogEntry; -import org.osgi.service.log.LogListener; +import org.osgi.service.log.*; public class ExtendedLogReaderServiceFactory implements ServiceFactory<ExtendedLogReaderServiceImpl> { @@ -177,21 +176,21 @@ public class ExtendedLogReaderServiceFactory implements ServiceFactory<ExtendedL return count; } - void log(final Bundle bundle, final String name, final Object context, final int level, final String message, final Throwable exception) { + void log(final Bundle bundle, final String name, final Object context, final LogLevel logLevelEnum, final int level, final String message, final Throwable exception) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { - logPrivileged(bundle, name, context, level, message, exception); + logPrivileged(bundle, name, context, logLevelEnum, level, message, exception); return null; } }); } else { - logPrivileged(bundle, name, context, level, message, exception); + logPrivileged(bundle, name, context, logLevelEnum, level, message, exception); } } - void logPrivileged(Bundle bundle, String name, Object context, int level, String message, Throwable exception) { - LogEntry logEntry = new ExtendedLogEntryImpl(bundle, name, context, level, message, exception); + void logPrivileged(Bundle bundle, String name, Object context, LogLevel logLevelEnum, int level, String message, Throwable exception) { + LogEntry logEntry = new ExtendedLogEntryImpl(bundle, name, context, logLevelEnum, level, message, exception); storeEntry(logEntry); ArrayMap<LogListener, Object[]> listenersCopy; listenersLock.readLock(); diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceFactory.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceFactory.java index ab8bcf025..cf92c747e 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceFactory.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceFactory.java @@ -7,21 +7,30 @@ ******************************************************************************/ package org.eclipse.osgi.internal.log; +import java.security.AccessController; import java.security.Permission; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.eclipse.equinox.log.ExtendedLogService; import org.eclipse.equinox.log.LogPermission; +import org.eclipse.osgi.framework.util.SecureAction; import org.osgi.framework.*; +import org.osgi.service.log.LogLevel; +import org.osgi.service.log.Logger; +import org.osgi.service.log.admin.LoggerAdmin; +import org.osgi.service.log.admin.LoggerContext; public class ExtendedLogServiceFactory implements ServiceFactory<ExtendedLogService>, BundleListener { - + static final SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction()); + final ReentrantReadWriteLock contextsLock = new ReentrantReadWriteLock(); + final LoggerContextTargetMap loggerContextTargetMap = new LoggerContextTargetMap(); private final Permission logPermission = new LogPermission("*", LogPermission.LOG); //$NON-NLS-1$ private final ExtendedLogReaderServiceFactory logReaderServiceFactory; - private final Map<Bundle, ExtendedLogService> logServices = new HashMap<>(); + private final LoggerAdmin loggerAdmin = new EquinoxLoggerAdmin(); public ExtendedLogServiceFactory(ExtendedLogReaderServiceFactory logReaderServiceFactory) { this.logReaderServiceFactory = logReaderServiceFactory; + } public ExtendedLogServiceImpl getService(Bundle bundle, ServiceRegistration<ExtendedLogService> registration) { @@ -39,30 +48,40 @@ public class ExtendedLogServiceFactory implements ServiceFactory<ExtendedLogServ removeLogService(event.getBundle()); } - synchronized ExtendedLogServiceImpl getLogService(Bundle bundle) { - ExtendedLogServiceImpl logService = (ExtendedLogServiceImpl) logServices.get(bundle); - if (logService == null) { - logService = new ExtendedLogServiceImpl(this, bundle); - if (bundle != null && bundle.getState() != Bundle.UNINSTALLED) - logServices.put(bundle, logService); + ExtendedLogServiceImpl getLogService(Bundle bundle) { + contextsLock.writeLock().lock(); + try { + return loggerContextTargetMap.getLogService(bundle, this); + } finally { + contextsLock.writeLock().unlock(); } - return logService; } - synchronized void shutdown() { - logServices.clear(); + void shutdown() { + contextsLock.writeLock().lock(); + try { + loggerContextTargetMap.clear(); + } finally { + contextsLock.writeLock().unlock(); + } + } - synchronized void removeLogService(Bundle bundle) { - logServices.remove(bundle); + void removeLogService(Bundle bundle) { + contextsLock.writeLock().lock(); + try { + loggerContextTargetMap.remove(bundle); + } finally { + contextsLock.writeLock().unlock(); + } } boolean isLoggable(Bundle bundle, String name, int level) { return logReaderServiceFactory.isLoggable(bundle, name, level); } - void log(Bundle bundle, String name, Object context, int level, String message, Throwable exception) { - logReaderServiceFactory.log(bundle, name, context, level, message, exception); + void log(Bundle bundle, String name, Object context, LogLevel logLevelEnum, int level, String message, Throwable exception) { + logReaderServiceFactory.log(bundle, name, context, logLevelEnum, level, message, exception); } void checkLogPermission() throws SecurityException { @@ -70,4 +89,132 @@ public class ExtendedLogServiceFactory implements ServiceFactory<ExtendedLogServ if (sm != null) sm.checkPermission(logPermission); } + + EquinoxLoggerContext createEquinoxLoggerContext(String name) { + return new EquinoxLoggerContext(name); + } + + LoggerAdmin getLoggerAdmin() { + return loggerAdmin; + } + + class EquinoxLoggerAdmin implements LoggerAdmin { + @Override + public LoggerContext getLoggerContext(String name) { + contextsLock.writeLock().lock(); + try { + return loggerContextTargetMap.createLoggerContext(name, ExtendedLogServiceFactory.this); + } finally { + contextsLock.writeLock().unlock(); + } + } + + } + + class EquinoxLoggerContext implements LoggerContext { + final String contextName; + final Map<String, LogLevel> contextLogLevels = new HashMap<>(); + + EquinoxLoggerContext(String name) { + this.contextName = name; + } + + @Override + public String getName() { + return contextName; + } + + @Override + public LogLevel getEffectiveLogLevel(final String name) { + contextsLock.readLock().lock(); + try { + LogLevel level = null; + String lookupName = name; + while ((level = contextLogLevels.get(lookupName)) == null) { + int lastDot = lookupName.lastIndexOf('.'); + if (lastDot >= 0) { + lookupName = lookupName.substring(0, lastDot); + } else { + break; + } + } + if (level == null) { + level = contextLogLevels.get(Logger.ROOT_LOGGER_NAME); + } + if (level == null && contextName != null) { + // non-null context name is a non-root context; + // must not check the root context + EquinoxLoggerContext rootContext = loggerContextTargetMap.getRootLoggerContext(); + if (rootContext != null) { + level = rootContext.getEffectiveLogLevel(name); + } + } + if (level == null) { + level = LogLevel.WARN; + } + return level; + } finally { + contextsLock.readLock().unlock(); + } + } + + @Override + public Map<String, LogLevel> getLogLevels() { + contextsLock.readLock().lock(); + try { + return new HashMap<>(contextLogLevels); + } finally { + contextsLock.readLock().unlock(); + } + } + + @Override + public void setLogLevels(Map<String, LogLevel> logLevels) { + if (!setWithConfigAdmin(logLevels)) { + doSetLogLevels(logLevels); + } + } + + private boolean setWithConfigAdmin(Map<String, LogLevel> logLevels) { + // TODO Auto-generated method stub + return false; + } + + private void doSetLogLevels(Map<String, LogLevel> logLevels) { + boolean readLocked = false; + try { + contextsLock.writeLock().lock(); + try { + contextLogLevels.clear(); + contextLogLevels.putAll(logLevels); + // downgrade to readlock + contextsLock.readLock().lock(); + readLocked = true; + } finally { + contextsLock.writeLock().unlock(); + } + loggerContextTargetMap.applyLogLevels(this); + } finally { + if (readLocked) { + contextsLock.readLock().unlock(); + } + } + } + + @Override + public void clear() { + doSetLogLevels(Collections.<String, LogLevel> emptyMap()); + } + + @Override + public boolean isEmpty() { + contextsLock.readLock().lock(); + try { + return contextLogLevels.isEmpty(); + } finally { + contextsLock.readLock().unlock(); + } + } + } + } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java index ab8dbb213..a2dd568d6 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/ExtendedLogServiceImpl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2012 Cognos Incorporated, IBM Corporation and others + * Copyright (c) 2006, 2016 Cognos Incorporated, 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 which * accompanies this distribution, and is available at @@ -11,37 +11,42 @@ import java.util.HashMap; import java.util.Map; import org.eclipse.equinox.log.ExtendedLogService; import org.eclipse.equinox.log.Logger; +import org.eclipse.osgi.internal.log.ExtendedLogServiceFactory.EquinoxLoggerContext; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; +import org.osgi.service.log.FormatterLogger; +import org.osgi.service.log.admin.LoggerContext; public class ExtendedLogServiceImpl implements ExtendedLogService { private final ExtendedLogServiceFactory factory; private volatile Bundle bundle; - private final Map<Class<? extends org.osgi.service.log.Logger>, Map<String, Logger>> loggerCache = new HashMap<>(); + private final Map<Class<? extends org.osgi.service.log.Logger>, Map<String, LoggerImpl>> loggerCache = new HashMap<>(); public ExtendedLogServiceImpl(ExtendedLogServiceFactory factory, Bundle bundle) { this.factory = factory; this.bundle = bundle; - loggerCache.put(org.osgi.service.log.Logger.class, new HashMap<String, Logger>()); - loggerCache.put(org.osgi.service.log.FormatterLogger.class, new HashMap<String, Logger>()); + loggerCache.put(org.osgi.service.log.Logger.class, new HashMap<String, LoggerImpl>()); + loggerCache.put(org.osgi.service.log.FormatterLogger.class, new HashMap<String, LoggerImpl>()); } + @SuppressWarnings("deprecation") public void log(int level, String message) { log(null, level, message, null); } + @SuppressWarnings("deprecation") public void log(int level, String message, Throwable exception) { log(null, level, message, exception); } - @SuppressWarnings("rawtypes") - public void log(ServiceReference sr, int level, String message) { + @SuppressWarnings("deprecation") + public void log(ServiceReference<?> sr, int level, String message) { log(sr, level, message, null); } - @SuppressWarnings("rawtypes") - public void log(ServiceReference sr, int level, String message, Throwable exception) { + @SuppressWarnings("deprecation") + public void log(ServiceReference<?> sr, int level, String message, Throwable exception) { getLogger((String) null).log(sr, level, message, exception); } @@ -79,13 +84,23 @@ public class ExtendedLogServiceImpl implements ExtendedLogService { return factory.isLoggable(bundle, name, level); } - // package private methods called from Logger - void log(String name, Object context, int level, String message, Throwable exception) { - factory.log(bundle, name, context, level, message, exception); + void setBundle(Bundle bundle) { + factory.contextsLock.writeLock().lock(); + try { + Bundle previous = this.bundle; + this.bundle = bundle; + factory.loggerContextTargetMap.replaceSystemBundleLogService(previous, bundle); + } finally { + factory.contextsLock.writeLock().unlock(); + } } - void setBundle(Bundle bundle) { - this.bundle = bundle; + Bundle getBundle() { + return bundle; + } + + ExtendedLogServiceFactory getFactory() { + return factory; } @Override @@ -94,15 +109,42 @@ public class ExtendedLogServiceImpl implements ExtendedLogService { } @Override - public synchronized <L extends org.osgi.service.log.Logger> L getLogger(String name, Class<L> loggerType) { - Map<String, Logger> loggers = loggerCache.get(loggerType); - if (loggers == null) { - throw new IllegalArgumentException(loggerType.getName()); + public <L extends org.osgi.service.log.Logger> L getLogger(String name, Class<L> loggerType) { + if (name == null) { + name = "LogService"; //$NON-NLS-1$ + } + LoggerImpl logger = null; + Map<String, LoggerImpl> loggers = null; + factory.contextsLock.readLock().lock(); + try { + loggers = loggerCache.get(loggerType); + if (loggers == null) { + throw new IllegalArgumentException(loggerType.getName()); + } + logger = loggers.get(name); + } finally { + factory.contextsLock.readLock().unlock(); } - Logger logger = loggers.get(name); if (logger == null) { - logger = new FormatterLoggerImpl(this, name); - loggers.put(name, logger); + LoggerContext loggerContext = factory.loggerContextTargetMap.getEffectiveLoggerContext(bundle); + if (loggerType == FormatterLogger.class) { + logger = new FormatterLoggerImpl(this, name, loggerContext); + } else if (loggerType == org.osgi.service.log.Logger.class) { + logger = new LoggerImpl(this, name, loggerContext); + } else { + throw new IllegalArgumentException(loggerType.getName()); + } + factory.contextsLock.writeLock().lock(); + try { + LoggerImpl existing = loggers.get(name); + if (existing == null) { + loggers.put(name, logger); + } else { + logger = existing; + } + } finally { + factory.contextsLock.writeLock().unlock(); + } } return loggerType.cast(logger); } @@ -256,4 +298,12 @@ public class ExtendedLogServiceImpl implements ExtendedLogService { public void audit(String format, Object... arguments) { getLogger((String) null).audit(format, arguments); } + + void applyLogLevels(EquinoxLoggerContext effectiveLoggerContext) { + for (Map<String, LoggerImpl> loggers : loggerCache.values()) { + for (LoggerImpl logger : loggers.values()) { + logger.applyLoggerContext(effectiveLoggerContext); + } + } + } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/FormatterLoggerImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/FormatterLoggerImpl.java index d3ab1e478..83cd5eed2 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/FormatterLoggerImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/FormatterLoggerImpl.java @@ -1,17 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2016 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 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ package org.eclipse.osgi.internal.log; import org.osgi.service.log.FormatterLogger; -import org.osgi.service.log.LogLevel; +import org.osgi.service.log.admin.LoggerContext; public class FormatterLoggerImpl extends LoggerImpl implements FormatterLogger { - public FormatterLoggerImpl(ExtendedLogServiceImpl logServiceImpl, String name) { - super(logServiceImpl, name); + public FormatterLoggerImpl(ExtendedLogServiceImpl logServiceImpl, String name, LoggerContext loggerContext) { + super(logServiceImpl, name, loggerContext); } @Override - protected void log(LogLevel level, String format, Object... arguments) { - Arguments processedArguments = new Arguments(arguments); - String message = String.format(format, processedArguments.arguments()); - logServiceImpl.log(name, processedArguments.serviceReference(), level.ordinal(), message, processedArguments.throwable()); + String formatMessage(String format, Arguments processedArguments) { + return String.format(format, processedArguments.arguments()); } + } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LogServiceManager.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LogServiceManager.java index 25a54c758..d14f5ab8e 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LogServiceManager.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LogServiceManager.java @@ -16,14 +16,19 @@ import org.eclipse.equinox.log.*; import org.eclipse.osgi.internal.framework.EquinoxContainer; import org.osgi.framework.*; import org.osgi.service.log.*; +import org.osgi.service.log.admin.LoggerAdmin; public class LogServiceManager implements BundleListener, FrameworkListener, ServiceListener { + private static final String LOGGER_FRAMEWORK_EVENT = "Events.Framework"; //$NON-NLS-1$ + private static final String LOGGER_BUNDLE_EVENT = "Events.Bundle"; //$NON-NLS-1$ + private static final String LOGGER_SERVICE_EVENT = "Events.Service"; //$NON-NLS-1$ - private static final String[] LOGSERVICE_CLASSES = {LogService.class.getName(), ExtendedLogService.class.getName()}; + private static final String[] LOGSERVICE_CLASSES = {LogService.class.getName(), LoggerFactory.class.getName(), ExtendedLogService.class.getName()}; private static final String[] LOGREADERSERVICE_CLASSES = {LogReaderService.class.getName(), ExtendedLogReaderService.class.getName()}; private ServiceRegistration<?> logReaderServiceRegistration; private ServiceRegistration<?> logServiceRegistration; + private ServiceRegistration<LoggerAdmin> loggerAdminRegistration; private final ExtendedLogReaderServiceFactory logReaderServiceFactory; private final ExtendedLogServiceFactory logServiceFactory; private final ExtendedLogServiceImpl systemBundleLog; @@ -51,6 +56,10 @@ public class LogServiceManager implements BundleListener, FrameworkListener, Ser context.addBundleListener(logServiceFactory); logReaderServiceRegistration = context.registerService(LOGREADERSERVICE_CLASSES, logReaderServiceFactory, null); logServiceRegistration = context.registerService(LOGSERVICE_CLASSES, logServiceFactory, null); + Hashtable<String, Object> loggerAdminProps = new Hashtable<String, Object>(); + // TODO the constant for log service id will like be defined + loggerAdminProps.put("osgi.log.service.id", logServiceRegistration.getReference().getProperty(Constants.SERVICE_ID)); //$NON-NLS-1$ + loggerAdminRegistration = context.registerService(LoggerAdmin.class, logServiceFactory.getLoggerAdmin(), loggerAdminProps); eventAdminAdapter = new EventAdminAdapter(context, logReaderServiceFactory); eventAdminAdapter.start(); @@ -59,6 +68,8 @@ public class LogServiceManager implements BundleListener, FrameworkListener, Ser public void stop(BundleContext context) { eventAdminAdapter.stop(); eventAdminAdapter = null; + loggerAdminRegistration.unregister(); + loggerAdminRegistration = null; logServiceRegistration.unregister(); logServiceRegistration = null; logReaderServiceRegistration.unregister(); @@ -73,14 +84,21 @@ public class LogServiceManager implements BundleListener, FrameworkListener, Ser return systemBundleLog; } + LoggerAdmin getLoggerAdmin() { + return logServiceFactory.getLoggerAdmin(); + } + /** * BundleListener.bundleChanged method. * */ + @SuppressWarnings("deprecation") public void bundleChanged(BundleEvent event) { Bundle bundle = event.getBundle(); - if (logReaderServiceFactory.isLoggable(bundle, null, LogService.LOG_INFO)) - logReaderServiceFactory.log(bundle, null, null, LogService.LOG_INFO, getBundleEventTypeName(event.getType()), null); + if (logReaderServiceFactory.isLoggable(bundle, LOGGER_BUNDLE_EVENT, LogService.LOG_INFO)) { + LoggerImpl logger = (LoggerImpl) systemBundleLog.getLogger(LOGGER_BUNDLE_EVENT); + logger.log(bundle, null, null, LogService.LOG_INFO, getBundleEventTypeName(event.getType()), null); + } } /** @@ -91,9 +109,12 @@ public class LogServiceManager implements BundleListener, FrameworkListener, Ser ServiceReference<?> reference = event.getServiceReference(); Bundle bundle = reference.getBundle(); int eventType = event.getType(); + @SuppressWarnings("deprecation") int logType = (eventType == ServiceEvent.MODIFIED) ? LogService.LOG_DEBUG : LogService.LOG_INFO; - if (logReaderServiceFactory.isLoggable(bundle, null, logType)) - logReaderServiceFactory.log(bundle, null, reference, logType, getServiceEventTypeName(eventType), null); + if (logReaderServiceFactory.isLoggable(bundle, LOGGER_SERVICE_EVENT, logType)) { + LoggerImpl logger = (LoggerImpl) systemBundleLog.getLogger(LOGGER_SERVICE_EVENT); + logger.log(bundle, null, null, logType, getServiceEventTypeName(eventType), null); + } } /** @@ -103,10 +124,12 @@ public class LogServiceManager implements BundleListener, FrameworkListener, Ser public void frameworkEvent(FrameworkEvent event) { Bundle bundle = event.getBundle(); int eventType = event.getType(); + @SuppressWarnings("deprecation") int logType = (eventType == FrameworkEvent.ERROR) ? LogService.LOG_ERROR : LogService.LOG_INFO; - Throwable throwable = (eventType == FrameworkEvent.ERROR) ? event.getThrowable() : null; - if (logReaderServiceFactory.isLoggable(bundle, null, logType)) - logReaderServiceFactory.log(bundle, null, null, logType, getFrameworkEventTypeName(eventType), throwable); + if (logReaderServiceFactory.isLoggable(bundle, LOGGER_FRAMEWORK_EVENT, logType)) { + LoggerImpl logger = (LoggerImpl) systemBundleLog.getLogger(LOGGER_FRAMEWORK_EVENT); + logger.log(bundle, null, null, logType, getFrameworkEventTypeName(eventType), event.getThrowable()); + } } /** diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerContextTargetMap.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerContextTargetMap.java new file mode 100755 index 000000000..f22ff956a --- /dev/null +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerContextTargetMap.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * 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 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.internal.log; + +import java.util.*; +import org.eclipse.osgi.internal.log.ExtendedLogServiceFactory.EquinoxLoggerContext; +import org.osgi.framework.Bundle; +import org.osgi.framework.Version; +import org.osgi.service.log.admin.LoggerContext; + +public class LoggerContextTargetMap { + private final Map<Bundle, ExtendedLogServiceImpl> logServices = new HashMap<Bundle, ExtendedLogServiceImpl>(); + private final Map<String, EquinoxLoggerContext> loggerContexts = new HashMap<String, EquinoxLoggerContext>(); + private final Map<Bundle, List<String>> targetToQualifiedNames = new HashMap<Bundle, List<String>>(); + private final Map<String, Collection<Bundle>> qualifiedNameToTargets = new HashMap<String, Collection<Bundle>>(); + + List<String> add(Bundle b) { + String bsn = b.getSymbolicName(); + if (bsn == null) { + bsn = ""; //$NON-NLS-1$ + } + Version v = b.getVersion(); + String version = v == null ? "" : v.toString(); //$NON-NLS-1$ + String location = ExtendedLogServiceFactory.secureAction.getLocation(b); + + List<String> result = new ArrayList<String>(3); + + StringBuilder sb = new StringBuilder(bsn); + getTargetsInternal(bsn).add(b); + + sb.append('|').append(version); + String bsnVersion = sb.toString(); + getTargetsInternal(bsnVersion).add(b); + + sb.append('|').append(location); + String bsnVersionLocation = sb.toString(); + getTargetsInternal(bsnVersionLocation).add(b); + + result.add(bsnVersionLocation); + result.add(bsnVersion); + result.add(bsn); + + List<String> unmodifiable = Collections.unmodifiableList(result); + targetToQualifiedNames.put(b, unmodifiable); + return unmodifiable; + } + + void remove(Bundle b) { + List<String> qualifiedNames = targetToQualifiedNames.remove(b); + if (qualifiedNames != null) { + for (String qualifiedName : qualifiedNames) { + Collection<Bundle> targets = qualifiedNameToTargets.get(qualifiedName); + if (targets != null) { + targets.remove(b); + if (targets.isEmpty()) { + qualifiedNameToTargets.remove(qualifiedName); + } + } + } + } + logServices.remove(b); + } + + private Collection<Bundle> getTargetsInternal(String pid) { + Collection<Bundle> targets = qualifiedNameToTargets.get(pid); + if (targets == null) { + targets = new ArrayList<Bundle>(1); + qualifiedNameToTargets.put(pid, targets); + } + return targets; + } + + ExtendedLogServiceImpl getLogService(Bundle bundle, ExtendedLogServiceFactory factory) { + ExtendedLogServiceImpl logService = logServices.get(bundle); + if (logService == null) { + // add bundle to target maps before constructing + add(bundle); + logService = new ExtendedLogServiceImpl(factory, bundle); + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED) + logServices.put(bundle, logService); + } + return logService; + } + + void replaceSystemBundleLogService(Bundle previousBundle, Bundle currentBundle) { + ExtendedLogServiceImpl existing = logServices.get(previousBundle); + if (existing != null) { + remove(previousBundle); + add(currentBundle); + logServices.put(currentBundle, existing); + existing.applyLogLevels(getEffectiveLoggerContext(currentBundle)); + } + } + + void clear() { + logServices.clear(); + qualifiedNameToTargets.clear(); + targetToQualifiedNames.clear(); + } + + LoggerContext createLoggerContext(String name, ExtendedLogServiceFactory factory) { + EquinoxLoggerContext loggerContext = loggerContexts.get(name); + if (loggerContext == null) { + loggerContext = factory.createEquinoxLoggerContext(name); + loggerContexts.put(null, loggerContext); + } + return loggerContext; + } + + EquinoxLoggerContext getRootLoggerContext() { + return loggerContexts.get(null); + } + + void applyLogLevels(EquinoxLoggerContext loggerContext) { + Collection<Bundle> matching; + boolean isRoot = loggerContext.getName() == null; + if (isRoot) { + // root applies to all loggers + matching = logServices.keySet(); + } else { + matching = qualifiedNameToTargets.get(loggerContext.getName()); + } + for (Bundle bundle : matching) { + ExtendedLogServiceImpl logService = logServices.get(bundle); + if (logService != null) { + // Always apply the effective log context. + // This may be more costly but it is more simple than checking + // if the changed context overrides the existing settings + logService.applyLogLevels(getEffectiveLoggerContext(bundle)); + } + } + } + + EquinoxLoggerContext getEffectiveLoggerContext(Bundle bundle) { + List<String> qualifiedNames = targetToQualifiedNames.get(bundle); + if (qualifiedNames != null) { + for (String qualifiedName : qualifiedNames) { + EquinoxLoggerContext loggerContext = loggerContexts.get(qualifiedName); + if (loggerContext != null && !loggerContext.isEmpty()) { + return loggerContext; + } + } + } + return getRootLoggerContext(); + } +} diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java index 792bbd087..bf2f385b4 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/log/LoggerImpl.java @@ -10,17 +10,23 @@ package org.eclipse.osgi.internal.log; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.equinox.log.Logger; +import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.service.log.LogLevel; +import org.osgi.service.log.LogService; +import org.osgi.service.log.admin.LoggerContext; public class LoggerImpl implements Logger { protected final ExtendedLogServiceImpl logServiceImpl; protected final String name; - public LoggerImpl(ExtendedLogServiceImpl logServiceImpl, String name) { + private LogLevel enabledLevel = LogLevel.TRACE; + + public LoggerImpl(ExtendedLogServiceImpl logServiceImpl, String name, LoggerContext loggerContext) { this.logServiceImpl = logServiceImpl; this.name = name; + applyLoggerContext(loggerContext); } public String getName() { @@ -46,7 +52,7 @@ public class LoggerImpl implements Logger { @SuppressWarnings("rawtypes") public void log(ServiceReference sr, int level, String message, Throwable exception) { - logServiceImpl.log(name, sr, level, message, exception); + log(sr, null, level, message, exception); } public void log(Object context, int level, String message) { @@ -54,12 +60,41 @@ public class LoggerImpl implements Logger { } public void log(Object context, int level, String message, Throwable exception) { - logServiceImpl.log(name, context, level, message, exception); + log(context, null, level, message, exception); + } + + private void log(Object context, LogLevel logLevelEnum, int level, String message, Throwable exception) { + log(logServiceImpl.getBundle(), context, logLevelEnum, level, message, exception); + } + + void log(Bundle entryBundle, Object context, LogLevel logLevelEnum, int level, String message, Throwable exception) { + if (logLevelEnum == null) { + logLevelEnum = getLogLevel(level); + } + if (enabledLevel.implies(logLevelEnum)) { + logServiceImpl.getFactory().log(entryBundle, name, context, logLevelEnum, level, message, exception); + } + } + + @SuppressWarnings("deprecation") + private LogLevel getLogLevel(int level) { + switch (level) { + case LogService.LOG_DEBUG : + return LogLevel.DEBUG; + case LogService.LOG_ERROR : + return LogLevel.ERROR; + case LogService.LOG_INFO : + return LogLevel.INFO; + case LogService.LOG_WARNING : + return LogLevel.WARN; + default : + return LogLevel.TRACE; + } } @Override public boolean isTraceEnabled() { - return isLoggable(LogLevel.TRACE.ordinal()); + return enabledLevel.implies(LogLevel.TRACE); } @Override @@ -84,7 +119,7 @@ public class LoggerImpl implements Logger { @Override public boolean isDebugEnabled() { - return isLoggable(LogLevel.DEBUG.ordinal()); + return enabledLevel.implies(LogLevel.DEBUG); } @Override @@ -109,7 +144,7 @@ public class LoggerImpl implements Logger { @Override public boolean isInfoEnabled() { - return isLoggable(LogLevel.INFO.ordinal()); + return enabledLevel.implies(LogLevel.INFO); } @Override @@ -134,7 +169,7 @@ public class LoggerImpl implements Logger { @Override public boolean isWarnEnabled() { - return isLoggable(LogLevel.WARN.ordinal()); + return enabledLevel.implies(LogLevel.WARN); } @Override @@ -159,7 +194,7 @@ public class LoggerImpl implements Logger { @Override public boolean isErrorEnabled() { - return isLoggable(LogLevel.ERROR.ordinal()); + return enabledLevel.implies(LogLevel.ERROR); } @Override @@ -204,12 +239,16 @@ public class LoggerImpl implements Logger { private static final Pattern pattern = Pattern.compile("(\\\\?)(\\\\?)(\\{\\})"); //$NON-NLS-1$ - protected void log(LogLevel level, String format, Object... arguments) { - Arguments processedArguments = new Arguments(arguments); - if (processedArguments.isEmpty()) { - logServiceImpl.log(name, processedArguments.serviceReference(), level.ordinal(), format, processedArguments.throwable()); + private void log(LogLevel level, String format, Object... arguments) { + if (!enabledLevel.implies(level)) { return; } + Arguments processedArguments = new Arguments(arguments); + String message = processedArguments.isEmpty() ? format : formatMessage(format, processedArguments); + logServiceImpl.getFactory().log(logServiceImpl.getBundle(), name, processedArguments.serviceReference(), level, level.ordinal(), message.toString(), processedArguments.throwable()); + } + + String formatMessage(String format, Arguments processedArguments) { Matcher matcher = pattern.matcher(format); char[] chars = format.toCharArray(); int offset = 0; @@ -235,7 +274,7 @@ public class LoggerImpl implements Logger { } } message.append(chars, offset, chars.length - offset); - logServiceImpl.log(name, processedArguments.serviceReference(), level.ordinal(), message.toString(), processedArguments.throwable()); + return message.toString(); } private static int append(StringBuilder builder, Matcher matcher, char[] chars, int offset, int length, Object argument) { @@ -243,4 +282,8 @@ public class LoggerImpl implements Logger { builder.append(argument); return matcher.end(3); } + + void applyLoggerContext(LoggerContext loggerContext) { + enabledLevel = loggerContext == null ? LogLevel.WARN : loggerContext.getEffectiveLogLevel(name); + } } diff --git a/bundles/org.eclipse.osgi/osgi/function.interface.jar b/bundles/org.eclipse.osgi/osgi/function.interface.jar Binary files differnew file mode 100755 index 000000000..d2f08316f --- /dev/null +++ b/bundles/org.eclipse.osgi/osgi/function.interface.jar diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/FormatterLogger.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/FormatterLogger.java index 964972b75..637d34fb8 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/FormatterLogger.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/FormatterLogger.java @@ -31,8 +31,8 @@ import org.osgi.annotation.versioning.ProviderType; * additional arguments. If the last argument is a {@code Throwable} or * {@code ServiceReference}, it is added to the generated {@link LogEntry} and * then if the next to last argument is a {@code ServiceReference} or - * {@code Throwable}, it is added to the generated {@link LogEntry}. For - * example: + * {@code Throwable} and not the same type as the last argument, it is added to + * the generated {@link LogEntry}. For example: * * <pre> * logger.info("Found service %s.", serviceReference, serviceReference); diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogEntry.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogEntry.java index 1b252eb63..6b3ee59f7 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogEntry.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogEntry.java @@ -54,12 +54,14 @@ public interface LogEntry { ServiceReference< ? > getServiceReference(); /** - * Returns the level of this {@code LogEntry} object. + * Returns the integer level of this {@code LogEntry} object. * <p> - * This is one of the severity levels defined by the {@code LogService} - * interface. + * If one of the {@code log} methods of {@link LogService} was used, this is + * the specified integer level. Otherwise, this is the + * {@link LogLevel#ordinal() ordinal} value of the {@link #getLogLevel() log + * level}. * - * @return Level of this {@code LogEntry} object. + * @return Integer level of this {@code LogEntry} object. * @deprecated Since 1.4. Replaced by {@link #getLogLevel()}. */ @Deprecated @@ -116,9 +118,7 @@ public interface LogEntry { * {@code LogEntry} object. * * @return The name of the {@link Logger} object used to create this - * {@code LogEntry} object or {@code ""} if this {@code LogEntry} - * object was created using one of the original {@code LogService} - * {@code log} methods. + * {@code LogEntry} object. * @since 1.4 */ String getLoggerName(); @@ -126,10 +126,9 @@ public interface LogEntry { /** * Returns the sequence number for this {@code LogEntry} object. * <p> - * The {@code LogService} assigns a unique, non-negative value that is - * larger than all previously assigned values since the {@code LogService} - * was started. These values are transient and are reused upon restart of - * the {@code LogService}. + * A unique, non-negative value that is larger than all previously assigned + * values since the log implementation was started. These values are + * transient and are reused upon restart of the log implementation. * * @return The sequence number for this {@code LogEntry} object. * @since 1.4 @@ -140,7 +139,8 @@ public interface LogEntry { * Returns a string representing the thread which created this * {@code LogEntry} object. * <p> - * This string contains the name of the thread. + * This string must contain the name of the thread and may contain other + * information about the thread. * * @return A string representing the thread which created this * {@code LogEntry} object. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogLevel.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogLevel.java index 94053969d..ebc1f14a4 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogLevel.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogLevel.java @@ -61,6 +61,6 @@ public enum LogLevel { * {@code false} otherwise. */ public boolean implies(LogLevel other) { - return ordinal() <= other.ordinal(); + return ordinal() >= other.ordinal(); } } diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogListener.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogListener.java index 49bb6b7e4..4e6f645f4 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogListener.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogListener.java @@ -37,6 +37,7 @@ import org.osgi.annotation.versioning.ConsumerType; * @author $Id$ */ @ConsumerType +@FunctionalInterface public interface LogListener extends EventListener { /** * Listener method called for each LogEntry object created. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogService.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogService.java index 983c2b524..55d10697b 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogService.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LogService.java @@ -74,6 +74,19 @@ public interface LogService extends LoggerFactory { * <p> * The {@code ServiceReference} field and the {@code Throwable} field of the * {@code LogEntry} object will be set to {@code null}. + * <p> + * This method will log to the {@link Logger} named {@code "LogService"} for + * the bundle. The specified level is mapped to a {@link LogLevel} as + * follows: + * <ul> + * <li>{@link #LOG_ERROR} - {@link LogLevel#ERROR}</li> + * <li>{@link #LOG_WARNING} - {@link LogLevel#WARN}</li> + * <li>{@link #LOG_INFO} - {@link LogLevel#INFO}</li> + * <li>{@link #LOG_DEBUG} - {@link LogLevel#DEBUG}</li> + * <li>Any other value - {@link LogLevel#TRACE}</li> + * </ul> + * In the generated log entry, {@link LogEntry#getLevel()} must return the + * specified level. * * @param level The severity of the message. This should be one of the * defined log levels but may be any integer that is interpreted @@ -91,6 +104,19 @@ public interface LogService extends LoggerFactory { * <p> * The {@code ServiceReference} field of the {@code LogEntry} object will be * set to {@code null}. + * <p> + * This method will log to the {@link Logger} named {@code "LogService"} for + * the bundle. The specified level is mapped to a {@link LogLevel} as + * follows: + * <ul> + * <li>{@link #LOG_ERROR} - {@link LogLevel#ERROR}</li> + * <li>{@link #LOG_WARNING} - {@link LogLevel#WARN}</li> + * <li>{@link #LOG_INFO} - {@link LogLevel#INFO}</li> + * <li>{@link #LOG_DEBUG} - {@link LogLevel#DEBUG}</li> + * <li>Any other value - {@link LogLevel#TRACE}</li> + * </ul> + * In the generated log entry, {@link LogEntry#getLevel()} must return the + * specified level. * * @param level The severity of the message. This should be one of the * defined log levels but may be any integer that is interpreted @@ -111,6 +137,19 @@ public interface LogService extends LoggerFactory { * <p> * The {@code Throwable} field of the {@code LogEntry} will be set to * {@code null}. + * <p> + * This method will log to the {@link Logger} named {@code "LogService"} for + * the bundle. The specified level is mapped to a {@link LogLevel} as + * follows: + * <ul> + * <li>{@link #LOG_ERROR} - {@link LogLevel#ERROR}</li> + * <li>{@link #LOG_WARNING} - {@link LogLevel#WARN}</li> + * <li>{@link #LOG_INFO} - {@link LogLevel#INFO}</li> + * <li>{@link #LOG_DEBUG} - {@link LogLevel#DEBUG}</li> + * <li>Any other value - {@link LogLevel#TRACE}</li> + * </ul> + * In the generated log entry, {@link LogEntry#getLevel()} must return the + * specified level. * * @param sr The {@code ServiceReference} object of the service that this * message is associated with or {@code null}. @@ -128,6 +167,19 @@ public interface LogService extends LoggerFactory { /** * Logs a message with an exception associated and a * {@code ServiceReference} object. + * <p> + * This method will log to the {@link Logger} named {@code "LogService"} for + * the bundle. The specified level is mapped to a {@link LogLevel} as + * follows: + * <ul> + * <li>{@link #LOG_ERROR} - {@link LogLevel#ERROR}</li> + * <li>{@link #LOG_WARNING} - {@link LogLevel#WARN}</li> + * <li>{@link #LOG_INFO} - {@link LogLevel#INFO}</li> + * <li>{@link #LOG_DEBUG} - {@link LogLevel#DEBUG}</li> + * <li>Any other value - {@link LogLevel#TRACE}</li> + * </ul> + * In the generated log entry, {@link LogEntry#getLevel()} must return the + * specified level. * * @param sr The {@code ServiceReference} object of the service that this * message is associated with. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java index 564a0ad19..790a664f4 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/Logger.java @@ -34,8 +34,9 @@ import org.osgi.annotation.versioning.ProviderType; * additional arguments. If the last argument is a {@code Throwable} or * {@code ServiceReference}, it is added to the generated {@link LogEntry} and * then if the next to last argument is a {@code ServiceReference} or - * {@code Throwable}, it is added to the generated {@link LogEntry}. These - * arguments will not be used for place holders. For example: + * {@code Throwable} and not the same type as the last argument, it is added to + * the generated {@link LogEntry}. These arguments will not be used for place + * holders. For example: * * <pre> * logger.info("Found service {}.", serviceReference, serviceReference); @@ -50,6 +51,10 @@ import org.osgi.annotation.versioning.ProviderType; */ @ProviderType public interface Logger { + /** + * Root Logger Name. + */ + static String ROOT_LOGGER_NAME = "ROOT"; /** * Return the name of this Logger. diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerFactory.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerFactory.java index df1835468..3d17ce95f 100644 --- a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerFactory.java +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/LoggerFactory.java @@ -23,6 +23,26 @@ import org.osgi.annotation.versioning.ProviderType; * <p> * Provides methods for bundles to obtain named {@link Logger}s that can be used * to write messages to the log. + * <p> + * Logger names should be in the form of a fully qualified Java class names with + * segments separated by full stop ({@code '.'} \u002E). For example: + * + * <pre> + * com.foo.Bar + * </pre> + * + * Logger names exist in a hierarchy. A logger name is said to be an ancestor of + * another logger name if the logger name followed by a full stop ({@code '.'} + * \u002E) is a prefix of the descendant logger name. The + * {@link Logger#ROOT_LOGGER_NAME root logger name} is the top ancestor of the + * logger name hierarchy. For example: + * + * <pre> + * com.foo.Bar + * com.foo + * com + * ROOT + * </pre> * * @ThreadSafe * @since 1.4 @@ -32,44 +52,50 @@ import org.osgi.annotation.versioning.ProviderType; public interface LoggerFactory { /** - * Return a {@link Logger} named with the specified name. + * Return the {@link Logger} named with the specified name. * * @param name The name to use for the logger name. - * @return A {@link Logger} named with the specified name. + * @return The {@link Logger} named with the specified name. If the name + * parameter is equal to {@link Logger#ROOT_LOGGER_NAME}, then the + * root logger is returned. */ Logger getLogger(String name); /** - * Return a {@link Logger} named with the specified class. + * Return the {@link Logger} named with the specified class. * * @param clazz The class to use for the logger name. - * @return A {@link Logger} named with the specified class. + * @return The {@link Logger} named with the name of the specified class. */ Logger getLogger(Class< ? > clazz); /** - * Return a {@link Logger} of the specified type named with the specified + * Return the {@link Logger} of the specified type named with the specified * name. * - * @param <L> A Logger type. + * @param <L> The Logger type. * @param name The name to use for the logger name. * @param loggerType The type of Logger. Can be {@link Logger} or * {@link FormatterLogger}. - * @return A {@link Logger} named with the specified name. + * @return The {@link Logger} or {@link FormatterLogger} named with the + * specified name. If the name parameter is equal to + * {@link Logger#ROOT_LOGGER_NAME}, then the root logger is + * returned. * @throws IllegalArgumentException If the specified type is not a supported * Logger type. */ <L extends Logger> L getLogger(String name, Class<L> loggerType); /** - * Return a {@link Logger} of the specified type named with the specified + * Return the {@link Logger} of the specified type named with the specified * class. * * @param <L> A Logger type. * @param clazz The class to use for the logger name. * @param loggerType The type of Logger. Can be {@link Logger} or * {@link FormatterLogger}. - * @return A {@link Logger} named with the specified class. + * @return The {@link Logger} or {@link FormatterLogger} named with the name + * of the specified class. * @throws IllegalArgumentException If the specified type is not a supported * Logger type. */ diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/LoggerAdmin.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/LoggerAdmin.java new file mode 100644 index 000000000..37c8ef2cf --- /dev/null +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/LoggerAdmin.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) OSGi Alliance (2016). All Rights Reserved. + * + * Licensed 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.osgi.service.log.admin; + +import org.osgi.annotation.versioning.ProviderType; +import org.osgi.service.log.LoggerFactory; + +/** + * LoggerAdmin service for configuring loggers. + * <p> + * Each bundle may have its own named {@link LoggerContext} based upon its + * bundle symbolic name, bundle version, and bundle location. There is also a + * root Logger Context from which each named Logger Context inherits. The root + * Logger Context has no name. + * <p> + * When a bundle logs, the logger implementation must locate the Logger Context + * for the bundle to determine the + * {@link LoggerContext#getEffectiveLogLevel(String) effective log level} of the + * logger name. The <i>best matching name</i> for the Logger Context is the + * longest name, which has a non-empty Logger Context, according to this syntax: + * + * <pre> + * name ::= symbolic-name ( ’|’ version ( ’|’ location )? )? + * </pre> + * + * The version must be formatted canonically, that is, according to the + * {@code toString()} method of the {@code Version} class. So the Logger Context + * for a bundle is searched for using the following names in the given order: + * + * <pre> + * <symbolic-name>|<version>|<location> + * <symbolic-name>|<version> + * <symbolic-name> + * </pre> + * + * If a non-empty Logger Context is not found, the Logger Context with the name + * {@code <symbolic-name>} is used for the bundle. + * + * @ThreadSafe + * @author $Id$ + */ +@ProviderType +public interface LoggerAdmin { + /** + * Logger Admin service property to associate the Logger Admin service with + * a {@link LoggerFactory} service. + * <p> + * This service property is set to the {@code service.id} for the + * {@link LoggerFactory} service administered by this Logger Admin. + * <p> + * The value of this service property must be of type {@code Long}. + */ + static String LOG_SERVICE_ID = "osgi.log.service.id"; + + /** + * Get the Logger Context for the specified name. + * + * @param name The name of the Logger Context. Can be {@code null} to + * specify the root Logger Context. + * @return The Logger Context for the specified name. + */ + LoggerContext getLoggerContext(String name); +} diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/LoggerContext.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/LoggerContext.java new file mode 100644 index 000000000..33b9e4b6f --- /dev/null +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/LoggerContext.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) OSGi Alliance (2016). All Rights Reserved. + * + * Licensed 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.osgi.service.log.admin; + +import java.util.Map; + +import org.osgi.annotation.versioning.ProviderType; +import org.osgi.service.log.LogLevel; + +/** + * Logger Context for a bundle. + * <p> + * Any change to the configuration of this Logger Context must be effective + * immediately for all loggers that would rely upon the configuration of this + * Logger Context. + * + * @ThreadSafe + * @author $Id$ + */ +@ProviderType +public interface LoggerContext { + /** + * Returns the name for this Logger Context. + * + * @return The name for this Logger Context. The root Logger Context has no + * name and returns {@code null}. + */ + String getName(); + + /** + * Returns the effective log level of the logger name in this Logger + * Context. + * <p> + * The effective log level for a logger name is found by the following + * steps: + * <ol> + * <li>If the specified logger name is configured with a non-null log level + * in this Logger Context, return the configured log level.</li> + * <li>For each ancestor logger name of the specified logger name, if the + * ancestor logger name is configured with a non-null log level in this + * Logger Context, return the configured log level.</li> + * <li>If the specified logger name is configured with a non-null log level + * in the root Logger Context, return the configured log level.</li> + * <li>For each ancestor logger name of the specified logger name, if the + * ancestor logger name is configured with a non-null log level in the root + * Logger Context, return the configured log level.</li> + * <li>Return {@link LogLevel#WARN} because no non-null log level has been + * found for the specified logger name or any of its ancestor logger names. + * </li> + * </ol> + * + * @param name The logger name. + * @return The effective log level of the logger name in this Logger + * Context. + */ + LogLevel getEffectiveLogLevel(String name); + + /** + * Returns the configured log levels for this Logger Context. + * + * @return The configured log levels for this Logger Context. The keys are + * the logger names and the values are the log levels. The returned + * map may be empty if no logger names are configured for this + * Logger Context. The log level value can be {@code null}. The + * returned map is the property of the caller who can modify the map + * and use it as input to {@link #setLogLevels(Map)}. The returned + * map must support all optional Map operations. + */ + Map<String,LogLevel> getLogLevels(); + + /** + * Configure the log levels for this Logger Context. + * <p> + * All previous log levels configured for this Logger Context are cleared + * and then the log levels in the specified map are configured. + * + * @param logLevels The log levels to configure for this Logger Context. The + * keys are the logger names and the values are the log levels. + * The log level value can be {@code null}. The specified map is + * the property of the caller and this method must not modify or + * retain the specified map. + */ + void setLogLevels(Map<String,LogLevel> logLevels); + + /** + * Clear the configuration of this Logger Context. + * <p> + * The configured log levels will be cleared. + */ + void clear(); + + /** + * Returns whether the configuration of this Logger Context is empty. + * + * @return {@code true} if this Logger Context has no configuration. That + * is, the configured log levels are empty. Otherwise {@code false} + * is returned. + */ + boolean isEmpty(); +} diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/package-info.java b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/package-info.java new file mode 100644 index 000000000..21f2c3493 --- /dev/null +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/package-info.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) OSGi Alliance (2016). All Rights Reserved. + * + * Licensed 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. + */ + +/** + * Log Admin Package Version 1.0. + * <p> + * Bundles wishing to use this package must list the package in the + * Import-Package header of the bundle's manifest. This package has two types of + * users: the consumers that use the API in this package and the providers that + * implement the API in this package. + * <p> + * Example import for consumers using the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.log.admin; version="[1.0,2.0)"} + * <p> + * Example import for providers implementing the API in this package: + * <p> + * {@code Import-Package: org.osgi.service.log.admin; version="[1.0,1.1)"} + * + * @author $Id$ + */ +@Version("1.0") +package org.osgi.service.log.admin; + +import org.osgi.annotation.versioning.Version; diff --git a/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/packageinfo b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/packageinfo new file mode 100644 index 000000000..7c8de0324 --- /dev/null +++ b/bundles/org.eclipse.osgi/osgi/src/org/osgi/service/log/admin/packageinfo @@ -0,0 +1 @@ +version 1.0 |