diff --git a/integration/build.xml b/integration/build.xml index bcb3db6..80f3efc 100644 --- a/integration/build.xml +++ b/integration/build.xml @@ -56,7 +56,7 @@ - + @@ -103,7 +103,7 @@ + + + + + + + + diff --git a/integration/pom.xml b/integration/pom.xml index 02af7f9..c0b12c9 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 integration diff --git a/integration/src/test/java/org/slf4j/MissingSingletonMethodAssertionTest.java b/integration/src/test/java/org/slf4j/MissingSingletonMethodAssertionTest.java index c142760..08776f8 100644 --- a/integration/src/test/java/org/slf4j/MissingSingletonMethodAssertionTest.java +++ b/integration/src/test/java/org/slf4j/MissingSingletonMethodAssertionTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2004-2011 QOS.ch + * Copyright (c) 2004-2016 QOS.ch * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining diff --git a/integration/src/test/java/org/slf4j/issues/Issue324Test.java b/integration/src/test/java/org/slf4j/issues/Issue324Test.java index 3f3c319..4093f62 100644 --- a/integration/src/test/java/org/slf4j/issues/Issue324Test.java +++ b/integration/src/test/java/org/slf4j/issues/Issue324Test.java @@ -7,10 +7,9 @@ public class Issue324Test extends TestCase { - public void testLoggerCreationInPresenseOfSecurityManager() { String currentDir = System.getProperty("user.dir"); - System.out.println("currentDir:"+currentDir); + System.out.println("currentDir:" + currentDir); Logger logger = LoggerFactory.getLogger(Issue324Test.class); logger.debug("hello"); } diff --git a/jcl-over-slf4j/pom.xml b/jcl-over-slf4j/pom.xml index fdadd29..1f01ded 100644 --- a/jcl-over-slf4j/pom.xml +++ b/jcl-over-slf4j/pom.xml @@ -5,7 +5,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 4.0.0 diff --git a/jul-to-slf4j/pom.xml b/jul-to-slf4j/pom.xml index 4fba41f..951a587 100644 --- a/jul-to-slf4j/pom.xml +++ b/jul-to-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 jul-to-slf4j diff --git a/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerPerfTest.java b/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerPerfTest.java index 384d90e..fa20411 100644 --- a/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerPerfTest.java +++ b/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerPerfTest.java @@ -33,6 +33,7 @@ import org.junit.Before; import org.junit.Test; import org.slf4j.LoggerFactory; + public class SLF4JBridgeHandlerPerfTest { static String LOGGER_NAME = "yay"; @@ -49,7 +50,6 @@ org.slf4j.Logger slf4jLogger = LoggerFactory.getLogger(LOGGER_NAME); Handler[] existingHandlers; - @Before public void setUp() throws Exception { diff --git a/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerTest.java b/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerTest.java index a30d685..d78fbdf 100644 --- a/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerTest.java +++ b/jul-to-slf4j/src/test/java/org/slf4j/bridge/SLF4JBridgeHandlerTest.java @@ -35,14 +35,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -public class SLF4JBridgeHandlerTest { + +public class SLF4JBridgeHandlerTest { static String LOGGER_NAME = "yay"; ListAppender listAppender = new ListAppender(); org.apache.log4j.Logger log4jRoot; java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("yay"); - @Before public void setUp() throws Exception { @@ -179,18 +179,18 @@ } // See http://jira.qos.ch/browse/SLF4J-337 - + @Test public void illFormattedInputShouldBeReturnedAsIs() { SLF4JBridgeHandler.install(); String msg = "foo {18=bad} {0}"; - + julLogger.log(Level.INFO, msg, "ignored parameter due to IllegalArgumentException"); assertEquals(1, listAppender.list.size()); LoggingEvent le = (LoggingEvent) listAppender.list.get(0); assertEquals(msg, le.getMessage()); } - + void assertLevel(int index, org.apache.log4j.Level expectedLevel) { LoggingEvent le = (LoggingEvent) listAppender.list.get(index); assertEquals(expectedLevel, le.getLevel()); diff --git a/log4j-over-slf4j/pom.xml b/log4j-over-slf4j/pom.xml index 1b21134..37d3c2d 100644 --- a/log4j-over-slf4j/pom.xml +++ b/log4j-over-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 diff --git a/log4j-over-slf4j/src/main/java/org/apache/log4j/Category.java b/log4j-over-slf4j/src/main/java/org/apache/log4j/Category.java index d785a83..27f567b 100644 --- a/log4j-over-slf4j/src/main/java/org/apache/log4j/Category.java +++ b/log4j-over-slf4j/src/main/java/org/apache/log4j/Category.java @@ -346,13 +346,13 @@ public void setLevel(Level level) { // nothing to do } - + public boolean getAdditivity() { return false; } - + public void assertLog(boolean assertion, String msg) { - if(!assertion) + if (!assertion) error(msg); } diff --git a/log4j-over-slf4j/src/main/resources/META-INF/MANIFEST.MF b/log4j-over-slf4j/src/main/resources/META-INF/MANIFEST.MF index 43d7391..3e98459 100644 --- a/log4j-over-slf4j/src/main/resources/META-INF/MANIFEST.MF +++ b/log4j-over-slf4j/src/main/resources/META-INF/MANIFEST.MF @@ -4,5 +4,10 @@ Bundle-Name: log4j-over-slf4j Bundle-Vendor: SLF4J.ORG Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Export-Package: org.apache.log4j;version=${log4j.version},org.apache.log4j.helpers;version=${log4j.version},org.apache.log4j.spi;version=${log4j.version},org.apache.log4j.xml;version=${log4j.version} -Import-Package: org.slf4j;version=${slf4j.api.minimum.compatible.version}, org.slf4j.helpers;version=${slf4j.api.minimum.compatible.version}, org.slf4j.spi;version=${slf4j.api.minimum.compatible.version} +Export-Package: org.apache.log4j;version=${log4j.version}, + org.apache.log4j.helpers;version=${log4j.version}, + org.apache.log4j.spi;version=${log4j.version}, + org.apache.log4j.xml;version=${log4j.version} +Import-Package: org.slf4j;version=${slf4j.api.minimum.compatible.version}, + org.slf4j.helpers;version=${slf4j.api.minimum.compatible.version}, + org.slf4j.spi;version=${slf4j.api.minimum.compatible.version} diff --git a/log4j-over-slf4j/src/test/java/org/dummy/Bug131.java b/log4j-over-slf4j/src/test/java/org/dummy/Bug131.java index 3479dbb..506f8a3 100644 --- a/log4j-over-slf4j/src/test/java/org/dummy/Bug131.java +++ b/log4j-over-slf4j/src/test/java/org/dummy/Bug131.java @@ -32,7 +32,8 @@ import org.apache.log4j.Category; import org.apache.log4j.Logger; import org.junit.Test; -public class Bug131 { + +public class Bug131 { @Test public void testBug131() { diff --git a/log4j-over-slf4j/src/test/java/org/dummy/Bug139.java b/log4j-over-slf4j/src/test/java/org/dummy/Bug139.java index 62d0980..0b1916e 100644 --- a/log4j-over-slf4j/src/test/java/org/dummy/Bug139.java +++ b/log4j-over-slf4j/src/test/java/org/dummy/Bug139.java @@ -33,7 +33,7 @@ import org.apache.log4j.Logger; import org.junit.Test; -public class Bug139 { +public class Bug139 { @Test public void test() { diff --git a/osgi-over-slf4j/pom.xml b/osgi-over-slf4j/pom.xml index 7c71d60..bb8ac68 100644 --- a/osgi-over-slf4j/pom.xml +++ b/osgi-over-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 osgi-over-slf4j diff --git a/pom.xml b/pom.xml index 771eec4..928bbd5 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 pom SLF4J @@ -28,7 +28,7 @@ - https://github.com/ceki/slf4j + https://github.com/qos-ch/slf4j git@github.com:qos-ch/slf4j.git @@ -44,7 +44,7 @@ 0.8.1 1.2.17 1.0.13 - 4.10 + 4.12 3.3 2.10.2 @@ -182,9 +182,10 @@ org.apache.maven.plugins maven-surefire-plugin - 2.10 + 2.19.1 - once + 2C + true plain false diff --git a/slf4j-android/pom.xml b/slf4j-android/pom.xml index 6a66ab4..fd78b04 100644 --- a/slf4j-android/pom.xml +++ b/slf4j-android/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-android diff --git a/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerAdapter.java b/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerAdapter.java index 946e72f..8221324 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerAdapter.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerAdapter.java @@ -81,7 +81,6 @@ class AndroidLoggerAdapter extends MarkerIgnoringBase { private static final long serialVersionUID = -1227274521521287937L; - /** * Package access allows only {@link AndroidLoggerFactory} to instantiate * SimpleLogger instances. diff --git a/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java b/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java index 88ae525..3033378 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java @@ -117,8 +117,7 @@ // Take leading part and append '*' to indicate that it was truncated int length = loggerName.length(); int lastPeriodIndex = loggerName.lastIndexOf('.'); - return lastPeriodIndex != -1 && length - (lastPeriodIndex + 1) <= TAG_MAX_LENGTH - ? loggerName.substring(lastPeriodIndex + 1) - : '*' + loggerName.substring(length - TAG_MAX_LENGTH + 1); + return lastPeriodIndex != -1 && length - (lastPeriodIndex + 1) <= TAG_MAX_LENGTH ? loggerName.substring(lastPeriodIndex + 1) : '*' + loggerName + .substring(length - TAG_MAX_LENGTH + 1); } }diff --git a/slf4j-android/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/slf4j-android/src/main/java/org/slf4j/impl/StaticLoggerBinder.java index 0ab2246..426ccae 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/StaticLoggerBinder.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -58,8 +58,6 @@ // to avoid constant folding by the compiler, this field must *not* be final public static String REQUESTED_API_VERSION = "1.6.99"; // !final - - private static final String loggerFactoryClassStr = AndroidLoggerFactory.class.getName(); /** diff --git a/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 9480c64..953e0e2 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -27,7 +27,6 @@ import org.slf4j.helpers.NOPMDCAdapter; import org.slf4j.spi.MDCAdapter; - /** * This implementation is bound to {@link NOPMDCAdapter}. * @@ -36,32 +35,33 @@ */ public class StaticMDCBinder { - /** - * The unique instance of this class. - */ - public static final StaticMDCBinder SINGLETON = new StaticMDCBinder(); + /** + * The unique instance of this class. + */ + public static final StaticMDCBinder SINGLETON = new StaticMDCBinder(); - private StaticMDCBinder() { - } - - /** - * Return the singleton of this class. - * - * @return the StaticMDCBinder singleton - * @since 1.7.14 - */ - public static final StaticMDCBinder getSingleton() { - return SINGLETON; - } - /** - * Currently this method always returns an instance of - * {@link NOPMDCAdapter}. - */ - public MDCAdapter getMDCA() { - return new NOPMDCAdapter(); - } - - public String getMDCAdapterClassStr() { - return NOPMDCAdapter.class.getName(); - } + private StaticMDCBinder() { + } + + /** + * Return the singleton of this class. + * + * @return the StaticMDCBinder singleton + * @since 1.7.14 + */ + public static final StaticMDCBinder getSingleton() { + return SINGLETON; + } + + /** + * Currently this method always returns an instance of + * {@link NOPMDCAdapter}. + */ + public MDCAdapter getMDCA() { + return new NOPMDCAdapter(); + } + + public String getMDCAdapterClassStr() { + return NOPMDCAdapter.class.getName(); + } } diff --git a/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index e744bd9..21a4427 100644 --- a/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-android/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -39,39 +39,39 @@ */ public class StaticMarkerBinder implements MarkerFactoryBinder { - /** - * The unique instance of this class. - */ - public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder(); - - final IMarkerFactory markerFactory = new BasicMarkerFactory(); - - private StaticMarkerBinder() { - } - - /** - * Return the singleton of this class. - * - * @return the StaticMarkerBinder singleton - * @since 1.7.14 - */ - public static StaticMarkerBinder getSingleton() { - return SINGLETON; - } - - /** - * Currently this method always returns an instance of - * {@link BasicMarkerFactory}. - */ - public IMarkerFactory getMarkerFactory() { - return markerFactory; - } - - /** - * Currently, this method returns the class name of - * {@link BasicMarkerFactory}. - */ - public String getMarkerFactoryClassStr() { - return BasicMarkerFactory.class.getName(); - } + /** + * The unique instance of this class. + */ + public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder(); + + final IMarkerFactory markerFactory = new BasicMarkerFactory(); + + private StaticMarkerBinder() { + } + + /** + * Return the singleton of this class. + * + * @return the StaticMarkerBinder singleton + * @since 1.7.14 + */ + public static StaticMarkerBinder getSingleton() { + return SINGLETON; + } + + /** + * Currently this method always returns an instance of + * {@link BasicMarkerFactory}. + */ + public IMarkerFactory getMarkerFactory() { + return markerFactory; + } + + /** + * Currently, this method returns the class name of + * {@link BasicMarkerFactory}. + */ + public String getMarkerFactoryClassStr() { + return BasicMarkerFactory.class.getName(); + } } diff --git a/slf4j-api/pom.xml b/slf4j-api/pom.xml index 6e79940..e90bd8c 100644 --- a/slf4j-api/pom.xml +++ b/slf4j-api/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-api diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java index 4bc830b..3587810 100644 --- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java @@ -26,12 +26,15 @@ import java.io.IOException; import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; - +import java.util.concurrent.LinkedBlockingQueue; + +import org.slf4j.event.SubstituteLoggingEvent; import org.slf4j.helpers.NOPLoggerFactory; import org.slf4j.helpers.SubstituteLogger; import org.slf4j.helpers.SubstituteLoggerFactory; @@ -68,6 +71,7 @@ static final String VERSION_MISMATCH = CODES_PREFIX + "#version_mismatch"; static final String SUBSTITUTE_LOGGER_URL = CODES_PREFIX + "#substituteLogger"; static final String LOGGER_NAME_MISMATCH_URL = CODES_PREFIX + "#loggerNameMismatch"; + static final String REPLAY_URL = CODES_PREFIX + "#replay"; static final String UNSUCCESSFUL_INIT_URL = CODES_PREFIX + "#unsuccessfulInit"; static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also " + UNSUCCESSFUL_INIT_URL; @@ -78,14 +82,14 @@ static final int SUCCESSFUL_INITIALIZATION = 3; static final int NOP_FALLBACK_INITIALIZATION = 4; - static int INITIALIZATION_STATE = UNINITIALIZED; - static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory(); + static volatile int INITIALIZATION_STATE = UNINITIALIZED; + static SubstituteLoggerFactory SUBST_FACTORY = new SubstituteLoggerFactory(); static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory(); // Support for detecting mismatched logger names. static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch"; static final String JAVA_VENDOR_PROPERTY = "java.vendor.url"; - + static boolean DETECT_LOGGER_NAME_MISMATCH = Util.safeGetBooleanSystemProperty(DETECT_LOGGER_NAME_MISMATCH_PROPERTY); /** @@ -114,7 +118,6 @@ */ static void reset() { INITIALIZATION_STATE = UNINITIALIZED; - TEMP_FACTORY = new SubstituteLoggerFactory(); } private final static void performInitialization() { @@ -136,13 +139,17 @@ private final static void bind() { try { - Set staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); - reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); + Set staticLoggerBinderPathSet = null; + // skip check under android, see also http://jira.qos.ch/browse/SLF4J-328 + if (!isAndroid()) { + staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); + reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); + } // the next line does the binding StaticLoggerBinder.getSingleton(); INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; reportActualBinding(staticLoggerBinderPathSet); - fixSubstitutedLoggers(); + replayEvents(); } catch (NoClassDefFoundError ncde) { String msg = ncde.getMessage(); if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { @@ -174,24 +181,67 @@ Util.report("Failed to instantiate SLF4J LoggerFactory", t); } - private final static void fixSubstitutedLoggers() { - List loggers = TEMP_FACTORY.getLoggers(); - - if (loggers.isEmpty()) { + private static void replayEvents() { + final LinkedBlockingQueue queue = SUBST_FACTORY.getEventQueue(); + final int queueSize = queue.size(); + int count = 0; + final int maxDrain = 128; + List eventList = new ArrayList(maxDrain); + while (true) { + int numDrained = queue.drainTo(eventList, maxDrain); + if (numDrained == 0) + break; + for (SubstituteLoggingEvent event : eventList) { + replaySingleEvent(event); + if (count++ == 0) + emitReplayOrSubstituionWarning(event, queueSize); + } + eventList.clear(); + } + } + + private static void emitReplayOrSubstituionWarning(SubstituteLoggingEvent event, int queueSize) { + if (event.getLogger().isDelegateEventAware()) { + emitReplayWarning(queueSize); + } else if (event.getLogger().isDelegateNOP()) { + // nothing to do + } else { + emitSubstitutionWarning(); + } + } + + private static void replaySingleEvent(SubstituteLoggingEvent event) { + if (event == null) return; - } - + + SubstituteLogger substLogger = event.getLogger(); + String loggerName = substLogger.getName(); + if (substLogger.isDelegateNull()) { + Logger logger = getLogger(loggerName); + substLogger.setDelegate(logger); + } + + if (substLogger.isDelegateNOP()) { + // nothing to do + } else if (substLogger.isDelegateEventAware()) { + substLogger.log(event); + } else { + Util.report(loggerName); + } + } + + private static void emitSubstitutionWarning() { Util.report("The following set of substitute loggers may have been accessed"); Util.report("during the initialization phase. Logging calls during this"); Util.report("phase were not honored. However, subsequent logging calls to these"); Util.report("loggers will work as normally expected."); Util.report("See also " + SUBSTITUTE_LOGGER_URL); - for (SubstituteLogger subLogger : loggers) { - subLogger.setDelegate(getLogger(subLogger.getName())); - Util.report(subLogger.getName()); - } - - TEMP_FACTORY.clear(); + } + + private static void emitReplayWarning(int eventCount) { + Util.report("A number (" + eventCount + ") of logging calls during the initialization phase have been intercepted and are"); + Util.report("now being replayed. These are suject to the filtering rules of the underlying logging system."); + Util.report("See also " + REPLAY_URL); } private final static void versionSanityCheck() { @@ -246,8 +296,8 @@ return staticLoggerBinderPathSet; } - private static boolean isAmbiguousStaticLoggerBinderPathSet(Set staticLoggerBinderPathSet) { - return staticLoggerBinderPathSet.size() > 1; + private static boolean isAmbiguousStaticLoggerBinderPathSet(Set binderPathSet) { + return binderPathSet.size() > 1; } /** @@ -255,15 +305,10 @@ * No reporting is done otherwise. * */ - private static void reportMultipleBindingAmbiguity(Set staticLoggerBinderPathSet) { - if(isAndroid()) { - // skip check under android, see also http://jira.qos.ch/browse/SLF4J-328 - return; - } - - if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { + private static void reportMultipleBindingAmbiguity(Set binderPathSet) { + if (isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) { Util.report("Class path contains multiple SLF4J bindings."); - for (URL path : staticLoggerBinderPathSet) { + for (URL path : binderPathSet) { Util.report("Found binding in [" + path + "]"); } Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation."); @@ -272,13 +317,14 @@ private static boolean isAndroid() { String vendor = Util.safeGetSystemProperty(JAVA_VENDOR_PROPERTY); - if(vendor == null) + if (vendor == null) return false; return vendor.toLowerCase().contains("android"); } - private static void reportActualBinding(Set staticLoggerBinderPathSet) { - if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { + private static void reportActualBinding(Set binderPathSet) { + // binderPathSet can be null under Android + if (binderPathSet != null && isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) { Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]"); } } @@ -355,7 +401,7 @@ case ONGOING_INITIALIZATION: // support re-entrant behavior. // See also http://jira.qos.ch/browse/SLF4J-97 - return TEMP_FACTORY; + return SUBST_FACTORY; } throw new IllegalStateException("Unreachable code"); } diff --git a/slf4j-api/src/main/java/org/slf4j/event/EventConstants.java b/slf4j-api/src/main/java/org/slf4j/event/EventConstants.java new file mode 100644 index 0000000..8a7e733 --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/event/EventConstants.java @@ -0,0 +1,13 @@ +package org.slf4j.event; + +import org.slf4j.spi.LocationAwareLogger; + +public class EventConstants { + public static final int ERROR_INT = LocationAwareLogger.ERROR_INT; + public static final int WARN_INT = LocationAwareLogger.WARN_INT; + public static final int INFO_INT = LocationAwareLogger.INFO_INT; + public static final int DEBUG_INT = LocationAwareLogger.DEBUG_INT; + public static final int TRACE_INT = LocationAwareLogger.TRACE_INT; + public static final String NA_SUBST = "NA/SubstituteLogger"; + +} diff --git a/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java b/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java new file mode 100644 index 0000000..401d622 --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java @@ -0,0 +1,296 @@ +package org.slf4j.event; + +import java.util.Queue; + +import org.slf4j.Logger; +import org.slf4j.Marker; +import org.slf4j.helpers.SubstituteLogger; + +public class EventRecodingLogger implements Logger { + + String name; + SubstituteLogger logger; + Queue eventQueue; + + public EventRecodingLogger(SubstituteLogger logger, Queue eventQueue) { + this.logger = logger; + this.name = logger.getName(); + this.eventQueue = eventQueue; + } + + public String getName() { + return name; + } + + private void recordEvent(Level level, String msg, Object[] args, Throwable throwable) { + recordEvent(level, null, msg, args, throwable); + } + + private void recordEvent(Level level, Marker marker, String msg, Object[] args, Throwable throwable) { + // System.out.println("recording logger:"+name+", msg:"+msg); + SubstituteLoggingEvent loggingEvent = new SubstituteLoggingEvent(); + loggingEvent.setTimeStamp(System.currentTimeMillis()); + loggingEvent.setLevel(level); + loggingEvent.setLogger(logger); + loggingEvent.setLoggerName(name); + + loggingEvent.setMessage(msg); + loggingEvent.setArgumentArray(args); + loggingEvent.setThrowable(throwable); + loggingEvent.setThreadName(Thread.currentThread().getName()); + eventQueue.add(loggingEvent); + } + + public boolean isTraceEnabled() { + return true; + } + + public void trace(String msg) { + recordEvent(Level.TRACE, msg, null, null); + } + + public void trace(String format, Object arg) { + recordEvent(Level.TRACE, format, new Object[] { arg }, null); + } + + public void trace(String format, Object arg1, Object arg2) { + recordEvent(Level.TRACE, format, new Object[] { arg1, arg2 }, null); + } + + public void trace(String format, Object... arguments) { + recordEvent(Level.TRACE, format, arguments, null); + } + + public void trace(String msg, Throwable t) { + recordEvent(Level.TRACE, msg, null, t); + } + + public boolean isTraceEnabled(Marker marker) { + return true; + } + + public void trace(Marker marker, String msg) { + recordEvent(Level.TRACE, marker, msg, null, null); + + } + + public void trace(Marker marker, String format, Object arg) { + recordEvent(Level.TRACE, marker, format, new Object[] { arg }, null); + } + + public void trace(Marker marker, String format, Object arg1, Object arg2) { + recordEvent(Level.TRACE, marker, format, new Object[] { arg1, arg2 }, null); + } + + public void trace(Marker marker, String format, Object... argArray) { + recordEvent(Level.TRACE, marker, format, argArray, null); + + } + + public void trace(Marker marker, String msg, Throwable t) { + recordEvent(Level.TRACE, marker, msg, null, t); + } + + public boolean isDebugEnabled() { + return true; + } + + public void debug(String msg) { + recordEvent(Level.TRACE, msg, null, null); + } + + public void debug(String format, Object arg) { + recordEvent(Level.DEBUG, format, new Object[] { arg }, null); + + } + + public void debug(String format, Object arg1, Object arg2) { + recordEvent(Level.DEBUG, format, new Object[] { arg1, arg2 }, null); + + } + + public void debug(String format, Object... arguments) { + recordEvent(Level.DEBUG, format, arguments, null); + } + + public void debug(String msg, Throwable t) { + recordEvent(Level.DEBUG, msg, null, t); + } + + public boolean isDebugEnabled(Marker marker) { + return true; + } + + public void debug(Marker marker, String msg) { + recordEvent(Level.DEBUG, marker, msg, null, null); + } + + public void debug(Marker marker, String format, Object arg) { + recordEvent(Level.DEBUG, marker, format, new Object[] { arg }, null); + } + + public void debug(Marker marker, String format, Object arg1, Object arg2) { + recordEvent(Level.DEBUG, marker, format, new Object[] { arg1, arg2 }, null); + } + + public void debug(Marker marker, String format, Object... arguments) { + recordEvent(Level.DEBUG, marker, format, arguments, null); + } + + public void debug(Marker marker, String msg, Throwable t) { + recordEvent(Level.DEBUG, marker, msg, null, t); + } + + public boolean isInfoEnabled() { + return true; + } + + public void info(String msg) { + recordEvent(Level.INFO, msg, null, null); + } + + public void info(String format, Object arg) { + recordEvent(Level.INFO, format, new Object[] { arg }, null); + } + + public void info(String format, Object arg1, Object arg2) { + recordEvent(Level.INFO, format, new Object[] { arg1, arg2 }, null); + } + + public void info(String format, Object... arguments) { + recordEvent(Level.INFO, format, arguments, null); + } + + public void info(String msg, Throwable t) { + recordEvent(Level.INFO, msg, null, t); + } + + public boolean isInfoEnabled(Marker marker) { + return true; + } + + public void info(Marker marker, String msg) { + recordEvent(Level.INFO, marker, msg, null, null); + } + + public void info(Marker marker, String format, Object arg) { + recordEvent(Level.INFO, marker, format, new Object[] { arg }, null); + } + + public void info(Marker marker, String format, Object arg1, Object arg2) { + recordEvent(Level.INFO, marker, format, new Object[] { arg1, arg2 }, null); + } + + public void info(Marker marker, String format, Object... arguments) { + recordEvent(Level.INFO, marker, format, arguments, null); + } + + public void info(Marker marker, String msg, Throwable t) { + recordEvent(Level.INFO, marker, msg, null, t); + + } + + public boolean isWarnEnabled() { + return true; + } + + public void warn(String msg) { + recordEvent(Level.WARN, msg, null, null); + } + + public void warn(String format, Object arg) { + recordEvent(Level.WARN, format, new Object[] { arg }, null); + + } + + public void warn(String format, Object arg1, Object arg2) { + recordEvent(Level.WARN, format, new Object[] { arg1, arg2 }, null); + } + + public void warn(String format, Object... arguments) { + recordEvent(Level.WARN, format, arguments, null); + } + + public void warn(String msg, Throwable t) { + recordEvent(Level.WARN, msg, null, t); + } + + public boolean isWarnEnabled(Marker marker) { + return true; + } + + public void warn(Marker marker, String msg) { + recordEvent(Level.WARN, msg, null, null); + } + + public void warn(Marker marker, String format, Object arg) { + recordEvent(Level.WARN, format, new Object[] { arg }, null); + } + + public void warn(Marker marker, String format, Object arg1, Object arg2) { + recordEvent(Level.WARN, marker, format, new Object[] { arg1, arg2 }, null); + + } + + public void warn(Marker marker, String format, Object... arguments) { + recordEvent(Level.WARN, marker, format, arguments, null); + } + + public void warn(Marker marker, String msg, Throwable t) { + recordEvent(Level.WARN, marker, msg, null, t); + } + + public boolean isErrorEnabled() { + return true; + } + + public void error(String msg) { + recordEvent(Level.ERROR, msg, null, null); + } + + public void error(String format, Object arg) { + recordEvent(Level.ERROR, format, new Object[] { arg }, null); + + } + + public void error(String format, Object arg1, Object arg2) { + recordEvent(Level.ERROR, format, new Object[] { arg1, arg2 }, null); + + } + + public void error(String format, Object... arguments) { + recordEvent(Level.ERROR, format, arguments, null); + + } + + public void error(String msg, Throwable t) { + recordEvent(Level.ERROR, msg, null, t); + } + + public boolean isErrorEnabled(Marker marker) { + return true; + } + + public void error(Marker marker, String msg) { + recordEvent(Level.ERROR, marker, msg, null, null); + + } + + public void error(Marker marker, String format, Object arg) { + recordEvent(Level.ERROR, marker, format, new Object[] { arg }, null); + + } + + public void error(Marker marker, String format, Object arg1, Object arg2) { + recordEvent(Level.ERROR, marker, format, new Object[] { arg1, arg2 }, null); + } + + public void error(Marker marker, String format, Object... arguments) { + recordEvent(Level.ERROR, marker, format, arguments, null); + } + + public void error(Marker marker, String msg, Throwable t) { + recordEvent(Level.ERROR, marker, msg, null, t); + } + +} diff --git a/slf4j-api/src/main/java/org/slf4j/event/Level.java b/slf4j-api/src/main/java/org/slf4j/event/Level.java new file mode 100644 index 0000000..ee4146c --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/event/Level.java @@ -0,0 +1,37 @@ +package org.slf4j.event; + +import static org.slf4j.event.EventConstants.DEBUG_INT; +import static org.slf4j.event.EventConstants.ERROR_INT; +import static org.slf4j.event.EventConstants.INFO_INT; +import static org.slf4j.event.EventConstants.TRACE_INT; +import static org.slf4j.event.EventConstants.WARN_INT; + +/** + * + * @author ceki + * @since 1.7.15 + */ +public enum Level { + + ERROR(ERROR_INT, "ERROR"), WARN(WARN_INT, "WARN"), INFO(INFO_INT, "INFO"), DEBUG(DEBUG_INT, "DEBUG"), TRACE(TRACE_INT, "TRACE"); + + private int levelInt; + private String levelStr; + + Level(int i, String s) { + levelInt = i; + levelStr = s; + } + + public int toInt() { + return levelInt; + } + + /** + * Returns the string representation of this Level. + */ + public String toString() { + return levelStr; + } + +} diff --git a/slf4j-api/src/main/java/org/slf4j/event/LoggingEvent.java b/slf4j-api/src/main/java/org/slf4j/event/LoggingEvent.java new file mode 100644 index 0000000..d9eabed --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/event/LoggingEvent.java @@ -0,0 +1,28 @@ +package org.slf4j.event; + +import org.slf4j.Marker; + +/** + * + * @author ceki + * @since 1.7.15 + */ +public interface LoggingEvent { + + Level getLevel(); + + Marker getMarker(); + + String getLoggerName(); + + String getMessage(); + + String getThreadName(); + + Object[] getArgumentArray(); + + long getTimeStamp(); + + Throwable getThrowable(); + +} diff --git a/slf4j-api/src/main/java/org/slf4j/event/SubstituteLoggingEvent.java b/slf4j-api/src/main/java/org/slf4j/event/SubstituteLoggingEvent.java new file mode 100644 index 0000000..d352c65 --- /dev/null +++ b/slf4j-api/src/main/java/org/slf4j/event/SubstituteLoggingEvent.java @@ -0,0 +1,89 @@ +package org.slf4j.event; + +import org.slf4j.Marker; +import org.slf4j.helpers.SubstituteLogger; + +public class SubstituteLoggingEvent implements LoggingEvent { + + Level level; + Marker marker; + String loggerName; + SubstituteLogger logger; + String threadName; + String message; + Object[] argArray; + long timeStamp; + Throwable throwable; + + public Level getLevel() { + return level; + } + + public void setLevel(Level level) { + this.level = level; + } + + public Marker getMarker() { + return marker; + } + + public void setMarker(Marker marker) { + this.marker = marker; + } + + public String getLoggerName() { + return loggerName; + } + + public void setLoggerName(String loggerName) { + this.loggerName = loggerName; + } + + public SubstituteLogger getLogger() { + return logger; + } + + public void setLogger(SubstituteLogger logger) { + this.logger = logger; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object[] getArgumentArray() { + return argArray; + } + + public void setArgumentArray(Object[] argArray) { + this.argArray = argArray; + } + + public long getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + } + + public String getThreadName() { + return threadName; + } + + public void setThreadName(String threadName) { + this.threadName = threadName; + } + + public Throwable getThrowable() { + return throwable; + } + + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } +} diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java b/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java index 5f5e69f..2269f5c 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java @@ -44,10 +44,9 @@ */ public class BasicMDCAdapter implements MDCAdapter { - private InheritableThreadLocal> inheritableThreadLocal = - new InheritableThreadLocal>() { + private InheritableThreadLocal> inheritableThreadLocal = new InheritableThreadLocal>() { @Override - protected Map childValue(Map parentValue) { + protected Map childValue(Map parentValue) { if (parentValue == null) { return null; } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/FormattingTuple.java b/slf4j-api/src/main/java/org/slf4j/helpers/FormattingTuple.java index b58270f..8d34f73 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/FormattingTuple.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/FormattingTuple.java @@ -44,21 +44,7 @@ public FormattingTuple(String message, Object[] argArray, Throwable throwable) { this.message = message; this.throwable = throwable; - if (throwable == null) { - this.argArray = argArray; - } else { - this.argArray = trimmedCopy(argArray); - } - } - - static Object[] trimmedCopy(Object[] argArray) { - if (argArray == null || argArray.length == 0) { - throw new IllegalStateException("non-sensical empty or null argument array"); - } - final int trimemdLen = argArray.length - 1; - Object[] trimmed = new Object[trimemdLen]; - System.arraycopy(argArray, 0, trimmed, 0, trimemdLen); - return trimmed; + this.argArray = argArray; } public String getMessage() { diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java b/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java index d5a5051..3b7557b 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java @@ -33,14 +33,14 @@ /** * Formats messages according to very simple substitution rules. Substitutions * can be made 1, 2 or more arguments. - * + * *

* For example, - * + * *

  * MessageFormatter.format("Hi {}.", "there")
  * 
- * + * * will return the string "Hi there.". *

* The {} pair is called the formatting anchor. It serves to designate @@ -50,48 +50,48 @@ * In case your message contains the '{' or the '}' character, you do not have * to do anything special unless the '}' character immediately follows '{'. For * example, - * + * *

  * MessageFormatter.format("Set {1,2,3} is not equal to {}.", "1,2");
  * 
- * + * * will return the string "Set {1,2,3} is not equal to 1,2.". - * + * *

* If for whatever reason you need to place the string "{}" in the message * without its formatting anchor meaning, then you need to escape the * '{' character with '\', that is the backslash character. Only the '{' * character should be escaped. There is no need to escape the '}' character. * For example, - * + * *

  * MessageFormatter.format("Set \\{} is not equal to {}.", "1,2");
  * 
- * + * * will return the string "Set {} is not equal to 1,2.". - * + * *

* The escaping behavior just described can be overridden by escaping the escape * character '\'. Calling - * + * *

  * MessageFormatter.format("File name is C:\\\\{}.", "file.zip");
  * 
- * + * * will return the string "File name is C:\file.zip". - * + * *

* The formatting conventions are different than those of {@link MessageFormat} * which ships with the Java platform. This is justified by the fact that * SLF4J's implementation is 10 times faster than that of {@link MessageFormat}. * This local performance difference is both measurable and significant in the * larger context of the complete logging processing chain. - * + * *

* See also {@link #format(String, Object)}, * {@link #format(String, Object, Object)} and * {@link #arrayFormat(String, Object[])} methods for more details. - * + * * @author Ceki Gülcü * @author Joern Huxhorn */ @@ -106,17 +106,17 @@ * parameter. *

* For example, - * + * *

      * MessageFormatter.format("Hi {}.", "there");
      * 
- * + * * will return the string "Hi there.". *

- * + * * @param messagePattern * The message pattern which will be parsed and formatted - * @param argument + * @param arg * The argument to be substituted in place of the formatting anchor * @return The formatted message */ @@ -125,18 +125,18 @@ } /** - * + * * Performs a two argument substitution for the 'messagePattern' passed as * parameter. *

* For example, - * + * *

      * MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");
      * 
- * + * * will return the string "Hi Alice. My name is Bob.". - * + * * @param messagePattern * The message pattern which will be parsed and formatted * @param arg1 @@ -151,6 +151,7 @@ return arrayFormat(messagePattern, new Object[] { arg1, arg2 }); } + static final Throwable getThrowableCandidate(Object[] argArray) { if (argArray == null || argArray.length == 0) { return null; @@ -163,24 +164,29 @@ return null; } - /** - * Same principle as the {@link #format(String, Object)} and - * {@link #format(String, Object, Object)} methods except that any number of - * arguments can be passed in an array. - * - * @param messagePattern - * The message pattern which will be parsed and formatted - * @param argArray - * An array of arguments to be substituted in place of formatting - * anchors - * @return The formatted message - */ final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray) { - Throwable throwableCandidate = getThrowableCandidate(argArray); + Object[] args = argArray; + if (throwableCandidate != null) { + args = trimmedCopy(argArray); + } + return arrayFormat(messagePattern, args, throwableCandidate); + } + + private static Object[] trimmedCopy(Object[] argArray) { + if (argArray == null || argArray.length == 0) { + throw new IllegalStateException("non-sensical empty or null argument array"); + } + final int trimemdLen = argArray.length - 1; + Object[] trimmed = new Object[trimemdLen]; + System.arraycopy(argArray, 0, trimmed, 0, trimemdLen); + return trimmed; + } + + final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray, Throwable throwable) { if (messagePattern == null) { - return new FormattingTuple(null, argArray, throwableCandidate); + return new FormattingTuple(null, argArray, throwable); } if (argArray == null) { @@ -200,11 +206,11 @@ if (j == -1) { // no more variables if (i == 0) { // this is a simple string - return new FormattingTuple(messagePattern, argArray, throwableCandidate); + return new FormattingTuple(messagePattern, argArray, throwable); } else { // add the tail string which contains no variables and return // the result. sbuf.append(messagePattern, i, messagePattern.length()); - return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate); + return new FormattingTuple(sbuf.toString(), argArray, throwable); } } else { if (isEscapedDelimeter(messagePattern, j)) { @@ -231,11 +237,7 @@ } // append the characters following the last {} pair. sbuf.append(messagePattern, i, messagePattern.length()); - if (L < argArray.length - 1) { - return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate); - } else { - return new FormattingTuple(sbuf.toString(), argArray, null); - } + return new FormattingTuple(sbuf.toString(), argArray, throwable); } final static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) { @@ -297,8 +299,7 @@ String oAsString = o.toString(); sbuf.append(oAsString); } catch (Throwable t) { - System.err.println("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]"); - t.printStackTrace(); + Util.report("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]", t); sbuf.append("[FAILED toString()]"); } @@ -409,4 +410,5 @@ } sbuf.append(']'); } + } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java index 8a6ce3a..2de429b 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLogger.java @@ -24,26 +24,38 @@ */ package org.slf4j.helpers; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Queue; + import org.slf4j.Logger; import org.slf4j.Marker; +import org.slf4j.event.EventRecodingLogger; +import org.slf4j.event.LoggingEvent; +import org.slf4j.event.SubstituteLoggingEvent; /** * A logger implementation which logs via a delegate logger. By default, the delegate is a - * {@link NOPLogger}. However, a different delegate can be set at anytime. + * {@link NOPLogger}. However, a different delegate can be set at any time. *

* See also the relevant * error code documentation. * * @author Chetan Mehrotra + * @author Ceki Gulcu */ public class SubstituteLogger implements Logger { private final String name; - private volatile Logger _delegate; - - public SubstituteLogger(String name) { + private Boolean delegateEventAware; + private Method logMethodCache; + private EventRecodingLogger eventRecodingLogger; + private Queue eventQueue; + + public SubstituteLogger(String name, Queue eventQueue) { this.name = name; + this.eventQueue = eventQueue; } public String getName() { @@ -315,7 +327,14 @@ * instance. */ Logger delegate() { - return _delegate != null ? _delegate : NOPLogger.NOP_LOGGER; + return _delegate != null ? _delegate : getEventRecordingLogger(); + } + + private Logger getEventRecordingLogger() { + if (eventRecodingLogger == null) { + eventRecodingLogger = new EventRecodingLogger(this, eventQueue); + } + return eventRecodingLogger; } /** @@ -325,4 +344,37 @@ public void setDelegate(Logger delegate) { this._delegate = delegate; } + + public boolean isDelegateEventAware() { + if (delegateEventAware != null) + return delegateEventAware; + + try { + logMethodCache = _delegate.getClass().getMethod("log", LoggingEvent.class); + delegateEventAware = Boolean.TRUE; + } catch (NoSuchMethodException e) { + delegateEventAware = Boolean.FALSE; + } + return delegateEventAware; + } + + public void log(LoggingEvent event) { + if (isDelegateEventAware()) { + try { + logMethodCache.invoke(_delegate, event); + } catch (IllegalAccessException e) { + } catch (IllegalArgumentException e) { + } catch (InvocationTargetException e) { + } + } + } + + + public boolean isDelegateNull() { + return _delegate == null; + } + + public boolean isDelegateNOP() { + return _delegate instanceof NOPLogger; + } } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java index 480ce24..37f7491 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/SubstituteLoggerFactory.java @@ -24,13 +24,15 @@ */ package org.slf4j.helpers; -import org.slf4j.ILoggerFactory; -import org.slf4j.Logger; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.LinkedBlockingQueue; + +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; +import org.slf4j.event.SubstituteLoggingEvent; /** * SubstituteLoggerFactory manages instances of {@link SubstituteLogger}. @@ -42,10 +44,12 @@ final ConcurrentMap loggers = new ConcurrentHashMap(); + final LinkedBlockingQueue eventQueue = new LinkedBlockingQueue(); + public Logger getLogger(String name) { SubstituteLogger logger = loggers.get(name); if (logger == null) { - logger = new SubstituteLogger(name); + logger = new SubstituteLogger(name, eventQueue); SubstituteLogger oldLogger = loggers.putIfAbsent(name, logger); if (oldLogger != null) logger = oldLogger; @@ -61,7 +65,12 @@ return new ArrayList(loggers.values()); } + public LinkedBlockingQueue getEventQueue() { + return eventQueue; + } + public void clear() { loggers.clear(); + eventQueue.clear(); } } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/Util.java b/slf4j-api/src/main/java/org/slf4j/helpers/Util.java index 7cdf076..99784ae 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/Util.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/Util.java @@ -69,19 +69,19 @@ private static ClassContextSecurityManager SECURITY_MANAGER; private static boolean SECURITY_MANAGER_CREATION_ALREADY_ATTEMPTED = false; - + private static ClassContextSecurityManager getSecurityManager() { - if(SECURITY_MANAGER != null) + if (SECURITY_MANAGER != null) return SECURITY_MANAGER; - else if(SECURITY_MANAGER_CREATION_ALREADY_ATTEMPTED) + else if (SECURITY_MANAGER_CREATION_ALREADY_ATTEMPTED) return null; else { - SECURITY_MANAGER = safeCreateSecurityManager(); + SECURITY_MANAGER = safeCreateSecurityManager(); SECURITY_MANAGER_CREATION_ALREADY_ATTEMPTED = true; return SECURITY_MANAGER; } } - + private static ClassContextSecurityManager safeCreateSecurityManager() { try { return new ClassContextSecurityManager(); @@ -97,7 +97,7 @@ */ public static Class getCallingClass() { ClassContextSecurityManager securityManager = getSecurityManager(); - if(securityManager == null) + if (securityManager == null) return null; Class[] trace = securityManager.getClassContext(); String thisClassName = Util.class.getName(); diff --git a/slf4j-api/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/slf4j-api/src/main/java/org/slf4j/impl/StaticLoggerBinder.java index e044d53..cadfab5 100644 --- a/slf4j-api/src/main/java/org/slf4j/impl/StaticLoggerBinder.java +++ b/slf4j-api/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -27,13 +27,13 @@ import org.slf4j.ILoggerFactory; /** - * The binding of {@link LoggerFactory} class with an actual instance of + * The binding of {@link org.slf4j.LoggerFactory} class with an actual instance of * {@link ILoggerFactory} is performed using information returned by this class. - * - * This class is meant to provide a dummy StaticLoggerBinder to the slf4j-api module. - * Real implementations are found in each SLF4J binding project, e.g. slf4j-nop, + * + * This class is meant to provide a dummy StaticLoggerBinder to the slf4j-api module. + * Real implementations are found in each SLF4J binding project, e.g. slf4j-nop, * slf4j-log4j12 etc. - * + * * @author Ceki Gülcü */ public class StaticLoggerBinder { @@ -45,7 +45,7 @@ /** * Return the singleton of this class. - * + * * @return the StaticLoggerBinder singleton */ public static final StaticLoggerBinder getSingleton() { @@ -53,8 +53,8 @@ } /** - * Declare the version of the SLF4J API this implementation is compiled against. - * The value of this field is modified with each major release. + * Declare the version of the SLF4J API this implementation is compiled against. + * The value of this field is modified with each major release. */ // to avoid constant folding by the compiler, this field must *not* be final public static String REQUESTED_API_VERSION = "1.6.99"; // !final diff --git a/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java index fc26bf5..e837a2b 100644 --- a/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-api/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -42,7 +42,7 @@ private StaticMDCBinder() { throw new UnsupportedOperationException("This code should never make it into the jar"); } - + /** * Return the singleton of this class. * @@ -50,7 +50,7 @@ * @since 1.7.14 */ public static final StaticMDCBinder getSingleton() { - return SINGLETON; + return SINGLETON; } /** diff --git a/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 211f78d..c19914b 100644 --- a/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-api/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -60,7 +60,7 @@ public static StaticMarkerBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMarkerFactory}. diff --git a/slf4j-api/src/main/java/org/slf4j/spi/LocationAwareLogger.java b/slf4j-api/src/main/java/org/slf4j/spi/LocationAwareLogger.java index d1dd548..925e0ea 100644 --- a/slf4j-api/src/main/java/org/slf4j/spi/LocationAwareLogger.java +++ b/slf4j-api/src/main/java/org/slf4j/spi/LocationAwareLogger.java @@ -39,6 +39,8 @@ */ public interface LocationAwareLogger extends Logger { + // these constants should be in EventContants. However, in order to preserve binary backward compatibility + // we keep these constants here final public int TRACE_INT = 00; final public int DEBUG_INT = 10; final public int INFO_INT = 20; diff --git a/slf4j-api/src/main/resources/META-INF/MANIFEST.MF b/slf4j-api/src/main/resources/META-INF/MANIFEST.MF index 96ba98c..def3812 100644 --- a/slf4j-api/src/main/resources/META-INF/MANIFEST.MF +++ b/slf4j-api/src/main/resources/META-INF/MANIFEST.MF @@ -4,5 +4,8 @@ Bundle-Name: slf4j-api Bundle-Vendor: SLF4J.ORG Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Export-Package: org.slf4j;version=${parsedVersion.osgiVersion}, org.slf4j.spi;version=${parsedVersion.osgiVersion}, org.slf4j.helpers;version=${parsedVersion.osgiVersion} +Export-Package: org.slf4j;version=${parsedVersion.osgiVersion}, + org.slf4j.spi;version=${parsedVersion.osgiVersion}, + org.slf4j.helpers;version=${parsedVersion.osgiVersion}, + org.slf4j.event;version=${parsedVersion.osgiVersion} Import-Package: org.slf4j.impl;version=${slf4j.api.minimum.compatible.version} diff --git a/slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java b/slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java index 7e855bb..218262b 100644 --- a/slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java +++ b/slf4j-api/src/test/java/org/slf4j/BasicMarkerTest.java @@ -37,7 +37,7 @@ * @author Ceki Gülcü * @author Joern Huxhorn */ -public class BasicMarkerTest { +public class BasicMarkerTest { static final String BLUE_STR = "BLUE"; static final String RED_STR = "RED"; static final String GREEN_STR = "GREEN"; diff --git a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava b/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava new file mode 100644 index 0000000..9c3fdd2 --- /dev/null +++ b/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava @@ -0,0 +1,55 @@ +package org.slf4j; + +import org.junit.Ignore; +import org.junit.Test; + +public class FindStaticLoggerBinderPathsPerfTest { + + @Test + @Ignore + public void test() { + long duration = timeFindBindingSetCall(); + System.out.println(duration / (1000) + " microseconds"); + + int count = 10; + long sum = 0; + for (int i = 0; i < count; i++) { + sum += timeFindBindingSetCall(); + } + System.out.println(sum / (count * 1000) + " microseconds in average"); + } + + @Test + public void testAsync() throws InterruptedException { + long start = System.nanoTime(); + FindPathSetThread thread = new FindPathSetThread(); + thread.start(); + long end = System.nanoTime(); + + long duration = end - start; + System.out.println(duration / (1000) + " microseconds"); + + thread.join(); + } + + long timeFindBindingSetCall() { + long start = System.nanoTime(); + + LoggerFactory.findPossibleStaticLoggerBinderPathSet(); + long end = System.nanoTime(); + return end - start; + + } + + static class FindPathSetThread extends Thread { + + public void run() { + long start = System.nanoTime(); + LoggerFactory.findPossibleStaticLoggerBinderPathSet(); + long end = System.nanoTime(); + + System.out.println("Found set in " + (end - start)/1000 + " microseconds"); + + } + } +} diff --git a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.java b/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.java deleted file mode 100644 index 9c3fdd2..0000000 --- a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.slf4j; - -import org.junit.Ignore; -import org.junit.Test; - -public class FindStaticLoggerBinderPathsPerfTest { - - @Test - @Ignore - public void test() { - long duration = timeFindBindingSetCall(); - System.out.println(duration / (1000) + " microseconds"); - - int count = 10; - long sum = 0; - for (int i = 0; i < count; i++) { - sum += timeFindBindingSetCall(); - } - System.out.println(sum / (count * 1000) + " microseconds in average"); - } - - @Test - public void testAsync() throws InterruptedException { - long start = System.nanoTime(); - FindPathSetThread thread = new FindPathSetThread(); - thread.start(); - long end = System.nanoTime(); - - long duration = end - start; - System.out.println(duration / (1000) + " microseconds"); - - thread.join(); - } - - long timeFindBindingSetCall() { - long start = System.nanoTime(); - - LoggerFactory.findPossibleStaticLoggerBinderPathSet(); - long end = System.nanoTime(); - return end - start; - - } - - static class FindPathSetThread extends Thread { - - public void run() { - long start = System.nanoTime(); - LoggerFactory.findPossibleStaticLoggerBinderPathSet(); - long end = System.nanoTime(); - - System.out.println("Found set in " + (end - start)/1000 + " microseconds"); - - } - } -} diff --git a/slf4j-api/src/test/java/org/slf4j/NoBindingTest.java b/slf4j-api/src/test/java/org/slf4j/NoBindingTest.java index c9f85e6..467278f 100644 --- a/slf4j-api/src/test/java/org/slf4j/NoBindingTest.java +++ b/slf4j-api/src/test/java/org/slf4j/NoBindingTest.java @@ -45,7 +45,7 @@ } @Test - public void testMDC() { + public void testMDC() { MDC.put("k" + diff, "v"); assertNull(MDC.get("k")); } diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java index d0df4c0..1c1d09e 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/BasicMDCAdapterTest.java @@ -41,7 +41,7 @@ * * @author Lukasz Cwik */ -public class BasicMDCAdapterTest { +public class BasicMDCAdapterTest { MDCAdapter mdc = new BasicMDCAdapter(); @After @@ -55,7 +55,7 @@ mdc.put("testKey", "testValue"); assertEquals(mdc.get("testKey"), "testValue"); } - + @Test public void testOverwritingAKeyInMDC() { assertNull(mdc.get("testKey")); diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java index 21b6a24..7e8b057 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterPerfTest.java @@ -30,7 +30,7 @@ import org.junit.Test; @Ignore -public class MessageFormatterPerfTest{ //extends TestCase { +public class MessageFormatterPerfTest { // extends TestCase { Integer i1 = new Integer(1); Integer i2 = new Integer(2); diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java index 8cf7249..76a1d19 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java @@ -311,14 +311,20 @@ assertTrue(Arrays.equals(iaWitness, ft.getArgArray())); assertEquals(t, ft.getThrowable()); - ft = MessageFormatter.arrayFormat("Value {} is smaller than {} and {} -- {} .", ia); - assertEquals("Value 1 is smaller than 2 and 3 -- " + t.toString() + " .", ft.getMessage()); - assertTrue(Arrays.equals(ia, ft.getArgArray())); - assertNull(ft.getThrowable()); + ft = MessageFormatter.arrayFormat("Value {} is smaller than {} and {}.", ia); + assertEquals("Value 1 is smaller than 2 and 3.", ft.getMessage()); + assertTrue(Arrays.equals(iaWitness, ft.getArgArray())); + assertEquals(t, ft.getThrowable()); ft = MessageFormatter.arrayFormat("{}{}{}{}", ia); - assertEquals("123" + t.toString(), ft.getMessage()); - assertTrue(Arrays.equals(ia, ft.getArgArray())); - assertNull(ft.getThrowable()); + assertEquals("123{}", ft.getMessage()); + assertTrue(Arrays.equals(iaWitness, ft.getArgArray())); + assertEquals(t, ft.getThrowable()); + + ft = MessageFormatter.arrayFormat("1={}", new Object[] { i1 }, t); + assertEquals("1=1", ft.getMessage()); + assertTrue(Arrays.equals(new Object[] { i1 }, ft.getArgArray())); + assertEquals(t, ft.getThrowable()); + } } diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java index ab076fc..0df5336 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstitutableLoggerTest.java @@ -39,6 +39,7 @@ import org.junit.Test; import org.slf4j.Logger; +import org.slf4j.event.EventRecodingLogger; /** * @author Chetan Mehrotra @@ -48,8 +49,8 @@ @Test public void testDelegate() throws Exception { - SubstituteLogger log = new SubstituteLogger("foo"); - assertTrue(log.delegate() instanceof NOPLogger); + SubstituteLogger log = new SubstituteLogger("foo", null); + assertTrue(log.delegate() instanceof EventRecodingLogger); Set expectedMethodSignatures = determineMethodSignatures(Logger.class); LoggerInvocationHandler ih = new LoggerInvocationHandler(); diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java index 246f9c4..620af1b 100644 --- a/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java +++ b/slf4j-api/src/test/java/org/slf4j/helpers/SubstituteLoggerFactoryTest.java @@ -35,7 +35,7 @@ import java.util.HashSet; import java.util.Set; -public class SubstituteLoggerFactoryTest { +public class SubstituteLoggerFactoryTest { private SubstituteLoggerFactory factory = new SubstituteLoggerFactory(); @Test diff --git a/slf4j-ext/pom.xml b/slf4j-ext/pom.xml index 23c39ef..0d0ec4f 100644 --- a/slf4j-ext/pom.xml +++ b/slf4j-ext/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-ext diff --git a/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java b/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java index f8fea78..80ecebf 100644 --- a/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java +++ b/slf4j-ext/src/main/java/org/slf4j/agent/AgentPremain.java @@ -34,16 +34,14 @@ /** * Entry point for slf4j-ext when used as a Java agent. - * + * */ public class AgentPremain { /** * JavaAgent premain entry point as specified in the MANIFEST.MF file. See - * {@link http - * ://java.sun.com/javase/6/docs/api/java/lang/instrument/package- - * summary.html} for details. - * + * http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html for details. + * * @param agentArgument * string provided after "=" up to first space * @param instrumentation @@ -85,8 +83,8 @@ * Consider the argument string to be a property file (by converting the * splitter character to line feeds), and then reading it like any other * property file. - * - * + * + * * @param agentArgument * string given by instrumentation framework * @param separator @@ -109,7 +107,7 @@ * Print the start message to System.err with the time NOW, and register a * shutdown hook which will print the stop message to System.err with the * time then and the number of milliseconds passed since. - * + * */ private static void printStartStopTimes() { final long start = System.currentTimeMillis(); @@ -125,4 +123,4 @@ }; Runtime.getRuntime().addShutdownHook(hook); } -} \ No newline at end of file +} diff --git a/slf4j-ext/src/main/java/org/slf4j/cal10n/LocLoggerFactory.java b/slf4j-ext/src/main/java/org/slf4j/cal10n/LocLoggerFactory.java index 126f98e..4ddff60 100644 --- a/slf4j-ext/src/main/java/org/slf4j/cal10n/LocLoggerFactory.java +++ b/slf4j-ext/src/main/java/org/slf4j/cal10n/LocLoggerFactory.java @@ -30,19 +30,19 @@ import ch.qos.cal10n.IMessageConveyor; /** - * + * * This class is essentially a wrapper around an {@link LoggerFactory} producing * {@link LocLogger} instances. - * + * *

* Contrary to {@link LoggerFactory#getLogger(String)} method of - * {@link LoggerFactory}, each call to {@link getLocLogger} produces a new + * {@link LoggerFactory}, each call to {@link #getLocLogger(String)} produces a new * instance of {@link LocLogger}. This should not matter because a LocLogger - * instance does have any state beyond that of the {@link Logger} in stance it + * instance does have any state beyond that of the {@link Logger} instance it * wraps and its message conveyor. - * + * * @author Ceki Gücü - * + * */ public class LocLoggerFactory { @@ -54,7 +54,7 @@ /** * Get an LocLogger instance by name. - * + * * @param name * @return LocLogger instance by name. */ @@ -65,7 +65,7 @@ /** * Get a new LocLogger instance by class. The returned LocLogger will be named * after the class. - * + * * @param clazz * @return LocLogger instance by class */ diff --git a/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java b/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java index f9a4c82..050084e 100644 --- a/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java +++ b/slf4j-ext/src/main/java/org/slf4j/instrumentation/LogTransformer.java @@ -23,7 +23,7 @@ * */ /** - * + * */ package org.slf4j.instrumentation; @@ -57,17 +57,16 @@ /** * Builder provides a flexible way of configuring some of many options on the * parent class instead of providing many constructors. - * - * {@link http - * ://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html} - * + * + * http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html + * */ public static class Builder { /** * Build and return the LogTransformer corresponding to the options set in * this Builder. - * + * * @return */ public LogTransformer build() { @@ -82,7 +81,7 @@ /** * Should each method log entry (with parameters) and exit (with parameters * and returnvalue)? - * + * * @param b * value of flag * @return @@ -105,7 +104,7 @@ /** * Should LogTransformer be verbose in what it does? This currently list the * names of the classes being processed. - * + * * @param b * @return */ @@ -177,7 +176,7 @@ * transform0 sees if the className starts with any of the namespaces to * ignore, if so it is returned unchanged. Otherwise it is processed by * doClass(...) - * + * * @param className * @param clazz * @param domain @@ -227,7 +226,7 @@ * defined have bodies, and a static final logger object is added with the * name of this class as an argument, and each method then gets processed with * doMethod(...) to have logger calls added. - * + * * @param name * class name (slashes separate, not dots) * @param clazz @@ -285,7 +284,7 @@ /** * process a single method - this means add entry/exit logging if requested. * It is only called for methods with a body. - * + * * @param method * method to work on * @throws NotFoundException @@ -310,4 +309,4 @@ method.insertAfter(after); } } -} \ No newline at end of file +} diff --git a/slf4j-ext/src/test/java/org/slf4j/NDCTest.java b/slf4j-ext/src/test/java/org/slf4j/NDCTest.java index f919a4b..4adfd31 100644 --- a/slf4j-ext/src/test/java/org/slf4j/NDCTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/NDCTest.java @@ -41,14 +41,12 @@ assertEquals("", NDC.pop()); } - @Test public void testSmoke() { NDC.push("a"); String result = NDC.pop(); assertEquals("a", result); } - @Test public void testSmoke2() { diff --git a/slf4j-ext/src/test/java/org/slf4j/cal10n_dummy/LocLoggerTest.java b/slf4j-ext/src/test/java/org/slf4j/cal10n_dummy/LocLoggerTest.java index c6c6e00..d80a7de 100644 --- a/slf4j-ext/src/test/java/org/slf4j/cal10n_dummy/LocLoggerTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/cal10n_dummy/LocLoggerTest.java @@ -37,7 +37,8 @@ import ch.qos.cal10n.IMessageConveyor; import ch.qos.cal10n.MessageConveyor; -public class LocLoggerTest { + +public class LocLoggerTest { ListAppender listAppender; org.apache.log4j.Logger log4jRoot; @@ -46,7 +47,6 @@ LocLoggerFactory llFactory_uk = new LocLoggerFactory(imc); final static String EXPECTED_FILE_NAME = "LocLoggerTest.java"; - @Before public void setUp() throws Exception { @@ -64,7 +64,6 @@ assertEquals(EXPECTED_FILE_NAME, le.getLocationInformation().getFileName()); } - @Test public void testSmoke() { LocLogger locLogger = llFactory_uk.getLocLogger(this.getClass()); diff --git a/slf4j-ext/src/test/java/org/slf4j/dummyExt/EventLoggerTest.java b/slf4j-ext/src/test/java/org/slf4j/dummyExt/EventLoggerTest.java index 40d5976..b65b33f 100644 --- a/slf4j-ext/src/test/java/org/slf4j/dummyExt/EventLoggerTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/dummyExt/EventLoggerTest.java @@ -38,13 +38,13 @@ import org.slf4j.MDC; import org.slf4j.ext.EventData; import org.slf4j.ext.EventLogger; -public class EventLoggerTest { + +public class EventLoggerTest { ListAppender listAppender; org.apache.log4j.Logger log4; final static String EXPECTED_FILE_NAME = "EventLoggerTest.java"; - @Before public void setUp() throws Exception { @@ -76,7 +76,7 @@ assertEquals(expectedMsg, le.getMessage()); assertEquals(EXPECTED_FILE_NAME, le.getLocationInformation().getFileName()); } - + @Test public void testEventLogger() { EventData data[] = new EventData[2]; diff --git a/slf4j-ext/src/test/java/org/slf4j/dummyExt/MDCStrLookupTest.java b/slf4j-ext/src/test/java/org/slf4j/dummyExt/MDCStrLookupTest.java index db77298..d5a0a38 100644 --- a/slf4j-ext/src/test/java/org/slf4j/dummyExt/MDCStrLookupTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/dummyExt/MDCStrLookupTest.java @@ -29,7 +29,8 @@ import org.junit.Test; import org.slf4j.MDC; import org.slf4j.ext.MDCStrLookup; -public class MDCStrLookupTest { + +public class MDCStrLookupTest { @Test public void testLookup() throws Exception { diff --git a/slf4j-ext/src/test/java/org/slf4j/dummyExt/PackageTest.java b/slf4j-ext/src/test/java/org/slf4j/dummyExt/PackageTest.java index 56fb103..8c9e39e 100644 --- a/slf4j-ext/src/test/java/org/slf4j/dummyExt/PackageTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/dummyExt/PackageTest.java @@ -24,8 +24,6 @@ */ package org.slf4j.dummyExt; -import junit.framework.*; - import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; diff --git a/slf4j-ext/src/test/java/org/slf4j/instrumentation/ToStringHelperTest.java b/slf4j-ext/src/test/java/org/slf4j/instrumentation/ToStringHelperTest.java index 7c41a74..9e8a63e 100644 --- a/slf4j-ext/src/test/java/org/slf4j/instrumentation/ToStringHelperTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/instrumentation/ToStringHelperTest.java @@ -28,7 +28,7 @@ import org.junit.Test; -public class ToStringHelperTest { +public class ToStringHelperTest { @Test public void testRenderer() { diff --git a/slf4j-ext/src/test/java/org/slf4j/profiler/PackageTest.java b/slf4j-ext/src/test/java/org/slf4j/profiler/PackageTest.java index 1c2b09c..a0963b0 100644 --- a/slf4j-ext/src/test/java/org/slf4j/profiler/PackageTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/profiler/PackageTest.java @@ -29,9 +29,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({UtilTest.class, - ProfilerTest.class}) +@SuiteClasses({ UtilTest.class, ProfilerTest.class }) public class PackageTest { - }diff --git a/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerTest.java b/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerTest.java index cd1ec3c..13d557d 100644 --- a/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerTest.java +++ b/slf4j-ext/src/test/java/org/slf4j/profiler/ProfilerTest.java @@ -31,6 +31,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + public class ProfilerTest { Logger logger = LoggerFactory.getLogger(ProfilerTest.class); diff --git a/slf4j-jcl/pom.xml b/slf4j-jcl/pom.xml index 3bb0aff..63a4227 100644 --- a/slf4j-jcl/pom.xml +++ b/slf4j-jcl/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-jcl diff --git a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java index 67a81f4..70ef3c4 100644 --- a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java +++ b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -57,7 +57,6 @@ // to avoid constant folding by the compiler, this field must *not* be final public static String REQUESTED_API_VERSION = "1.6.99"; // !final - // Binding specific code: private static final String loggerFactoryClassStr = JCLLoggerFactory.class.getName(); diff --git a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 98218ed..21a48df 100644 --- a/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-jcl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -57,7 +57,7 @@ public static StaticMarkerBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMarkerFactory}. diff --git a/slf4j-jcl/src/test/java/org/slf4j/InvocationTest.java b/slf4j-jcl/src/test/java/org/slf4j/InvocationTest.java index dcc294f..50b74d7 100644 --- a/slf4j-jcl/src/test/java/org/slf4j/InvocationTest.java +++ b/slf4j-jcl/src/test/java/org/slf4j/InvocationTest.java @@ -42,7 +42,6 @@ Level oldLevel; java.util.logging.Logger root = java.util.logging.Logger.getLogger(""); - @Before public void setUp() throws Exception { diff --git a/slf4j-jdk14/pom.xml b/slf4j-jdk14/pom.xml index 0faf805..032a21b 100644 --- a/slf4j-jdk14/pom.xml +++ b/slf4j-jdk14/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-jdk14 diff --git a/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerAdapter.java b/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerAdapter.java index 6122284..7cfafc8 100644 --- a/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerAdapter.java +++ b/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerAdapter.java @@ -29,6 +29,8 @@ import org.slf4j.Logger; import org.slf4j.Marker; +import org.slf4j.event.EventConstants; +import org.slf4j.event.LoggingEvent; import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MarkerIgnoringBase; import org.slf4j.helpers.MessageFormatter; @@ -574,11 +576,10 @@ LogRecord record = new LogRecord(level, msg); record.setLoggerName(getName()); record.setThrown(t); - // Note: parameters in record are not set because SLF4J only + // Note: parameters in record are not set because SLF4J only // supports a single formatting style fillCallerData(callerFQCN, record); logger.log(record); - } static String SELF = JDK14LoggerAdapter.class.getName(); @@ -621,8 +622,20 @@ } public void log(Marker marker, String callerFQCN, int level, String message, Object[] argArray, Throwable t) { + Level julLevel = slf4jLevelIntToJULLevel(level); + // the logger.isLoggable check avoids the unconditional + // construction of location data for disabled log + // statements. As of 2008-07-31, callers of this method + // do not perform this check. See also + // http://jira.qos.ch/browse/SLF4J-81 + if (logger.isLoggable(julLevel)) { + log(callerFQCN, julLevel, message, t); + } + } + + private Level slf4jLevelIntToJULLevel(int slf4jLevelInt) { Level julLevel; - switch (level) { + switch (slf4jLevelInt) { case LocationAwareLogger.TRACE_INT: julLevel = Level.FINEST; break; @@ -639,15 +652,43 @@ julLevel = Level.SEVERE; break; default: - throw new IllegalStateException("Level number " + level + " is not recognized."); - } - // the logger.isLoggable check avoids the unconditional - // construction of location data for disabled log - // statements. As of 2008-07-31, callers of this method - // do not perform this check. See also - // http://jira.qos.ch/browse/SLF4J-81 + throw new IllegalStateException("Level number " + slf4jLevelInt + " is not recognized."); + } + return julLevel; + } + + /** + * @since 1.7.15 + */ + public void log(LoggingEvent event) { + Level julLevel = slf4jLevelIntToJULLevel(event.getLevel().toInt()); if (logger.isLoggable(julLevel)) { - log(callerFQCN, julLevel, message, t); - } + LogRecord record = eventToRecord(event, julLevel); + logger.log(record); + } + } + + private LogRecord eventToRecord(LoggingEvent event, Level julLevel) { + String format = event.getMessage(); + Object[] arguments = event.getArgumentArray(); + FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); + if (ft.getThrowable() != null && event.getThrowable() != null) { + throw new IllegalArgumentException("both last element in argument array and last argument are of type Throwable"); + } + + Throwable t = event.getThrowable(); + if (ft.getThrowable() != null) { + t = ft.getThrowable(); + throw new IllegalStateException("fix above code"); + } + + LogRecord record = new LogRecord(julLevel, ft.getMessage()); + record.setLoggerName(event.getLoggerName()); + record.setMillis(event.getTimeStamp()); + record.setSourceClassName(EventConstants.NA_SUBST); + record.setSourceMethodName(EventConstants.NA_SUBST); + + record.setThrown(t); + return record; } } diff --git a/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerFactory.java b/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerFactory.java index f8f794e..ba6c179 100644 --- a/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerFactory.java +++ b/slf4j-jdk14/src/main/java/org/slf4j/impl/JDK14LoggerFactory.java @@ -43,6 +43,8 @@ public JDK14LoggerFactory() { loggerMap = new ConcurrentHashMap(); + // ensure jul initialization. see also SLF4J-359 + java.util.logging.LogManager.getLogManager(); } /* diff --git a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 4948a69..0a1dcb4 100644 --- a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -41,7 +41,7 @@ private StaticMDCBinder() { } - + /** * Return the singleton of this class. * @@ -51,7 +51,7 @@ public static final StaticMDCBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMDCAdapter}. diff --git a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 98218ed..21a48df 100644 --- a/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-jdk14/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -57,7 +57,7 @@ public static StaticMarkerBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMarkerFactory}. diff --git a/slf4j-jdk14/src/main/resources/META-INF/MANIFEST.MF b/slf4j-jdk14/src/main/resources/META-INF/MANIFEST.MF index 6249cfc..f7334d1 100644 --- a/slf4j-jdk14/src/main/resources/META-INF/MANIFEST.MF +++ b/slf4j-jdk14/src/main/resources/META-INF/MANIFEST.MF @@ -5,5 +5,8 @@ Bundle-Vendor: SLF4J.ORG Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: org.slf4j.impl;version=${parsedVersion.osgiVersion} -Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, org.slf4j.spi;version=${parsedVersion.osgiVersion}, org.slf4j.helpers;version=${parsedVersion.osgiVersion} +Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, + org.slf4j.spi;version=${parsedVersion.osgiVersion}, + org.slf4j.helpers;version=${parsedVersion.osgiVersion}, + org.slf4j.event;version=${parsedVersion.osgiVersion} Fragment-Host: slf4j.apidiff --git a/slf4j-jdk14/src/test/java/org/slf4j/LoggerFactoryFriend.java b/slf4j-jdk14/src/test/java/org/slf4j/LoggerFactoryFriend.java new file mode 100644 index 0000000..edf5fcf --- /dev/null +++ b/slf4j-jdk14/src/test/java/org/slf4j/LoggerFactoryFriend.java @@ -0,0 +1,7 @@ +package org.slf4j; + +public class LoggerFactoryFriend { + static public void reset() { + LoggerFactory.reset(); + } +} diff --git a/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14AdapterLoggerNameTest.java b/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14AdapterLoggerNameTest.java index 17651d5..4e5273b 100644 --- a/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14AdapterLoggerNameTest.java +++ b/slf4j-jdk14/src/test/java/org/slf4j/impl/JDK14AdapterLoggerNameTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNotNull; +import java.util.Random; import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.logging.Logger; @@ -36,35 +37,45 @@ public class JDK14AdapterLoggerNameTest { private MockHandler mockHandler; - + static Random random = new Random(System.currentTimeMillis()); + long diff = random.nextInt(10000); + String loggerName = "JDK14AdapterLoggerNameTest"+diff; + + Logger logger = Logger.getLogger(loggerName); + @Before public void setUp() throws Exception { - Logger logger = Logger.getLogger("TEST"); - mockHandler = new MockHandler(); - removeHandlers(logger); - logger.addHandler(mockHandler); + Logger logger = Logger.getLogger(loggerName); + addMockHandler(logger); } + + @After public void tearDown() throws Exception { - removeHandlers(Logger.getLogger("TEST")); + removeHandlers(Logger.getLogger(loggerName)); } @Test - public void testLoggerNameusingJdkLogging() throws Exception { - Logger.getLogger("TEST").info("test message"); + public void testLoggerNameUsingJdkLogging() throws Exception { + logger.info("test message"); assertCorrectLoggerName(); - } @Test public void testLoggerNameUsingSlf4j() throws Exception { JDK14LoggerFactory factory = new JDK14LoggerFactory(); - org.slf4j.Logger logger = factory.getLogger("TEST"); + org.slf4j.Logger logger = factory.getLogger(loggerName); logger.info("test message"); assertCorrectLoggerName(); } + private void addMockHandler(Logger logger) { + mockHandler = new MockHandler(); + removeHandlers(logger); + logger.addHandler(mockHandler); + } + private void removeHandlers(Logger logger) { logger.setUseParentHandlers(false); Handler[] handlers = logger.getHandlers(); diff --git a/slf4j-jdk14/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java b/slf4j-jdk14/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java new file mode 100644 index 0000000..16a7647 --- /dev/null +++ b/slf4j-jdk14/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2004-2016 QOS.ch + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package org.slf4j.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.List; +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MultithreadedInitializationTest { + + final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; + + private static AtomicLong EVENT_COUNT = new AtomicLong(0); + + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + + int diff = new Random().nextInt(10000); + String packagePrefix = "org.slf4j.impl.MultithreadedInitializationTest" + diff; + + java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(packagePrefix); + + @Before + public void addRecordingHandler() { + julLogger.addHandler(new RecordingHandler()); + } + + @After + public void tearDown() throws Exception { + Handler[] handlers = julLogger.getHandlers(); + for (int i = 0; i < handlers.length; i++) { + if (handlers[i] instanceof RecordingHandler) { + julLogger.removeHandler(handlers[i]); + } + } + } + + @Test + public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + LoggerAccessingThread[] accessors = harness(); + + for (int i = 0; i < accessors.length; i++) { + LoggerAccessingThread accessor = accessors[i]; + EVENT_COUNT.getAndIncrement(); + if (accessor.logger == null) { + fail("logger for LoggerAccessingThread " + i + " is not set"); + } + accessor.logger.info("post harness"); + } + + Logger logger = LoggerFactory.getLogger(packagePrefix + ".test"); + logger.info("hello"); + EVENT_COUNT.getAndIncrement(); + + List records = getRecordedEvents(); + assertEquals(EVENT_COUNT.get(), records.size()); + } + + private List getRecordedEvents() { + RecordingHandler ra = findRecordingHandler(); + if (ra == null) { + fail("failed to fing RecordingHandler"); + } + return ra.records; + } + + private RecordingHandler findRecordingHandler() { + Handler[] handlers = julLogger.getHandlers(); + for (Handler h : handlers) { + if (h instanceof RecordingHandler) + return (RecordingHandler) h; + } + return null; + } + + private LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { + LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i] = new LoggerAccessingThread(barrier, i); + threads[i].start(); + } + + // trigger barrier + barrier.await(); + + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } + + return threads; + } + + class LoggerAccessingThread extends Thread { + final CyclicBarrier barrier; + volatile Logger logger; + final int count; + + LoggerAccessingThread(CyclicBarrier barrier, int count) { + this.barrier = barrier; + this.count = count; + } + + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + for (int i = 0; i < 64; i++) { + logger = LoggerFactory.getLogger(packagePrefix + ".LoggerAccessingThread" + count + "-" + i); + logger.info("in run method"); + EVENT_COUNT.getAndIncrement(); + } + } + }; + +} diff --git a/slf4j-jdk14/src/test/java/org/slf4j/impl/PerfTest.java b/slf4j-jdk14/src/test/java/org/slf4j/impl/PerfTest.java index 269ffaf..77635f7 100644 --- a/slf4j-jdk14/src/test/java/org/slf4j/impl/PerfTest.java +++ b/slf4j-jdk14/src/test/java/org/slf4j/impl/PerfTest.java @@ -24,17 +24,19 @@ */ package org.slf4j.impl; +import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.helpers.BogoPerf; +@Ignore public class PerfTest { static long REFERENCE_BIPS = 9000; @Test - public void testBug72() { + public void issue63() { int LEN = 1000 * 1000 * 10; debugLoop(LEN); // warm up diff --git a/slf4j-jdk14/src/test/java/org/slf4j/impl/RecordingHandler.java b/slf4j-jdk14/src/test/java/org/slf4j/impl/RecordingHandler.java new file mode 100644 index 0000000..118ccd7 --- /dev/null +++ b/slf4j-jdk14/src/test/java/org/slf4j/impl/RecordingHandler.java @@ -0,0 +1,26 @@ +package org.slf4j.impl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +public class RecordingHandler extends Handler { + + List records = Collections.synchronizedList(new ArrayList()); + + @Override + public void publish(LogRecord record) { + records.add(record); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + +} diff --git a/slf4j-jdk14/src/test/java/org/slf4j/issue/LoggerSerializationTest.java b/slf4j-jdk14/src/test/java/org/slf4j/issue/LoggerSerializationTest.java index 73314fe..41ed758 100644 --- a/slf4j-jdk14/src/test/java/org/slf4j/issue/LoggerSerializationTest.java +++ b/slf4j-jdk14/src/test/java/org/slf4j/issue/LoggerSerializationTest.java @@ -42,7 +42,7 @@ * See http://jira.qos.ch/browse/SLF4J-252 * @author Thorbjorn Ravn Andersen */ -public class LoggerSerializationTest { +public class LoggerSerializationTest { static class LoggerHolder implements Serializable { private static final long serialVersionUID = 1L; diff --git a/slf4j-log4j12/pom.xml b/slf4j-log4j12/pom.xml index bf180c4..f724e09 100644 --- a/slf4j-log4j12/pom.xml +++ b/slf4j-log4j12/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-log4j12 diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerAdapter.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerAdapter.java index 0685a4e..ebd568e 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerAdapter.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerAdapter.java @@ -24,11 +24,16 @@ */ package org.slf4j.impl; +import static org.slf4j.event.EventConstants.NA_SUBST; + import java.io.Serializable; import org.apache.log4j.Level; +import org.apache.log4j.spi.LocationInfo; +import org.apache.log4j.spi.ThrowableInformation; import org.slf4j.Logger; import org.slf4j.Marker; +import org.slf4j.event.LoggingEvent; import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MarkerIgnoringBase; import org.slf4j.helpers.MessageFormatter; @@ -572,6 +577,11 @@ } public void log(Marker marker, String callerFQCN, int level, String msg, Object[] argArray, Throwable t) { + Level log4jLevel = toLog4jLevel(level); + logger.log(callerFQCN, log4jLevel, msg, t); + } + + private Level toLog4jLevel(int level) { Level log4jLevel; switch (level) { case LocationAwareLogger.TRACE_INT: @@ -592,7 +602,34 @@ default: throw new IllegalStateException("Level number " + level + " is not recognized."); } - logger.log(callerFQCN, log4jLevel, msg, t); + return log4jLevel; + } + + public void log(LoggingEvent event) { + Level log4jLevel = toLog4jLevel(event.getLevel().toInt()); + if (!logger.isEnabledFor(log4jLevel)) + return; + + org.apache.log4j.spi.LoggingEvent log4jevent = toLog4jEvent(event, log4jLevel); + logger.callAppenders(log4jevent); + + } + + private org.apache.log4j.spi.LoggingEvent toLog4jEvent(LoggingEvent event, Level log4jLevel) { + + FormattingTuple ft = MessageFormatter.format(event.getMessage(), event.getArgumentArray(), event.getThrowable()); + + LocationInfo locationInfo = new LocationInfo(NA_SUBST, NA_SUBST, NA_SUBST, "0"); + + ThrowableInformation ti = null; + Throwable t = ft.getThrowable(); + if (t != null) + ti = new ThrowableInformation(t); + + org.apache.log4j.spi.LoggingEvent log4jEvent = new org.apache.log4j.spi.LoggingEvent(FQCN, logger, event.getTimeStamp(), log4jLevel, ft.getMessage(), + event.getThreadName(), ti, null, locationInfo, null); + + return log4jEvent; } } diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java index fa1b292..686db90 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java @@ -41,7 +41,7 @@ public class Log4jLoggerFactory implements ILoggerFactory { private static final String LOG4J_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#log4jDelegationLoop"; - + // check for delegation loops static { try { @@ -62,6 +62,8 @@ public Log4jLoggerFactory() { loggerMap = new ConcurrentHashMap(); + // force log4j to initialize + org.apache.log4j.LogManager.getRootLogger(); } /* diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java index 78c8bcd..bb0f065 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -40,7 +40,7 @@ private StaticMDCBinder() { } - + /** * Return the singleton of this class. * @@ -50,7 +50,7 @@ public static final StaticMDCBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link StaticMDCBinder}. diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 98218ed..21a48df 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -57,7 +57,7 @@ public static StaticMarkerBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMarkerFactory}. diff --git a/slf4j-log4j12/src/main/resources/META-INF/MANIFEST.MF b/slf4j-log4j12/src/main/resources/META-INF/MANIFEST.MF index b5be4ce..148ff62 100644 --- a/slf4j-log4j12/src/main/resources/META-INF/MANIFEST.MF +++ b/slf4j-log4j12/src/main/resources/META-INF/MANIFEST.MF @@ -5,5 +5,9 @@ Bundle-Vendor: SLF4J.ORG Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: org.slf4j.impl;version=${parsedVersion.osgiVersion} -Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, org.slf4j.spi;version=${parsedVersion.osgiVersion}, org.slf4j.helpers;version=${parsedVersion.osgiVersion}, org.apache.log4j +Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, + org.slf4j.spi;version=${parsedVersion.osgiVersion}, + org.slf4j.helpers;version=${parsedVersion.osgiVersion}, + org.slf4j.event;version=${parsedVersion.osgiVersion}, + org.apache.log4j Fragment-Host: slf4j.apidiff --git a/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java b/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java index 8bf3453..d687383 100644 --- a/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java +++ b/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java @@ -48,7 +48,6 @@ ListAppender listAppender = new ListAppender(); org.apache.log4j.Logger root; - @Before public void setUp() throws Exception { root = org.apache.log4j.Logger.getRootLogger(); @@ -59,7 +58,7 @@ public void tearDown() throws Exception { root.getLoggerRepository().resetConfiguration(); } - + @Test public void test1() { Logger logger = LoggerFactory.getLogger("test1"); @@ -119,8 +118,8 @@ String[] parameters = null; String msg = "hello {}"; - logger.debug(msg, (Object[]) parameters); - + logger.debug(msg, (Object[]) parameters); + assertEquals(1, listAppender.list.size()); LoggingEvent e = (LoggingEvent) listAppender.list.get(0); assertEquals(msg, e.getMessage()); diff --git a/slf4j-log4j12/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java b/slf4j-log4j12/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java new file mode 100644 index 0000000..c9fde1d --- /dev/null +++ b/slf4j-log4j12/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2004-2011 QOS.ch + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package org.slf4j.impl; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.log4j.LogManager; +import org.apache.log4j.spi.LoggingEvent; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MultithreadedInitializationTest { + + // value of LogManager.DEFAULT_CONFIGURATION_KEY; + static String CONFIG_FILE_KEY = "log4j.configuration"; + + final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; + + private static AtomicLong EVENT_COUNT = new AtomicLong(0); + + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + + int diff = new Random().nextInt(10000); + String loggerName = "org.slf4j.impl.RecursiveInitializationTest"; + + @After + public void tearDown() throws Exception { + System.clearProperty(CONFIG_FILE_KEY); + } + + @Test + public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + System.setProperty(CONFIG_FILE_KEY, "recursiveInitWithActivationDelay.properties"); + LoggerAccessingThread[] accessors = harness(); + + for (LoggerAccessingThread accessor : accessors) { + EVENT_COUNT.getAndIncrement(); + accessor.logger.info("post harness"); + } + + Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff); + logger.info("hello"); + EVENT_COUNT.getAndIncrement(); + + List events = getRecordedEvents(); + // 3 evetns generated by RecursiveAppender + assertEquals(EVENT_COUNT.get() + 3, events.size()); + } + + private List getRecordedEvents() { + org.apache.log4j.Logger root = LogManager.getRootLogger(); + + RecursiveAppender ra = (RecursiveAppender) root.getAppender("RECURSIVE"); + return ra.events; + } + + private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { + LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i] = new LoggerAccessingThread(barrier, i); + threads[i].start(); + } + + barrier.await(); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } + return threads; + } + + static class LoggerAccessingThread extends Thread { + final CyclicBarrier barrier; + Logger logger; + int count; + + LoggerAccessingThread(CyclicBarrier barrier, int count) { + this.barrier = barrier; + this.count = count; + } + + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + for (int i = 0; i < 64; i++) { + logger = LoggerFactory.getLogger(this.getClass().getName() + "-" + count + "-" + i); + logger.info("in run method"); + EVENT_COUNT.getAndIncrement(); + } + } + }; + +} diff --git a/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveAppender.java b/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveAppender.java index 3f1ff5f..267e2b2 100644 --- a/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveAppender.java +++ b/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveAppender.java @@ -24,6 +24,8 @@ */ package org.slf4j.impl; +import java.util.ArrayList; +import java.util.List; import java.util.Random; import org.apache.log4j.AppenderSkeleton; @@ -34,15 +36,20 @@ public class RecursiveAppender extends AppenderSkeleton { int diff = new Random().nextInt(); + int activationDelay = 0; + String loggerName = "org.slf4j.impl.RecursiveAppender" + diff; + + List events = new ArrayList(); public RecursiveAppender() { - System.out.println("in RecursiveAppender constructor"); - Logger logger = LoggerFactory.getLogger("RecursiveAppender" + diff); - System.out.println("logger class=" + logger.getClass().getName()); + System.out.println("entering RecursiveAppender constructor"); + Logger logger = LoggerFactory.getLogger(loggerName); logger.info("Calling a logger in the constructor"); + System.out.println("exiting RecursiveAppender constructor"); } - protected void append(LoggingEvent arg0) { + protected void append(LoggingEvent e) { + events.add(e); } public void close() { @@ -51,4 +58,31 @@ public boolean requiresLayout() { return false; } + + @Override + public void activateOptions() { + System.out.println("entering RecursiveAppender.activateOptions"); + if (activationDelay > 0) { + Logger logger = LoggerFactory.getLogger(loggerName); + logger.info("About to wait {} millis", activationDelay); + try { + Thread.sleep(activationDelay); + } catch (InterruptedException e) { + e.printStackTrace(); + } + logger.info("Done waiting {} millis", activationDelay); + } + super.activateOptions(); + + System.out.println("exiting RecursiveAppender.activateOptions"); + } + + public int getActivationDelay() { + return activationDelay; + } + + public void setActivationDelay(int activationDelay) { + this.activationDelay = activationDelay; + } + } diff --git a/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java b/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java index 9a3fa5d..3e02043 100644 --- a/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java +++ b/slf4j-log4j12/src/test/java/org/slf4j/impl/RecursiveInitializationTest.java @@ -27,21 +27,17 @@ import java.util.Random; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + public class RecursiveInitializationTest { // value of LogManager.DEFAULT_CONFIGURATION_KEY; static String CONFIG_FILE_KEY = "log4j.configuration"; int diff = new Random().nextInt(10000); - - @Before - public void setUp() throws Exception { - System.setProperty(CONFIG_FILE_KEY, "recursiveInit.properties"); - } + String loggerName = "org.slf4j.impl.RecursiveInitializationTest"; @After public void tearDown() throws Exception { @@ -49,9 +45,9 @@ } @Test - public void testLog4j() { - Logger logger = LoggerFactory.getLogger("x" + diff); - System.out.println("logger class=" + logger.getClass().getName()); + public void loggingDuringInitialization() { + System.setProperty(CONFIG_FILE_KEY, "recursiveInit.properties"); + Logger logger = LoggerFactory.getLogger(loggerName + ".loggingDuringInitialization-" + diff); logger.info("hello"); } diff --git a/slf4j-log4j12/src/test/resources/recursiveInitWithActivationDelay.properties b/slf4j-log4j12/src/test/resources/recursiveInitWithActivationDelay.properties new file mode 100644 index 0000000..91e93f6 --- /dev/null +++ b/slf4j-log4j12/src/test/resources/recursiveInitWithActivationDelay.properties @@ -0,0 +1,9 @@ +log4j.debug=true +log4j.rootLogger=DEBUG, CONSOLE, RECURSIVE + +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=CON %d [%t] %c - %m%n + +log4j.appender.RECURSIVE=org.slf4j.impl.RecursiveAppender +log4j.appender.RECURSIVE.activationDelay=10 \ No newline at end of file diff --git a/slf4j-migrator/pom.xml b/slf4j-migrator/pom.xml index 3d67e10..d25152f 100644 --- a/slf4j-migrator/pom.xml +++ b/slf4j-migrator/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-migrator diff --git a/slf4j-migrator/src/main/java/org/slf4j/migrator/internal/MigratorFrame.java b/slf4j-migrator/src/main/java/org/slf4j/migrator/internal/MigratorFrame.java index 1625515..aa37d40 100644 --- a/slf4j-migrator/src/main/java/org/slf4j/migrator/internal/MigratorFrame.java +++ b/slf4j-migrator/src/main/java/org/slf4j/migrator/internal/MigratorFrame.java @@ -46,16 +46,6 @@ import org.slf4j.migrator.Constant; import org.slf4j.migrator.helper.SpringLayoutHelper; -/** - * This code was edited or generated using CloudGarden's Jigloo SWT/Swing GUI - * Builder, which is free for non-commercial use. If Jigloo is being used - * commercially (ie, by a corporation, company or business for any purpose - * whatever) then you should purchase a license for each developer using Jigloo. - * Please visit www.cloudgarden.com for details. Use of Jigloo implies - * acceptance of these licensing terms. A COMMERCIAL LICENSE HAS NOT BEEN - * PURCHASED FOR THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED LEGALLY FOR - * ANY CORPORATE OR COMMERCIAL PURPOSE. - */ public class MigratorFrame extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; diff --git a/slf4j-migrator/src/test/java/org/slf4j/migrator/FileConverterTest.java b/slf4j-migrator/src/test/java/org/slf4j/migrator/FileConverterTest.java index a2b5bc4..4db2002 100644 --- a/slf4j-migrator/src/test/java/org/slf4j/migrator/FileConverterTest.java +++ b/slf4j-migrator/src/test/java/org/slf4j/migrator/FileConverterTest.java @@ -31,8 +31,8 @@ import org.junit.Test; import org.slf4j.migrator.internal.NopProgressListener; import org.slf4j.migrator.line.EmptyRuleSet; -public class FileConverterTest { +public class FileConverterTest { @Test @Ignore diff --git a/slf4j-migrator/src/test/java/org/slf4j/migrator/ProjectConverterTest.java b/slf4j-migrator/src/test/java/org/slf4j/migrator/ProjectConverterTest.java index 975355d..1bf1905 100644 --- a/slf4j-migrator/src/test/java/org/slf4j/migrator/ProjectConverterTest.java +++ b/slf4j-migrator/src/test/java/org/slf4j/migrator/ProjectConverterTest.java @@ -30,7 +30,7 @@ import org.junit.Test; import org.slf4j.migrator.internal.NopProgressListener; -public class ProjectConverterTest { +public class ProjectConverterTest { public void test() { } diff --git a/slf4j-migrator/src/test/java/org/slf4j/migrator/helper/AbbreviatorTest.java b/slf4j-migrator/src/test/java/org/slf4j/migrator/helper/AbbreviatorTest.java index 106aaf9..9f24df5 100644 --- a/slf4j-migrator/src/test/java/org/slf4j/migrator/helper/AbbreviatorTest.java +++ b/slf4j-migrator/src/test/java/org/slf4j/migrator/helper/AbbreviatorTest.java @@ -28,6 +28,7 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; + public class AbbreviatorTest { static final char FS = '/'; diff --git a/slf4j-migrator/src/test/java/org/slf4j/migrator/line/JCLRuleSetTest.java b/slf4j-migrator/src/test/java/org/slf4j/migrator/line/JCLRuleSetTest.java index a1f28e9..6282b91 100644 --- a/slf4j-migrator/src/test/java/org/slf4j/migrator/line/JCLRuleSetTest.java +++ b/slf4j-migrator/src/test/java/org/slf4j/migrator/line/JCLRuleSetTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; + public class JCLRuleSetTest { LineConverter jclConverter = new LineConverter(new JCLRuleSet()); @@ -38,7 +39,6 @@ // Log import replacement assertEquals("import org.slf4j.Logger;", jclConverter.getOneLineReplacement("import org.apache.commons.logging.Log;")); } - @Test public void testLogFactoryGetLogReplacement() { @@ -93,7 +93,6 @@ jclConverter.getOneLineReplacement("// myLog = LogFactory.getFactory().getInstance(MyClass.class);//logger instanciation")); } - @Test public void testLogDeclarationReplacement() { diff --git a/slf4j-migrator/src/test/java/org/slf4j/migrator/line/NoConversionTest.java b/slf4j-migrator/src/test/java/org/slf4j/migrator/line/NoConversionTest.java index 616f5df..179b280 100644 --- a/slf4j-migrator/src/test/java/org/slf4j/migrator/line/NoConversionTest.java +++ b/slf4j-migrator/src/test/java/org/slf4j/migrator/line/NoConversionTest.java @@ -27,7 +27,8 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; -public class NoConversionTest { + +public class NoConversionTest { /** * This test shows that performing JCL to SLF4J conversion has no impact on diff --git a/slf4j-nop/pom.xml b/slf4j-nop/pom.xml index 073ea4c..31408cb 100644 --- a/slf4j-nop/pom.xml +++ b/slf4j-nop/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-nop diff --git a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java index c570b46..dccb05a 100644 --- a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -51,7 +51,7 @@ public static final StaticMDCBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link StaticMDCBinder}. diff --git a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 98218ed..21a48df 100644 --- a/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-nop/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -57,7 +57,7 @@ public static StaticMarkerBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMarkerFactory}. diff --git a/slf4j-nop/src/main/resources/META-INF/MANIFEST.MF b/slf4j-nop/src/main/resources/META-INF/MANIFEST.MF index 0151226..88f1cc9 100644 --- a/slf4j-nop/src/main/resources/META-INF/MANIFEST.MF +++ b/slf4j-nop/src/main/resources/META-INF/MANIFEST.MF @@ -5,5 +5,8 @@ Bundle-Vendor: SLF4J.ORG Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: org.slf4j.impl;version=${parsedVersion.osgiVersion} -Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, org.slf4j.spi;version=${parsedVersion.osgiVersion}, org.slf4j.helpers;version=${parsedVersion.osgiVersion} +Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, + org.slf4j.spi;version=${parsedVersion.osgiVersion}, + org.slf4j.helpers;version=${parsedVersion.osgiVersion}, + org.slf4j.event;version=${parsedVersion.osgiVersion} Fragment-Host: slf4j.apidiff --git a/slf4j-nop/src/test/java/org/slf4j/LoggerFactoryFriend.java b/slf4j-nop/src/test/java/org/slf4j/LoggerFactoryFriend.java new file mode 100644 index 0000000..edf5fcf --- /dev/null +++ b/slf4j-nop/src/test/java/org/slf4j/LoggerFactoryFriend.java @@ -0,0 +1,7 @@ +package org.slf4j; + +public class LoggerFactoryFriend { + static public void reset() { + LoggerFactory.reset(); + } +} diff --git a/slf4j-nop/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java b/slf4j-nop/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java new file mode 100644 index 0000000..18a3732 --- /dev/null +++ b/slf4j-nop/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java @@ -0,0 +1,150 @@ +/** + * Copyright (c) 2004-2016 QOS.ch + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package org.slf4j.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.LoggerFactoryFriend; + +public class MultithreadedInitializationTest { + + final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; + + private static AtomicLong EVENT_COUNT = new AtomicLong(0); + + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + + int diff = new Random().nextInt(10000); + String loggerName = "org.slf4j.impl.MultithreadedInitializationTest"; + private final PrintStream oldErr = System.err; + StringPrintStream sps = new StringPrintStream(oldErr); + + @Before + public void setup() { + LoggerFactoryFriend.reset(); + System.setErr(sps); + } + + @After + public void tearDown() throws Exception { + LoggerFactoryFriend.reset(); + System.setErr(oldErr); + } + + @Test + public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + LoggerAccessingThread[] accessors = harness(); + + for (LoggerAccessingThread accessor : accessors) { + EVENT_COUNT.getAndIncrement(); + accessor.logger.info("post harness"); + } + + Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff); + logger.info("hello"); + EVENT_COUNT.getAndIncrement(); + + assertEquals(0, sps.stringList.size()); + } + + private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { + LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i] = new LoggerAccessingThread(barrier, i); + threads[i].start(); + } + + barrier.await(); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } + return threads; + } + + static class LoggerAccessingThread extends Thread { + final CyclicBarrier barrier; + Logger logger; + int count; + + LoggerAccessingThread(CyclicBarrier barrier, int count) { + this.barrier = barrier; + this.count = count; + } + + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + logger = LoggerFactory.getLogger(this.getClass().getName() + "-" + count); + logger.info("in run method"); + EVENT_COUNT.getAndIncrement(); + } + }; + + public static class StringPrintStream extends PrintStream { + + public static final String LINE_SEP = System.getProperty("line.separator"); + PrintStream other; + List stringList = new ArrayList(); + + public StringPrintStream(PrintStream ps) { + super(ps); + other = ps; + } + + public void print(String s) { + other.print(s); + stringList.add(s); + } + + public void println(String s) { + other.println(s); + stringList.add(s); + } + + public void println(Object o) { + other.println(o); + stringList.add(o.toString()); + } + }; + +} diff --git a/slf4j-simple/pom.xml b/slf4j-simple/pom.xml index 6217d65..94bdd41 100644 --- a/slf4j-simple/pom.xml +++ b/slf4j-simple/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-simple diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLogger.java b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLogger.java index 984c294..4f95260 100644 --- a/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLogger.java +++ b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLogger.java @@ -36,6 +36,7 @@ import java.util.Properties; import org.slf4j.Logger; +import org.slf4j.event.LoggingEvent; import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MarkerIgnoringBase; import org.slf4j.helpers.MessageFormatter; @@ -182,6 +183,9 @@ // Load properties file, if found. // Override with system properties. static void init() { + if (INITIALIZED) { + return; + } INITIALIZED = true; loadProperties(); @@ -258,9 +262,6 @@ * SimpleLogger instances. */ SimpleLogger(String name) { - if (!INITIALIZED) { - init(); - } this.name = name; String levelString = recursivelyComputeLevelString(); @@ -645,4 +646,15 @@ public void error(String msg, Throwable t) { log(LOG_LEVEL_ERROR, msg, t); } + + public void log(LoggingEvent event) { + int levelInt = event.getLevel().toInt(); + + if (!isLevelEnabled(levelInt)) { + return; + } + FormattingTuple tp = MessageFormatter.arrayFormat(event.getMessage(), event.getArgumentArray(), event.getThrowable()); + log(levelInt, tp.getMessage(), event.getThrowable()); + } + } diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerFactory.java b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerFactory.java index 1ceb815..66f8910 100644 --- a/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerFactory.java +++ b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerFactory.java @@ -42,6 +42,7 @@ public SimpleLoggerFactory() { loggerMap = new ConcurrentHashMap(); + SimpleLogger.init(); } /** diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java index 1172cd3..cef7875 100644 --- a/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ b/slf4j-simple/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -48,7 +48,7 @@ private StaticMarkerBinder() { } - + /** * Return the singleton of this class. * @@ -58,7 +58,7 @@ public static StaticMarkerBinder getSingleton() { return SINGLETON; } - + /** * Currently this method always returns an instance of * {@link BasicMarkerFactory}. diff --git a/slf4j-simple/src/main/resources/META-INF/MANIFEST.MF b/slf4j-simple/src/main/resources/META-INF/MANIFEST.MF index ded9247..081988f 100644 --- a/slf4j-simple/src/main/resources/META-INF/MANIFEST.MF +++ b/slf4j-simple/src/main/resources/META-INF/MANIFEST.MF @@ -6,5 +6,8 @@ Require-Bundle: slf4j.api Bundle-RequiredExecutionEnvironment: J2SE-1.5 Export-Package: org.slf4j.impl;version=${parsedVersion.osgiVersion} -Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, org.slf4j.spi;version=${parsedVersion.osgiVersion}, org.slf4j.helpers;version=${parsedVersion.osgiVersion} +Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, + org.slf4j.spi;version=${parsedVersion.osgiVersion}, + org.slf4j.helpers;version=${parsedVersion.osgiVersion}, + org.slf4j.event;version=${parsedVersion.osgiVersion} Fragment-Host: slf4j.apidiff --git a/slf4j-simple/src/test/java/org/slf4j/LoggerFactoryFriend.java b/slf4j-simple/src/test/java/org/slf4j/LoggerFactoryFriend.java new file mode 100644 index 0000000..edf5fcf --- /dev/null +++ b/slf4j-simple/src/test/java/org/slf4j/LoggerFactoryFriend.java @@ -0,0 +1,7 @@ +package org.slf4j; + +public class LoggerFactoryFriend { + static public void reset() { + LoggerFactory.reset(); + } +} diff --git a/slf4j-simple/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java b/slf4j-simple/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java new file mode 100644 index 0000000..54719c5 --- /dev/null +++ b/slf4j-simple/src/test/java/org/slf4j/impl/MultithreadedInitializationTest.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2004-2016 QOS.ch + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package org.slf4j.impl; + +import static org.junit.Assert.assertEquals; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.LoggerFactoryFriend; + +public class MultithreadedInitializationTest { + + final static int THREAD_COUNT = 4 + Runtime.getRuntime().availableProcessors() * 2; + + private static AtomicLong EVENT_COUNT = new AtomicLong(0); + + private final PrintStream oldErr = System.err; + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + + int diff = new Random().nextInt(10000); + String loggerName = "org.slf4j.impl.MultithreadedInitializationTest"; + StringPrintStream sps = new StringPrintStream(oldErr); + + @Before + public void setup() { + LoggerFactoryFriend.reset(); + System.setErr(sps); + } + + @After + public void tearDown() throws Exception { + LoggerFactoryFriend.reset(); + System.setErr(oldErr); + } + + @Test + public void multiThreadedInitialization() throws InterruptedException, BrokenBarrierException { + System.out.println("THREAD_COUNT=" + THREAD_COUNT); + LoggerAccessingThread[] accessors = harness(); + + for (LoggerAccessingThread accessor : accessors) { + EVENT_COUNT.getAndIncrement(); + accessor.logger.info("post harness"); + } + + Logger logger = LoggerFactory.getLogger(loggerName + ".slowInitialization-" + diff); + logger.info("hello"); + EVENT_COUNT.getAndIncrement(); + + int NUM_LINES_IN_SLF4J_REPLAY_WARNING = 3; + assertEquals(EVENT_COUNT.get() + NUM_LINES_IN_SLF4J_REPLAY_WARNING, sps.stringList.size()); + } + + private static LoggerAccessingThread[] harness() throws InterruptedException, BrokenBarrierException { + LoggerAccessingThread[] threads = new LoggerAccessingThread[THREAD_COUNT]; + final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT + 1); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i] = new LoggerAccessingThread(barrier, i); + threads[i].start(); + } + + barrier.await(); + for (int i = 0; i < THREAD_COUNT; i++) { + threads[i].join(); + } + return threads; + } + + static class LoggerAccessingThread extends Thread { + final CyclicBarrier barrier; + Logger logger; + int count; + + LoggerAccessingThread(CyclicBarrier barrier, int count) { + this.barrier = barrier; + this.count = count; + } + + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + for (int i = 0; i < 64; i++) { + logger = LoggerFactory.getLogger(this.getClass().getName() + "-" + count+"-"+i); + logger.info("in run method"); + EVENT_COUNT.getAndIncrement(); + } + } + }; + + public static class StringPrintStream extends PrintStream { + + public static final String LINE_SEP = System.getProperty("line.separator"); + PrintStream other; + List stringList = Collections.synchronizedList(new ArrayList()); + + public StringPrintStream(PrintStream ps) { + super(ps); + other = ps; + } + + public void print(String s) { + other.print(s); + stringList.add(s); + } + + public void println(String s) { + other.println(s); + stringList.add(s); + } + + public void println(Object o) { + other.println(o); + stringList.add(o.toString()); + } + }; + +} diff --git a/slf4j-site/pom.xml b/slf4j-site/pom.xml index 8813e9b..fd57623 100644 --- a/slf4j-site/pom.xml +++ b/slf4j-site/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.14 + 1.7.19 slf4j-site