diff --git a/LICENSE.txt b/LICENSE.txt index 5d3a83b..54f5abe 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2004-2014 QOS.ch +Copyright (c) 2004-2017 QOS.ch All rights reserved. Permission is hereby granted, free of charge, to any person obtaining diff --git a/integration/pom.xml b/integration/pom.xml index 0625ffb..6d33bc5 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 integration @@ -40,7 +40,8 @@ org.apache.felix org.apache.felix.main - 2.0.2 + 5.6.1 + diff --git a/integration/src/test/java/org/slf4j/test_osgi/FelixHost.java b/integration/src/test/java/org/slf4j/test_osgi/FelixHost.java index 738a971..adcd565 100644 --- a/integration/src/test/java/org/slf4j/test_osgi/FelixHost.java +++ b/integration/src/test/java/org/slf4j/test_osgi/FelixHost.java @@ -59,7 +59,7 @@ public void doLaunch() { // Create a case-insensitive configuration property map. - StringMap configMap = new StringMap(false); + StringMap configMap = new StringMap(); // Configure the Felix instance to be embedded. // configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true"); // Add core OSGi packages to be exported from the class path @@ -89,8 +89,8 @@ // otherProps.put(Constants.FRAMEWORK_STORAGE, "bundles"); - otherProps.put(AutoProcessor.AUTO_DEPLOY_DIR_PROPERY, AutoProcessor.AUTO_DEPLOY_DIR_VALUE); - otherProps.put(AutoProcessor.AUTO_DEPLOY_ACTION_PROPERY, AutoProcessor.AUTO_DEPLOY_START_VALUE + "," + AutoProcessor.AUTO_DEPLOY_INSTALL_VALUE); + otherProps.put(AutoProcessor.AUTO_DEPLOY_DIR_PROPERTY, AutoProcessor.AUTO_DEPLOY_DIR_VALUE); + otherProps.put(AutoProcessor.AUTO_DEPLOY_ACTION_PROPERTY, AutoProcessor.AUTO_DEPLOY_START_VALUE + "," + AutoProcessor.AUTO_DEPLOY_INSTALL_VALUE); BundleContext felixBudleContext = felix.getBundleContext(); diff --git a/jcl-over-slf4j/pom.xml b/jcl-over-slf4j/pom.xml index 8c08e24..0c94e46 100644 --- a/jcl-over-slf4j/pom.xml +++ b/jcl-over-slf4j/pom.xml @@ -5,15 +5,15 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 4.0.0 jcl-over-slf4j jar - JCL 1.1.1 implemented over SLF4J - JCL 1.1.1 implemented over SLF4J + JCL 1.2 implemented over SLF4J + JCL 1.2 implemented over SLF4J http://www.slf4j.org diff --git a/jcl-over-slf4j/src/main/resources/META-INF/MANIFEST.MF b/jcl-over-slf4j/src/main/resources/META-INF/MANIFEST.MF index b737e98..ae8f969 100644 --- a/jcl-over-slf4j/src/main/resources/META-INF/MANIFEST.MF +++ b/jcl-over-slf4j/src/main/resources/META-INF/MANIFEST.MF @@ -4,6 +4,6 @@ Bundle-Name: jcl-over-slf4j Bundle-Vendor: SLF4J.ORG Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Export-Package: org.apache.commons.logging;version=1.1.1, - org.apache.commons.logging.impl;version=1.1.1 +Export-Package: org.apache.commons.logging;version=1.2, + org.apache.commons.logging.impl;version=1.2 Import-Package: org.slf4j;version=${parsedVersion.osgiVersion}, org.slf4j.spi;version=${parsedVersion.osgiVersion} diff --git a/jul-to-slf4j/pom.xml b/jul-to-slf4j/pom.xml index 31feeea..d9ed8c5 100644 --- a/jul-to-slf4j/pom.xml +++ b/jul-to-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 jul-to-slf4j diff --git a/log4j-over-slf4j/pom.xml b/log4j-over-slf4j/pom.xml index 40595c6..53a3a48 100644 --- a/log4j-over-slf4j/pom.xml +++ b/log4j-over-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 diff --git a/osgi-over-slf4j/pom.xml b/osgi-over-slf4j/pom.xml index ac3a468..2b0d80a 100644 --- a/osgi-over-slf4j/pom.xml +++ b/osgi-over-slf4j/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 osgi-over-slf4j diff --git a/pom.xml b/pom.xml index 5c4f7ef..0df1e97 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 pom SLF4J @@ -46,7 +46,7 @@ 1.0.13 4.12 3.3 - 2.10.2 + 2.10.4 @@ -59,12 +59,11 @@ slf4j-api - slf4j-simple slf4j-nop slf4j-jdk14 slf4j-log4j12 - slf4j-jcl + slf4j-jcl slf4j-android slf4j-ext jcl-over-slf4j @@ -262,6 +261,7 @@ maven-javadoc-plugin ${javadoc.plugin.version} + true org.slf4j.migrator:org.slf4j.migrator.* diff --git a/slf4j-android/pom.xml b/slf4j-android/pom.xml index 2442e54..a0bd3cb 100644 --- a/slf4j-android/pom.xml +++ b/slf4j-android/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-android diff --git a/slf4j-api/pom.xml b/slf4j-api/pom.xml index 75cfdb6..a33ed63 100644 --- a/slf4j-api/pom.xml +++ b/slf4j-api/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-api @@ -82,6 +82,39 @@ + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.apache.maven.plugins + + + maven-antrun-plugin + + [1.3,) + + run + + + + + + + + + + + + diff --git a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java index 2601678..c245a70 100644 --- a/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java +++ b/slf4j-api/src/main/java/org/slf4j/LoggerFactory.java @@ -74,7 +74,7 @@ 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; + static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also " + UNSUCCESSFUL_INIT_URL; static final int UNINITIALIZED = 0; static final int ONGOING_INITIALIZATION = 1; @@ -83,8 +83,8 @@ static final int NOP_FALLBACK_INITIALIZATION = 4; static volatile int INITIALIZATION_STATE = UNINITIALIZED; - static SubstituteLoggerFactory SUBST_FACTORY = new SubstituteLoggerFactory(); - static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory(); + static final SubstituteLoggerFactory SUBST_FACTORY = new SubstituteLoggerFactory(); + static final NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory(); // Support for detecting mismatched logger names. static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch"; diff --git a/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java b/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java index 401d622..112dc33 100644 --- a/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java +++ b/slf4j-api/src/main/java/org/slf4j/event/EventRecodingLogger.java @@ -33,7 +33,7 @@ loggingEvent.setLevel(level); loggingEvent.setLogger(logger); loggingEvent.setLoggerName(name); - + loggingEvent.setMarker(marker); loggingEvent.setMessage(msg); loggingEvent.setArgumentArray(args); loggingEvent.setThrowable(throwable); diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/BasicMarker.java b/slf4j-api/src/main/java/org/slf4j/helpers/BasicMarker.java index 7ed253d..bda9fd9 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/BasicMarker.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/BasicMarker.java @@ -24,10 +24,9 @@ */ package org.slf4j.helpers; -import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Vector; +import java.util.concurrent.CopyOnWriteArrayList; import org.slf4j.Marker; @@ -39,10 +38,9 @@ */ public class BasicMarker implements Marker { - private static final long serialVersionUID = 1803952589649545191L; - + private static final long serialVersionUID = -2849567615646933777L; private final String name; - private List referenceList; + private List referenceList = new CopyOnWriteArrayList(); BasicMarker(String name) { if (name == null) { @@ -55,7 +53,7 @@ return name; } - public synchronized void add(Marker reference) { + public void add(Marker reference) { if (reference == null) { throw new IllegalArgumentException("A null value cannot be added to a Marker as reference."); } @@ -65,49 +63,27 @@ return; } else if (reference.contains(this)) { // avoid recursion - // a potential reference should not its future "parent" as a reference + // a potential reference should not hold its future "parent" as a reference return; } else { - // let's add the reference - if (referenceList == null) { - referenceList = new Vector(); - } referenceList.add(reference); } - } - public synchronized boolean hasReferences() { - return ((referenceList != null) && (referenceList.size() > 0)); + public boolean hasReferences() { + return (referenceList.size() > 0); } public boolean hasChildren() { return hasReferences(); } - public synchronized Iterator iterator() { - if (referenceList != null) { - return referenceList.iterator(); - } else { - List emptyList = Collections.emptyList(); - return emptyList.iterator(); - } + public Iterator iterator() { + return referenceList.iterator(); } - public synchronized boolean remove(Marker referenceToRemove) { - if (referenceList == null) { - return false; - } - - int size = referenceList.size(); - for (int i = 0; i < size; i++) { - Marker m = referenceList.get(i); - if (referenceToRemove.equals(m)) { - referenceList.remove(i); - return true; - } - } - return false; + public boolean remove(Marker referenceToRemove) { + return referenceList.remove(referenceToRemove); } public boolean contains(Marker other) { 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 99784ae..86493bf 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/Util.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/Util.java @@ -32,6 +32,7 @@ */ public final class Util { + private Util() { } @@ -126,4 +127,7 @@ static final public void report(String msg) { System.err.println("SLF4J: " + msg); } + + + } diff --git a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava b/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava deleted file mode 100644 index 9c3fdd2..0000000 --- a/slf4j-api/src/test/java/org/slf4j/FindStaticLoggerBinderPathsPerfTest.hava +++ /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-ext/pom.xml b/slf4j-ext/pom.xml index 0e7b649..558e3d2 100644 --- a/slf4j-ext/pom.xml +++ b/slf4j-ext/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-ext @@ -32,6 +32,7 @@ ch.qos.cal10n cal10n-api + true javassist diff --git a/slf4j-jcl/pom.xml b/slf4j-jcl/pom.xml index 6089c30..9e313ca 100644 --- a/slf4j-jcl/pom.xml +++ b/slf4j-jcl/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-jcl diff --git a/slf4j-jdk14/pom.xml b/slf4j-jdk14/pom.xml index 104589b..a165a71 100644 --- a/slf4j-jdk14/pom.xml +++ b/slf4j-jdk14/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-jdk14 diff --git a/slf4j-log4j12/pom.xml b/slf4j-log4j12/pom.xml index ed07606..7d0657f 100644 --- a/slf4j-log4j12/pom.xml +++ b/slf4j-log4j12/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-log4j12 diff --git a/slf4j-log4j12/src/main/java/org/apache/log4j/MDCFriend.java b/slf4j-log4j12/src/main/java/org/apache/log4j/MDCFriend.java new file mode 100644 index 0000000..f14daaf --- /dev/null +++ b/slf4j-log4j12/src/main/java/org/apache/log4j/MDCFriend.java @@ -0,0 +1,33 @@ +package org.apache.log4j; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.log4j.helpers.ThreadLocalMap; + +public class MDCFriend { + + public static void fixForJava9() { + if (MDC.mdc.tlm == null) { + MDC.mdc.tlm = new ThreadLocalMap(); + MDC.mdc.java1 = false; + setRemoveMethod(MDC.mdc); + } + + } + + private static void setRemoveMethod(MDC mdc) { + try { + Method removeMethod = ThreadLocal.class.getMethod("remove"); + Field removeMethodField = MDC.class.getDeclaredField("removeMethod"); + removeMethodField.setAccessible(true); + removeMethodField.set(mdc, removeMethod); + } catch (NoSuchMethodException e) { + } catch (SecurityException e) { + } catch (NoSuchFieldException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + + } +} 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 686db90..6327965 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jLoggerFactory.java @@ -28,9 +28,9 @@ import java.util.concurrent.ConcurrentMap; import org.apache.log4j.LogManager; -import org.slf4j.helpers.Util; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; +import org.slf4j.helpers.Util; /** * Log4jLoggerFactory is an implementation of {@link ILoggerFactory} returning diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jMDCAdapter.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jMDCAdapter.java index cbb96b6..36c0bcc 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jMDCAdapter.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/Log4jMDCAdapter.java @@ -28,64 +28,71 @@ import java.util.Iterator; import java.util.Map; +import org.apache.log4j.MDCFriend; import org.slf4j.spi.MDCAdapter; public class Log4jMDCAdapter implements MDCAdapter { - public void clear() { - @SuppressWarnings("rawtypes") - Map map = org.apache.log4j.MDC.getContext(); - if (map != null) { - map.clear(); - } - } + static { + if (VersionUtil.getJavaMajorVersion() >= 9) { + MDCFriend.fixForJava9(); + } + } - public String get(String key) { - return (String) org.apache.log4j.MDC.get(key); - } + public void clear() { + @SuppressWarnings("rawtypes") + Map map = org.apache.log4j.MDC.getContext(); + if (map != null) { + map.clear(); + } + } - /** - * Put a context value (the val parameter) as identified with - * the key parameter into the current thread's context map. The - * key parameter cannot be null. Log4j does not - * support null for the val parameter. - * - *

- * This method delegates all work to log4j's MDC. - * - * @throws IllegalArgumentException - * in case the "key" or "val" parameter is null - */ - public void put(String key, String val) { - org.apache.log4j.MDC.put(key, val); - } + public String get(String key) { + return (String) org.apache.log4j.MDC.get(key); + } - public void remove(String key) { - org.apache.log4j.MDC.remove(key); - } + /** + * Put a context value (the val parameter) as identified with + * the key parameter into the current thread's context map. The + * key parameter cannot be null. Log4j does not + * support null for the val parameter. + * + *

+ * This method delegates all work to log4j's MDC. + * + * @throws IllegalArgumentException + * in case the "key" or "val" parameter is null + */ + public void put(String key, String val) { + org.apache.log4j.MDC.put(key, val); + } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Map getCopyOfContextMap() { - Map old = org.apache.log4j.MDC.getContext(); - if (old != null) { - return new HashMap(old); - } else { - return null; - } - } + public void remove(String key) { + org.apache.log4j.MDC.remove(key); + } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void setContextMap(Map contextMap) { - Map old = org.apache.log4j.MDC.getContext(); - if (old == null) { - Iterator entrySetIterator = contextMap.entrySet().iterator(); - while (entrySetIterator.hasNext()) { - Map.Entry mapEntry = (Map.Entry) entrySetIterator.next(); - org.apache.log4j.MDC.put((String) mapEntry.getKey(), mapEntry.getValue()); - } - } else { - old.clear(); - old.putAll(contextMap); - } - } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Map getCopyOfContextMap() { + Map old = org.apache.log4j.MDC.getContext(); + if (old != null) { + return new HashMap(old); + } else { + return null; + } + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void setContextMap(Map contextMap) { + Map old = org.apache.log4j.MDC.getContext(); + if (old == null) { + Iterator entrySetIterator = contextMap.entrySet().iterator(); + while (entrySetIterator.hasNext()) { + Map.Entry mapEntry = (Map.Entry) entrySetIterator.next(); + org.apache.log4j.MDC.put((String) mapEntry.getKey(), mapEntry.getValue()); + } + } else { + old.clear(); + old.putAll(contextMap); + } + } } 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 bb0f065..aab9ee6 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -33,33 +33,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() { - } + private StaticMDCBinder() { + } - /** - * Return the singleton of this class. - * - * @return the StaticMDCBinder singleton - * @since 1.7.14 - */ - public static final StaticMDCBinder getSingleton() { - return SINGLETON; - } + /** + * 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 StaticMDCBinder}. - */ - public MDCAdapter getMDCA() { - return new Log4jMDCAdapter(); - } + /** + * Currently this method always returns an instance of + * {@link StaticMDCBinder}. + */ + public MDCAdapter getMDCA() { + return new Log4jMDCAdapter(); + } - public String getMDCAdapterClassStr() { - return Log4jMDCAdapter.class.getName(); - } + public String getMDCAdapterClassStr() { + return Log4jMDCAdapter.class.getName(); + } } diff --git a/slf4j-log4j12/src/main/java/org/slf4j/impl/VersionUtil.java b/slf4j-log4j12/src/main/java/org/slf4j/impl/VersionUtil.java new file mode 100644 index 0000000..ee913ed --- /dev/null +++ b/slf4j-log4j12/src/main/java/org/slf4j/impl/VersionUtil.java @@ -0,0 +1,33 @@ +package org.slf4j.impl; + +import java.lang.reflect.Method; + +import org.slf4j.helpers.Util; + +public class VersionUtil { + static final int MINIMAL_VERSION = 5; + + static public int getJavaMajorVersion() { + String javaVersionString = Util.safeGetSystemProperty("java.version"); + return getJavaMajorVersion(javaVersionString); + } + + static int getJavaMajorVersion(String versionString) { + if (versionString == null) + return MINIMAL_VERSION; + if (versionString.startsWith("1.")) { + return versionString.charAt(2) - '0'; + } else { + // we running under Java 9 or later + try { + Method versionMethod = Runtime.class.getMethod("version"); + Object versionObj = versionMethod.invoke(null); + Method majorMethod = versionObj.getClass().getMethod("major"); + Integer resultInteger = (Integer) majorMethod.invoke(versionObj); + return resultInteger.intValue(); + } catch (Exception e) { + return MINIMAL_VERSION; + } + } + } +} diff --git a/slf4j-log4j12/src/test/java/org/apache/log4j/MDCFriendTest.java b/slf4j-log4j12/src/test/java/org/apache/log4j/MDCFriendTest.java new file mode 100644 index 0000000..ffa17f5 --- /dev/null +++ b/slf4j-log4j12/src/test/java/org/apache/log4j/MDCFriendTest.java @@ -0,0 +1,32 @@ +package org.apache.log4j; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Random; + +import org.junit.Test; +import org.slf4j.impl.VersionUtil; + +public class MDCFriendTest { + + + private static Random random = new Random(); + int diff = random.nextInt(1024*8); + + @Test + public void smoke() { + if(VersionUtil.getJavaMajorVersion() < 9) + return; + + MDCFriend.fixForJava9(); + String key = "MDCFriendTest.smoke"+diff; + String val = "val"+diff; + MDC.put(key, val); + assertEquals(val, MDC.get(key)); + MDC.clear(); + assertNull(MDC.get(key)); + + } + +} diff --git a/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java b/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java index d687383..6c71a11 100644 --- a/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java +++ b/slf4j-log4j12/src/test/java/org/slf4j/InvocationTest.java @@ -68,9 +68,9 @@ @Test public void test2() { - Integer i1 = new Integer(1); - Integer i2 = new Integer(2); - Integer i3 = new Integer(3); + Integer i1 = Integer.valueOf(1); + Integer i2 = Integer.valueOf(2); + Integer i3 = Integer.valueOf(3); Exception e = new Exception("This is a test exception."); Logger logger = LoggerFactory.getLogger("test2"); @@ -88,7 +88,7 @@ logger.warn("Hello world 3", e); logger.error("Hello world 4."); - logger.error("Hello world {}", new Integer(3)); + logger.error("Hello world {}", Integer.valueOf(3)); logger.error("Hello world 4.", e); assertEquals(11, listAppender.list.size()); } diff --git a/slf4j-log4j12/src/test/java/org/slf4j/impl/UtilVersionTest.java b/slf4j-log4j12/src/test/java/org/slf4j/impl/UtilVersionTest.java new file mode 100644 index 0000000..e84d5cf --- /dev/null +++ b/slf4j-log4j12/src/test/java/org/slf4j/impl/UtilVersionTest.java @@ -0,0 +1,24 @@ +package org.slf4j.impl; + +import static org.junit.Assert.*; + +import org.junit.Ignore; +import org.junit.Test; + +public class UtilVersionTest { + + @Test + public void test() { + System.out.println(System.getProperty("java.version")); + assertEquals(6, VersionUtil.getJavaMajorVersion("1.6")); + assertEquals(7, VersionUtil.getJavaMajorVersion("1.7.0_21-b11")); + assertEquals(8, VersionUtil.getJavaMajorVersion("1.8.0_25")); + } + + @Ignore + @Test // requires Java 9 to pass + public void testJava9() { + assertEquals(9, VersionUtil.getJavaMajorVersion("9ea")); + } + +} diff --git a/slf4j-migrator/pom.xml b/slf4j-migrator/pom.xml index e67c1d3..1762cc9 100644 --- a/slf4j-migrator/pom.xml +++ b/slf4j-migrator/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-migrator diff --git a/slf4j-nop/pom.xml b/slf4j-nop/pom.xml index f1ab6dc..41f5a76 100644 --- a/slf4j-nop/pom.xml +++ b/slf4j-nop/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-nop diff --git a/slf4j-simple/pom.xml b/slf4j-simple/pom.xml index 253ad14..6b019bd 100644 --- a/slf4j-simple/pom.xml +++ b/slf4j-simple/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-simple diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/OutputChoice.java b/slf4j-simple/src/main/java/org/slf4j/impl/OutputChoice.java new file mode 100644 index 0000000..c3d691e --- /dev/null +++ b/slf4j-simple/src/main/java/org/slf4j/impl/OutputChoice.java @@ -0,0 +1,55 @@ +package org.slf4j.impl; + +import java.io.PrintStream; + +/** + * This class encapsulates the user's choice of output target. + * + * @author Ceki Gülcü + * + */ +class OutputChoice { + + enum OutputChoiceType { + SYS_OUT, CACHED_SYS_OUT, SYS_ERR, CACHED_SYS_ERR, FILE; + } + + final OutputChoiceType outputChoiceType; + final PrintStream targetPrintStream; + + OutputChoice(OutputChoiceType outputChoiceType) { + if (outputChoiceType == OutputChoiceType.FILE) { + throw new IllegalArgumentException(); + } + this.outputChoiceType = outputChoiceType; + if (outputChoiceType == OutputChoiceType.CACHED_SYS_OUT) { + this.targetPrintStream = System.out; + } else if (outputChoiceType == OutputChoiceType.CACHED_SYS_ERR) { + this.targetPrintStream = System.err; + } else { + this.targetPrintStream = null; + } + } + + OutputChoice(PrintStream printStream) { + this.outputChoiceType = OutputChoiceType.FILE; + this.targetPrintStream = printStream; + } + + PrintStream getTargetPrintStream() { + switch (outputChoiceType) { + case SYS_OUT: + return System.out; + case SYS_ERR: + return System.err; + case CACHED_SYS_ERR: + case CACHED_SYS_OUT: + case FILE: + return targetPrintStream; + default: + throw new IllegalArgumentException(); + } + + } + +} 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 1c401ed..5fceba2 100644 --- a/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLogger.java +++ b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLogger.java @@ -24,76 +24,97 @@ */ package org.slf4j.impl; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.InputStream; import java.io.PrintStream; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Date; -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; -import org.slf4j.helpers.Util; import org.slf4j.spi.LocationAwareLogger; /** - *

Simple implementation of {@link Logger} that sends all enabled log messages, - * for all defined loggers, to the console ({@code System.err}). - * The following system properties are supported to configure the behavior of this logger:

+ *

+ * Simple implementation of {@link Logger} that sends all enabled log messages, + * for all defined loggers, to the console ({@code System.err}). The following + * system properties are supported to configure the behavior of this logger: + *

* *
    - *
  • org.slf4j.simpleLogger.logFile - The output target which can be the path to a file, or - * the special values "System.out" and "System.err". Default is "System.err". - * - *
  • org.slf4j.simpleLogger.defaultLogLevel - Default log level for all instances of SimpleLogger. - * Must be one of ("trace", "debug", "info", "warn", "error" or "off"). If not specified, defaults to "info".
  • - * - *
  • org.slf4j.simpleLogger.log.a.b.c - Logging detail level for a SimpleLogger instance - * named "a.b.c". Right-side value must be one of "trace", "debug", "info", "warn", "error" or "off". When a SimpleLogger - * named "a.b.c" is initialized, its level is assigned from this property. If unspecified, the level of nearest parent - * logger will be used, and if none is set, then the value specified by + *
  • org.slf4j.simpleLogger.logFile - The output target which can + * be the path to a file, or the special values "System.out" and + * "System.err". Default is "System.err".
  • + * + *
  • org.slf4j.simpleLogger.cacheOutputStream - If the output + * target is set to "System.out" or "System.err" (see preceding entry), by + * default, logs will be output to the latest value referenced by + * System.out/err variables. By setting this + * parameter to true, the output stream will be cached, i.e. assigned once at + * initialization time and re-used independently of the current value referenced by + * System.out/err. + *
  • + * + *
  • org.slf4j.simpleLogger.defaultLogLevel - Default log level + * for all instances of SimpleLogger. Must be one of ("trace", "debug", "info", + * "warn", "error" or "off"). If not specified, defaults to "info".
  • + * + *
  • org.slf4j.simpleLogger.log.a.b.c - Logging detail + * level for a SimpleLogger instance named "a.b.c". Right-side value must be one + * of "trace", "debug", "info", "warn", "error" or "off". When a SimpleLogger + * named "a.b.c" is initialized, its level is assigned from this property. If + * unspecified, the level of nearest parent logger will be used, and if none is + * set, then the value specified by * org.slf4j.simpleLogger.defaultLogLevel will be used.
  • * - *
  • org.slf4j.simpleLogger.showDateTime - Set to true if you want the current date and - * time to be included in output messages. Default is false
  • - * - *
  • org.slf4j.simpleLogger.dateTimeFormat - The date and time format to be used in the output messages. - * The pattern describing the date and time format is defined by - * SimpleDateFormat. - * If the format is not specified or is invalid, the number of milliseconds since start up will be output.
  • - * - *
  • org.slf4j.simpleLogger.showThreadName -Set to true if you want to output the current - * thread name. Defaults to true.
  • - * - *
  • org.slf4j.simpleLogger.showLogName - Set to true if you want the Logger instance name - * to be included in output messages. Defaults to true.
  • - * - *
  • org.slf4j.simpleLogger.showShortLogName - Set to true if you want the last component - * of the name to be included in output messages. Defaults to false.
  • - * - *
  • org.slf4j.simpleLogger.levelInBrackets - Should the level string be output in brackets? Defaults - * to false.
  • - * - *
  • org.slf4j.simpleLogger.warnLevelString - The string value output for the warn level. Defaults - * to WARN.
  • - + *
  • org.slf4j.simpleLogger.showDateTime - Set to + * true if you want the current date and time to be included in + * output messages. Default is false
  • + * + *
  • org.slf4j.simpleLogger.dateTimeFormat - The date and time + * format to be used in the output messages. The pattern describing the date and + * time format is defined by + * SimpleDateFormat. If the format is not specified or is + * invalid, the number of milliseconds since start up will be output.
  • + * + *
  • org.slf4j.simpleLogger.showThreadName -Set to + * true if you want to output the current thread name. Defaults to + * true.
  • + * + *
  • org.slf4j.simpleLogger.showLogName - Set to + * true if you want the Logger instance name to be included in + * output messages. Defaults to true.
  • + * + *
  • org.slf4j.simpleLogger.showShortLogName - Set to + * true if you want the last component of the name to be included + * in output messages. Defaults to false.
  • + * + *
  • org.slf4j.simpleLogger.levelInBrackets - Should the level + * string be output in brackets? Defaults to false.
  • + * + *
  • org.slf4j.simpleLogger.warnLevelString - The string value + * output for the warn level. Defaults to WARN.
  • + * *
* - *

In addition to looking for system properties with the names specified above, this implementation also checks for - * a class loader resource named "simplelogger.properties", and includes any matching definitions - * from this resource (if it exists).

- * - *

With no configuration, the default output includes the relative time in milliseconds, thread name, the level, - * logger name, and the message followed by the line separator for the host. In log4j terms it amounts to the "%r [%t] - * %level %logger - %m%n" pattern.

- *

Sample output follows.

+ *

+ * In addition to looking for system properties with the names specified above, + * this implementation also checks for a class loader resource named + * "simplelogger.properties", and includes any matching definitions + * from this resource (if it exists). + *

+ * + *

+ * With no configuration, the default output includes the relative time in + * milliseconds, thread name, the level, logger name, and the message followed + * by the line separator for the host. In log4j terms it amounts to the "%r [%t] + * %level %logger - %m%n" pattern. + *

+ *

+ * Sample output follows. + *

+ * *
  * 176 [main] INFO examples.Sort - Populating an array of 2 elements in reverse order.
  * 225 [main] INFO examples.SortAlgo - Entered the sort method.
@@ -107,11 +128,14 @@
  * 467 [main] INFO  examples.Sort - Exiting main method.
  * 
* - *

This implementation is heavily inspired by - * Apache Commons Logging's SimpleLog.

+ *

+ * This implementation is heavily inspired by + * Apache Commons Logging's + * SimpleLog. + *

* * @author Ceki Gülcü - * @author Scott Sanders + * @author Scott Sanders * @author Rod Waldhoff * @author Robert Burrell Donkin * @author Cédrik LIME @@ -119,68 +143,21 @@ public class SimpleLogger extends MarkerIgnoringBase { private static final long serialVersionUID = -632788891211436180L; - private static final String CONFIGURATION_FILE = "simplelogger.properties"; private static long START_TIME = System.currentTimeMillis(); - private static final Properties SIMPLE_LOGGER_PROPS = new Properties(); - - private static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT; - private static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT; - private static final int LOG_LEVEL_INFO = LocationAwareLogger.INFO_INT; - private static final int LOG_LEVEL_WARN = LocationAwareLogger.WARN_INT; - private static final int LOG_LEVEL_ERROR = LocationAwareLogger.ERROR_INT; - // The OFF level can only be used in configuration files to disable logging. It has + + protected static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT; + protected static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT; + protected static final int LOG_LEVEL_INFO = LocationAwareLogger.INFO_INT; + protected static final int LOG_LEVEL_WARN = LocationAwareLogger.WARN_INT; + protected static final int LOG_LEVEL_ERROR = LocationAwareLogger.ERROR_INT; + // The OFF level can only be used in configuration files to disable logging. + // It has // no printing method associated with it in o.s.Logger interface. - private static final int LOG_LEVEL_OFF = LOG_LEVEL_ERROR + 10; + protected static final int LOG_LEVEL_OFF = LOG_LEVEL_ERROR + 10; private static boolean INITIALIZED = false; - - private static int DEFAULT_LOG_LEVEL = LOG_LEVEL_INFO; - private static boolean SHOW_DATE_TIME = false; - private static String DATE_TIME_FORMAT_STR = null; - private static DateFormat DATE_FORMATTER = null; - private static boolean SHOW_THREAD_NAME = true; - private static boolean SHOW_LOG_NAME = true; - private static boolean SHOW_SHORT_LOG_NAME = false; - private static String LOG_FILE = "System.err"; - private static PrintStream TARGET_STREAM = null; - private static boolean LEVEL_IN_BRACKETS = false; - private static String WARN_LEVEL_STRING = "WARN"; - - /** All system properties used by SimpleLogger start with this prefix */ - public static final String SYSTEM_PREFIX = "org.slf4j.simpleLogger."; - - public static final String DEFAULT_LOG_LEVEL_KEY = SYSTEM_PREFIX + "defaultLogLevel"; - public static final String SHOW_DATE_TIME_KEY = SYSTEM_PREFIX + "showDateTime"; - public static final String DATE_TIME_FORMAT_KEY = SYSTEM_PREFIX + "dateTimeFormat"; - public static final String SHOW_THREAD_NAME_KEY = SYSTEM_PREFIX + "showThreadName"; - public static final String SHOW_LOG_NAME_KEY = SYSTEM_PREFIX + "showLogName"; - public static final String SHOW_SHORT_LOG_NAME_KEY = SYSTEM_PREFIX + "showShortLogName"; - public static final String LOG_FILE_KEY = SYSTEM_PREFIX + "logFile"; - public static final String LEVEL_IN_BRACKETS_KEY = SYSTEM_PREFIX + "levelInBrackets"; - public static final String WARN_LEVEL_STRING_KEY = SYSTEM_PREFIX + "warnLevelString"; - - public static final String LOG_KEY_PREFIX = SYSTEM_PREFIX + "log."; - - private static String getStringProperty(String name) { - String prop = null; - try { - prop = System.getProperty(name); - } catch (SecurityException e) { - ; // Ignore - } - return (prop == null) ? SIMPLE_LOGGER_PROPS.getProperty(name) : prop; - } - - private static String getStringProperty(String name, String defaultValue) { - String prop = getStringProperty(name); - return (prop == null) ? defaultValue : prop; - } - - private static boolean getBooleanProperty(String name, boolean defaultValue) { - String prop = getStringProperty(name); - return (prop == null) ? defaultValue : "true".equalsIgnoreCase(prop); - } + static SimpleLoggerConfiguration CONFIG_PARAMS = null; static void lazyInit() { if (INITIALIZED) { @@ -189,76 +166,12 @@ INITIALIZED = true; init(); } - + + // external software might be invoking this method directly. Do not rename + // or change its semantics. static void init() { - loadProperties(); - - String defaultLogLevelString = getStringProperty(DEFAULT_LOG_LEVEL_KEY, null); - if (defaultLogLevelString != null) - DEFAULT_LOG_LEVEL = stringToLevel(defaultLogLevelString); - - SHOW_LOG_NAME = getBooleanProperty(SHOW_LOG_NAME_KEY, SHOW_LOG_NAME); - SHOW_SHORT_LOG_NAME = getBooleanProperty(SHOW_SHORT_LOG_NAME_KEY, SHOW_SHORT_LOG_NAME); - SHOW_DATE_TIME = getBooleanProperty(SHOW_DATE_TIME_KEY, SHOW_DATE_TIME); - SHOW_THREAD_NAME = getBooleanProperty(SHOW_THREAD_NAME_KEY, SHOW_THREAD_NAME); - DATE_TIME_FORMAT_STR = getStringProperty(DATE_TIME_FORMAT_KEY, DATE_TIME_FORMAT_STR); - LEVEL_IN_BRACKETS = getBooleanProperty(LEVEL_IN_BRACKETS_KEY, LEVEL_IN_BRACKETS); - WARN_LEVEL_STRING = getStringProperty(WARN_LEVEL_STRING_KEY, WARN_LEVEL_STRING); - - LOG_FILE = getStringProperty(LOG_FILE_KEY, LOG_FILE); - TARGET_STREAM = computeTargetStream(LOG_FILE); - - if (DATE_TIME_FORMAT_STR != null) { - try { - DATE_FORMATTER = new SimpleDateFormat(DATE_TIME_FORMAT_STR); - } catch (IllegalArgumentException e) { - Util.report("Bad date format in " + CONFIGURATION_FILE + "; will output relative time", e); - } - } - } - - private static PrintStream computeTargetStream(String logFile) { - if ("System.err".equalsIgnoreCase(logFile)) - return System.err; - else if ("System.out".equalsIgnoreCase(logFile)) { - return System.out; - } else { - try { - FileOutputStream fos = new FileOutputStream(logFile); - PrintStream printStream = new PrintStream(fos); - return printStream; - } catch (FileNotFoundException e) { - Util.report("Could not open [" + logFile + "]. Defaulting to System.err", e); - return System.err; - } - } - } - - private static void loadProperties() { - // Add props from the resource simplelogger.properties - InputStream in = AccessController.doPrivileged(new PrivilegedAction() { - public InputStream run() { - ClassLoader threadCL = Thread.currentThread().getContextClassLoader(); - if (threadCL != null) { - return threadCL.getResourceAsStream(CONFIGURATION_FILE); - } else { - return ClassLoader.getSystemResourceAsStream(CONFIGURATION_FILE); - } - } - }); - if (null != in) { - try { - SIMPLE_LOGGER_PROPS.load(in); - } catch (java.io.IOException e) { - // ignored - } finally { - try { - in.close(); - } catch (java.io.IOException e) { - // ignored - } - } - } + CONFIG_PARAMS = new SimpleLoggerConfiguration(); + CONFIG_PARAMS.init(); } /** The current log level */ @@ -267,6 +180,34 @@ private transient String shortLogName = null; /** + * All system properties used by SimpleLogger start with this + * prefix + */ + public static final String SYSTEM_PREFIX = "org.slf4j.simpleLogger."; + + public static final String LOG_KEY_PREFIX = SimpleLogger.SYSTEM_PREFIX + "log."; + + public static final String CACHE_OUTPUT_STREAM_STRING_KEY = SimpleLogger.SYSTEM_PREFIX + "cacheOutputStream"; + + public static final String WARN_LEVEL_STRING_KEY = SimpleLogger.SYSTEM_PREFIX + "warnLevelString"; + + public static final String LEVEL_IN_BRACKETS_KEY = SimpleLogger.SYSTEM_PREFIX + "levelInBrackets"; + + public static final String LOG_FILE_KEY = SimpleLogger.SYSTEM_PREFIX + "logFile"; + + public static final String SHOW_SHORT_LOG_NAME_KEY = SimpleLogger.SYSTEM_PREFIX + "showShortLogName"; + + public static final String SHOW_LOG_NAME_KEY = SimpleLogger.SYSTEM_PREFIX + "showLogName"; + + public static final String SHOW_THREAD_NAME_KEY = SimpleLogger.SYSTEM_PREFIX + "showThreadName"; + + public static final String DATE_TIME_FORMAT_KEY = SimpleLogger.SYSTEM_PREFIX + "dateTimeFormat"; + + public static final String SHOW_DATE_TIME_KEY = SimpleLogger.SYSTEM_PREFIX + "showDateTime"; + + public static final String DEFAULT_LOG_LEVEL_KEY = SimpleLogger.SYSTEM_PREFIX + "defaultLogLevel"; + + /** * Package access allows only {@link SimpleLoggerFactory} to instantiate * SimpleLogger instances. */ @@ -275,9 +216,9 @@ String levelString = recursivelyComputeLevelString(); if (levelString != null) { - this.currentLogLevel = stringToLevel(levelString); + this.currentLogLevel = SimpleLoggerConfiguration.stringToLevel(levelString); } else { - this.currentLogLevel = DEFAULT_LOG_LEVEL; + this.currentLogLevel = CONFIG_PARAMS.defaultLogLevel; } } @@ -287,37 +228,22 @@ int indexOfLastDot = tempName.length(); while ((levelString == null) && (indexOfLastDot > -1)) { tempName = tempName.substring(0, indexOfLastDot); - levelString = getStringProperty(LOG_KEY_PREFIX + tempName, null); + levelString = CONFIG_PARAMS.getStringProperty(SimpleLogger.LOG_KEY_PREFIX + tempName, null); indexOfLastDot = String.valueOf(tempName).lastIndexOf("."); } return levelString; } - private static int stringToLevel(String levelStr) { - if ("trace".equalsIgnoreCase(levelStr)) { - return LOG_LEVEL_TRACE; - } else if ("debug".equalsIgnoreCase(levelStr)) { - return LOG_LEVEL_DEBUG; - } else if ("info".equalsIgnoreCase(levelStr)) { - return LOG_LEVEL_INFO; - } else if ("warn".equalsIgnoreCase(levelStr)) { - return LOG_LEVEL_WARN; - } else if ("error".equalsIgnoreCase(levelStr)) { - return LOG_LEVEL_ERROR; - } else if ("off".equalsIgnoreCase(levelStr)) { - return LOG_LEVEL_OFF; - } - // assume INFO by default - return LOG_LEVEL_INFO; - } - - /** - * This is our internal implementation for logging regular (non-parameterized) - * log messages. + /** + * This is our internal implementation for logging regular + * (non-parameterized) log messages. * - * @param level One of the LOG_LEVEL_XXX constants defining the log level - * @param message The message itself - * @param t The exception whose stack trace should be logged + * @param level + * One of the LOG_LEVEL_XXX constants defining the log level + * @param message + * The message itself + * @param t + * The exception whose stack trace should be logged */ private void log(int level, String message, Throwable t) { if (!isLevelEnabled(level)) { @@ -327,8 +253,8 @@ StringBuilder buf = new StringBuilder(32); // Append date-time if so configured - if (SHOW_DATE_TIME) { - if (DATE_FORMATTER != null) { + if (CONFIG_PARAMS.showDateTime) { + if (CONFIG_PARAMS.dateFormatter != null) { buf.append(getFormattedDate()); buf.append(' '); } else { @@ -338,43 +264,28 @@ } // Append current thread name if so configured - if (SHOW_THREAD_NAME) { + if (CONFIG_PARAMS.showThreadName) { buf.append('['); buf.append(Thread.currentThread().getName()); buf.append("] "); } - if (LEVEL_IN_BRACKETS) + if (CONFIG_PARAMS.levelInBrackets) buf.append('['); // Append a readable representation of the log level - switch (level) { - case LOG_LEVEL_TRACE: - buf.append("TRACE"); - break; - case LOG_LEVEL_DEBUG: - buf.append("DEBUG"); - break; - case LOG_LEVEL_INFO: - buf.append("INFO"); - break; - case LOG_LEVEL_WARN: - buf.append(WARN_LEVEL_STRING); - break; - case LOG_LEVEL_ERROR: - buf.append("ERROR"); - break; - } - if (LEVEL_IN_BRACKETS) + String levelStr = renderLevel(level); + buf.append(levelStr); + if (CONFIG_PARAMS.levelInBrackets) buf.append(']'); buf.append(' '); // Append the name of the log instance if so configured - if (SHOW_SHORT_LOG_NAME) { + if (CONFIG_PARAMS.showShortLogName) { if (shortLogName == null) shortLogName = computeShortName(); buf.append(String.valueOf(shortLogName)).append(" - "); - } else if (SHOW_LOG_NAME) { + } else if (CONFIG_PARAMS.showLogName) { buf.append(String.valueOf(name)).append(" - "); } @@ -385,19 +296,41 @@ } + protected String renderLevel(int level) { + switch (level) { + case LOG_LEVEL_TRACE: + return "TRACE"; + case LOG_LEVEL_DEBUG: + return ("DEBUG"); + case LOG_LEVEL_INFO: + return "INFO"; + case LOG_LEVEL_WARN: + return CONFIG_PARAMS.warnLevelString; + case LOG_LEVEL_ERROR: + return "ERROR"; + } + throw new IllegalStateException("Unrecognized level [" + level + "]"); + } + void write(StringBuilder buf, Throwable t) { - TARGET_STREAM.println(buf.toString()); + PrintStream targetStream = CONFIG_PARAMS.outputChoice.getTargetPrintStream(); + + targetStream.println(buf.toString()); + writeThrowable(t, targetStream); + targetStream.flush(); + } + + protected void writeThrowable(Throwable t, PrintStream targetStream) { if (t != null) { - t.printStackTrace(TARGET_STREAM); - } - TARGET_STREAM.flush(); + t.printStackTrace(targetStream); + } } private String getFormattedDate() { Date now = new Date(); String dateText; - synchronized (DATE_FORMATTER) { - dateText = DATE_FORMATTER.format(now); + synchronized (CONFIG_PARAMS.dateFormatter) { + dateText = CONFIG_PARAMS.dateFormatter.format(now); } return dateText; } @@ -427,7 +360,8 @@ * * @param level * @param format - * @param arguments a list of 3 ore more arguments + * @param arguments + * a list of 3 ore more arguments */ private void formatAndLog(int level, String format, Object... arguments) { if (!isLevelEnabled(level)) { @@ -440,7 +374,8 @@ /** * Is the given log level currently enabled? * - * @param logLevel is this level enabled? + * @param logLevel + * is this level enabled? */ protected boolean isLevelEnabled(int logLevel) { // log level are numerically ordered so can use simple numeric @@ -454,8 +389,8 @@ } /** - * A simple implementation which logs messages of level TRACE according - * to the format outlined above. + * A simple implementation which logs messages of level TRACE according to + * the format outlined above. */ public void trace(String msg) { log(LOG_LEVEL_TRACE, msg, null); @@ -496,8 +431,8 @@ } /** - * A simple implementation which logs messages of level DEBUG according - * to the format outlined above. + * A simple implementation which logs messages of level DEBUG according to + * the format outlined above. */ public void debug(String msg) { log(LOG_LEVEL_DEBUG, msg, null); @@ -538,8 +473,8 @@ } /** - * A simple implementation which logs messages of level INFO according - * to the format outlined above. + * A simple implementation which logs messages of level INFO according to + * the format outlined above. */ public void info(String msg) { log(LOG_LEVEL_INFO, msg, null); @@ -580,8 +515,8 @@ } /** - * A simple implementation which always logs messages of level WARN according - * to the format outlined above. + * A simple implementation which always logs messages of level WARN + * according to the format outlined above. */ public void warn(String msg) { log(LOG_LEVEL_WARN, msg, null); @@ -622,8 +557,8 @@ } /** - * A simple implementation which always logs messages of level ERROR according - * to the format outlined above. + * A simple implementation which always logs messages of level ERROR + * according to the format outlined above. */ public void error(String msg) { log(LOG_LEVEL_ERROR, msg, null); diff --git a/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java new file mode 100644 index 0000000..d538b0f --- /dev/null +++ b/slf4j-simple/src/main/java/org/slf4j/impl/SimpleLoggerConfiguration.java @@ -0,0 +1,186 @@ +package org.slf4j.impl; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Properties; + +import org.slf4j.helpers.Util; +import org.slf4j.impl.OutputChoice.OutputChoiceType; + +/** + * This class holds configuration values for {@link SimpleLogger}. The + * values are computed at runtime. See {@link SimpleLogger} documentation for + * more information. + * + * + * @author Ceki Gülcü + * @author Scott Sanders + * @author Rod Waldhoff + * @author Robert Burrell Donkin + * @author Cédrik LIME + * + * @since 1.7.25 + */ +public class SimpleLoggerConfiguration { + + private static final String CONFIGURATION_FILE = "simplelogger.properties"; + + static int DEFAULT_LOG_LEVEL_DEFAULT = SimpleLogger.LOG_LEVEL_INFO; + int defaultLogLevel = DEFAULT_LOG_LEVEL_DEFAULT; + + private static final boolean SHOW_DATE_TIME_DEFAULT = false; + boolean showDateTime = SHOW_DATE_TIME_DEFAULT; + + private static final String DATE_TIME_FORMAT_STR_DEFAULT = null; + private static String dateTimeFormatStr = DATE_TIME_FORMAT_STR_DEFAULT; + + DateFormat dateFormatter = null; + + private static final boolean SHOW_THREAD_NAME_DEFAULT = true; + boolean showThreadName = SHOW_THREAD_NAME_DEFAULT; + + final static boolean SHOW_LOG_NAME_DEFAULT = true; + boolean showLogName = SHOW_LOG_NAME_DEFAULT; + + private static final boolean SHOW_SHORT_LOG_NAME_DEFAULT = false; + boolean showShortLogName = SHOW_SHORT_LOG_NAME_DEFAULT; + + private static final boolean LEVEL_IN_BRACKETS_DEFAULT = false; + boolean levelInBrackets = LEVEL_IN_BRACKETS_DEFAULT; + + private static String LOG_FILE_DEFAULT = "System.err"; + private String logFile = LOG_FILE_DEFAULT; + OutputChoice outputChoice = null; + + private static final boolean CACHE_OUTPUT_STREAM_DEFAULT = false; + private boolean cacheOutputStream = CACHE_OUTPUT_STREAM_DEFAULT; + + private static final String WARN_LEVELS_STRING_DEFAULT = "WARN"; + String warnLevelString = WARN_LEVELS_STRING_DEFAULT; + + private final Properties properties = new Properties(); + + void init() { + loadProperties(); + + String defaultLogLevelString = getStringProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, null); + if (defaultLogLevelString != null) + defaultLogLevel = stringToLevel(defaultLogLevelString); + + showLogName = getBooleanProperty(SimpleLogger.SHOW_LOG_NAME_KEY, SimpleLoggerConfiguration.SHOW_LOG_NAME_DEFAULT); + showShortLogName = getBooleanProperty(SimpleLogger.SHOW_SHORT_LOG_NAME_KEY, SHOW_SHORT_LOG_NAME_DEFAULT); + showDateTime = getBooleanProperty(SimpleLogger.SHOW_DATE_TIME_KEY, SHOW_DATE_TIME_DEFAULT); + showThreadName = getBooleanProperty(SimpleLogger.SHOW_THREAD_NAME_KEY, SHOW_THREAD_NAME_DEFAULT); + dateTimeFormatStr = getStringProperty(SimpleLogger.DATE_TIME_FORMAT_KEY, DATE_TIME_FORMAT_STR_DEFAULT); + levelInBrackets = getBooleanProperty(SimpleLogger.LEVEL_IN_BRACKETS_KEY, LEVEL_IN_BRACKETS_DEFAULT); + warnLevelString = getStringProperty(SimpleLogger.WARN_LEVEL_STRING_KEY, WARN_LEVELS_STRING_DEFAULT); + + logFile = getStringProperty(SimpleLogger.LOG_FILE_KEY, logFile); + + cacheOutputStream = getBooleanProperty(SimpleLogger.CACHE_OUTPUT_STREAM_STRING_KEY, CACHE_OUTPUT_STREAM_DEFAULT); + outputChoice = computeOutputChoice(logFile, cacheOutputStream); + + if (dateTimeFormatStr != null) { + try { + dateFormatter = new SimpleDateFormat(dateTimeFormatStr); + } catch (IllegalArgumentException e) { + Util.report("Bad date format in " + CONFIGURATION_FILE + "; will output relative time", e); + } + } + } + + private void loadProperties() { + // Add props from the resource simplelogger.properties + InputStream in = AccessController.doPrivileged(new PrivilegedAction() { + public InputStream run() { + ClassLoader threadCL = Thread.currentThread().getContextClassLoader(); + if (threadCL != null) { + return threadCL.getResourceAsStream(CONFIGURATION_FILE); + } else { + return ClassLoader.getSystemResourceAsStream(CONFIGURATION_FILE); + } + } + }); + if (null != in) { + try { + properties.load(in); + } catch (java.io.IOException e) { + // ignored + } finally { + try { + in.close(); + } catch (java.io.IOException e) { + // ignored + } + } + } + } + + String getStringProperty(String name, String defaultValue) { + String prop = getStringProperty(name); + return (prop == null) ? defaultValue : prop; + } + + boolean getBooleanProperty(String name, boolean defaultValue) { + String prop = getStringProperty(name); + return (prop == null) ? defaultValue : "true".equalsIgnoreCase(prop); + } + + String getStringProperty(String name) { + String prop = null; + try { + prop = System.getProperty(name); + } catch (SecurityException e) { + ; // Ignore + } + return (prop == null) ? properties.getProperty(name) : prop; + } + + static int stringToLevel(String levelStr) { + if ("trace".equalsIgnoreCase(levelStr)) { + return SimpleLogger.LOG_LEVEL_TRACE; + } else if ("debug".equalsIgnoreCase(levelStr)) { + return SimpleLogger.LOG_LEVEL_DEBUG; + } else if ("info".equalsIgnoreCase(levelStr)) { + return SimpleLogger.LOG_LEVEL_INFO; + } else if ("warn".equalsIgnoreCase(levelStr)) { + return SimpleLogger.LOG_LEVEL_WARN; + } else if ("error".equalsIgnoreCase(levelStr)) { + return SimpleLogger.LOG_LEVEL_ERROR; + } else if ("off".equalsIgnoreCase(levelStr)) { + return SimpleLogger.LOG_LEVEL_OFF; + } + // assume INFO by default + return SimpleLogger.LOG_LEVEL_INFO; + } + + private static OutputChoice computeOutputChoice(String logFile, boolean cacheOutputStream) { + if ("System.err".equalsIgnoreCase(logFile)) + if (cacheOutputStream) + return new OutputChoice(OutputChoiceType.CACHED_SYS_ERR); + else + return new OutputChoice(OutputChoiceType.SYS_ERR); + else if ("System.out".equalsIgnoreCase(logFile)) { + if (cacheOutputStream) + return new OutputChoice(OutputChoiceType.CACHED_SYS_OUT); + else + return new OutputChoice(OutputChoiceType.SYS_OUT); + } else { + try { + FileOutputStream fos = new FileOutputStream(logFile); + PrintStream printStream = new PrintStream(fos); + return new OutputChoice(printStream); + } catch (FileNotFoundException e) { + Util.report("Could not open [" + logFile + "]. Defaulting to System.err", e); + return new OutputChoice(OutputChoiceType.SYS_ERR); + } + } + } + +} diff --git a/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerTest.java b/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerTest.java index 812c3e2..4e1fe30 100644 --- a/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerTest.java +++ b/slf4j-simple/src/test/java/org/slf4j/impl/SimpleLoggerTest.java @@ -24,15 +24,24 @@ */ package org.slf4j.impl; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; - public class SimpleLoggerTest { String A_KEY = SimpleLogger.LOG_KEY_PREFIX + "a"; + PrintStream original = System.out; + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + PrintStream replacement = new PrintStream(bout); @Before public void before() { @@ -42,6 +51,8 @@ @After public void after() { System.clearProperty(A_KEY); + System.clearProperty(SimpleLogger.CACHE_OUTPUT_STREAM_STRING_KEY); + System.setErr(original); } @Test @@ -53,14 +64,17 @@ @Test public void offLevel() { System.setProperty(A_KEY, "off"); + SimpleLogger.init(); SimpleLogger simpleLogger = new SimpleLogger("a"); assertEquals("off", simpleLogger.recursivelyComputeLevelString()); assertFalse(simpleLogger.isErrorEnabled()); } - + @Test public void loggerNameWithNoDots_WithLevel() { + SimpleLogger.init(); SimpleLogger simpleLogger = new SimpleLogger("a"); + assertEquals("info", simpleLogger.recursivelyComputeLevelString()); } @@ -82,4 +96,28 @@ assertNull(simpleLogger.recursivelyComputeLevelString()); } + @Test + public void checkUseOfLastSystemStreamReference() { + SimpleLogger.init(); + SimpleLogger simpleLogger = new SimpleLogger(this.getClass().getName()); + + System.setErr(replacement); + simpleLogger.info("hello"); + replacement.flush(); + assertTrue(bout.toString().contains("INFO org.slf4j.impl.SimpleLoggerTest - hello")); + } + + @Test + public void checkUseOfCachedOutputStream() { + System.setErr(replacement); + System.setProperty(SimpleLogger.CACHE_OUTPUT_STREAM_STRING_KEY, "true"); + SimpleLogger.init(); + SimpleLogger simpleLogger = new SimpleLogger(this.getClass().getName()); + // change reference to original before logging + System.setErr(original); + + simpleLogger.info("hello"); + replacement.flush(); + assertTrue(bout.toString().contains("INFO org.slf4j.impl.SimpleLoggerTest - hello")); + } } diff --git a/slf4j-site/pom.xml b/slf4j-site/pom.xml index cae0048..183e998 100644 --- a/slf4j-site/pom.xml +++ b/slf4j-site/pom.xml @@ -7,7 +7,7 @@ org.slf4j slf4j-parent - 1.7.22 + 1.7.25 slf4j-site