add slf4j-reload4j module

Signed-off-by: Ceki Gulcu <ceki@qos.ch>
This commit is contained in:
Ceki Gulcu 2022-01-13 15:21:26 +01:00
parent 0d4167abe7
commit 0e04efdbf6
18 changed files with 1144 additions and 1 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2004-2017 QOS.ch Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland)
All rights reserved. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining

View File

@ -44,6 +44,7 @@
<!-- used in integration testing --> <!-- used in integration testing -->
<slf4j.api.minimum.compatible.version>1.6.0</slf4j.api.minimum.compatible.version> <slf4j.api.minimum.compatible.version>1.6.0</slf4j.api.minimum.compatible.version>
<cal10n.version>0.8.1</cal10n.version> <cal10n.version>0.8.1</cal10n.version>
<reload4j.version>1.2.18.0</reload4j.version>
<log4j.version>1.2.17</log4j.version> <log4j.version>1.2.17</log4j.version>
<logback.version>1.2.3</logback.version> <logback.version>1.2.3</logback.version>
<junit.version>4.13.1</junit.version> <junit.version>4.13.1</junit.version>
@ -74,6 +75,7 @@
<module>slf4j-jdk14</module> <module>slf4j-jdk14</module>
<module>slf4j-jdk-platform-logging</module> <module>slf4j-jdk-platform-logging</module>
<module>slf4j-log4j12</module> <module>slf4j-log4j12</module>
<module>slf4j-reload4j</module>
<module>slf4j-ext</module> <module>slf4j-ext</module>
<module>jcl-over-slf4j</module> <module>jcl-over-slf4j</module>
<module>log4j-over-slf4j</module> <module>log4j-over-slf4j</module>
@ -123,6 +125,12 @@
<version>${log4j.version}</version> <version>${log4j.version}</version>
</dependency> </dependency>
<dependency>
<groupId>ch.qos.reload4j</groupId>
<artifactId>reload4j</artifactId>
<version>${reload4j.version}</version>
</dependency>
<dependency> <dependency>
<groupId>ch.qos.cal10n</groupId> <groupId>ch.qos.cal10n</groupId>
<artifactId>cal10n-api</artifactId> <artifactId>cal10n-api</artifactId>

View File

@ -0,0 +1,24 @@
Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland)
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.

67
slf4j-reload4j/pom.xml Normal file
View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-parent</artifactId>
<version>2.0.0-alpha6-SNAPSHOT</version>
</parent>
<artifactId>slf4j-reload4j</artifactId>
<packaging>jar</packaging>
<name>SLF4J Reload4j Binding</name>
<description>SLF4J Reload4j Binding</description>
<url>http://reload4j.qos.ch</url>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.reload4j</groupId>
<artifactId>reload4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<type>test-jar</type>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
<reportFormat>plain</reportFormat>
<trimStackTrace>false</trimStackTrace>
<excludes>
<exclude>**/AllTest.java</exclude>
<exclude>**/PackageTest.java</exclude>
</excludes>
<argLine>-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8001</argLine>
<!--<argLine>XXadd-opens log4j/org.apache.log4j=org.slf4j.log4j12</argLine>-->
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,232 @@
/**
* 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.reload4j;
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.event.SubstituteLoggingEvent;
import org.slf4j.helpers.LegacyAbstractLogger;
import org.slf4j.helpers.MessageFormatter;
import org.slf4j.helpers.NormalizedParameters;
import org.slf4j.helpers.SubstituteLogger;
import org.slf4j.spi.LocationAwareLogger;
import org.slf4j.spi.LoggingEventAware;
import org.slf4j.spi.LoggingEventBuilder;
/**
* A wrapper over {@link org.apache.log4j.Logger org.apache.log4j.Logger} in
* conforming to the {@link Logger} interface.
*
* <p>
* Note that the logging levels mentioned in this class refer to those defined
* in the <a href=
* "http://logging.apache.org/log4j/docs/api/org/apache/log4j/Level.html">
* <code>org.apache.log4j.Level</code></a> class.
*
* <p>
* The TRACE level was introduced in log4j version 1.2.12. In order to avoid
* crashing the host application, in the case the log4j version in use predates
* 1.2.12, the TRACE level will be mapped as DEBUG. See also
* <a href="http://jira.qos.ch/browse/SLF4J-59">SLF4J-59</a>.
*
* @author Ceki G&uuml;lc&uuml;
*/
public final class Reload4jLoggerAdapter extends LegacyAbstractLogger implements LocationAwareLogger, LoggingEventAware, Serializable {
private static final long serialVersionUID = 6182834493563598289L;
final transient org.apache.log4j.Logger logger;
/**
* Following the pattern discussed in pages 162 through 168 of "The complete
* log4j manual".
*/
final static String FQCN_NOMINAL = org.slf4j.helpers.AbstractLogger.class.getName();
final static String FQCN_SUBSTITUE = FQCN_NOMINAL;
final static String FQCN_FLUENT = org.slf4j.spi.DefaultLoggingEventBuilder.class.getName();
// Does the log4j version in use recognize the TRACE level?
// The trace level was introduced in log4j 1.2.12.
final boolean traceCapable;
// WARN: Log4jLoggerAdapter constructor should have only package access so
// that only Log4jLoggerFactory be able to create one.
Reload4jLoggerAdapter(org.apache.log4j.Logger logger) {
this.logger = logger;
this.name = logger.getName();
traceCapable = isTraceCapable();
}
private boolean isTraceCapable() {
try {
logger.isTraceEnabled();
return true;
} catch (NoSuchMethodError e) {
return false;
}
}
/**
* Is this logger instance enabled for the TRACE level?
*
* @return True if this Logger is enabled for level TRACE, false otherwise.
*/
public boolean isTraceEnabled() {
if (traceCapable) {
return logger.isTraceEnabled();
} else {
return logger.isDebugEnabled();
}
}
/**
* Is this logger instance enabled for the DEBUG level?
*
* @return True if this Logger is enabled for level DEBUG, false otherwise.
*/
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
/**
* Is this logger instance enabled for the INFO level?
*
* @return True if this Logger is enabled for the INFO level, false otherwise.
*/
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
/**
* Is this logger instance enabled for the WARN level?
*
* @return True if this Logger is enabled for the WARN level, false otherwise.
*/
public boolean isWarnEnabled() {
return logger.isEnabledFor(Level.WARN);
}
/**
* Is this logger instance enabled for level ERROR?
*
* @return True if this Logger is enabled for level ERROR, false otherwise.
*/
public boolean isErrorEnabled() {
return logger.isEnabledFor(Level.ERROR);
}
@Override
public void log(Marker marker, String callerFQCN, int level, String msg, Object[] arguments, Throwable t) {
Level log4jLevel = toLog4jLevel(level);
NormalizedParameters np = NormalizedParameters.normalize(msg, arguments, t);
String formattedMessage = MessageFormatter.basicArrayFormat(np.getMessage(), np.getArguments());
logger.log(callerFQCN, log4jLevel, formattedMessage, np.getThrowable());
}
@Override
protected void handleNormalizedLoggingCall(org.slf4j.event.Level level, Marker marker, String msg, Object[] arguments, Throwable throwable) {
Level log4jLevel = toLog4jLevel(level.toInt());
String formattedMessage = MessageFormatter.basicArrayFormat(msg, arguments);
logger.log(getFullyQualifiedCallerName(), log4jLevel, formattedMessage, throwable);
}
/**
* Called by {@link SubstituteLogger} or by {@link LoggingEventBuilder} instances
* @param event
*/
public void log(LoggingEvent event) {
Level log4jLevel = toLog4jLevel(event.getLevel().toInt());
if (!logger.isEnabledFor(log4jLevel))
return;
org.apache.log4j.spi.LoggingEvent log4jevent = event2Log4jEvent(event, log4jLevel);
logger.callAppenders(log4jevent);
}
private org.apache.log4j.spi.LoggingEvent event2Log4jEvent(LoggingEvent event, Level log4jLevel) {
String formattedMessage = MessageFormatter.basicArrayFormat(event.getMessage(), event.getArgumentArray());
LocationInfo locationInfo = null;
String fcqn = null;
if (event instanceof SubstituteLoggingEvent) {
locationInfo = new LocationInfo(NA_SUBST, NA_SUBST, NA_SUBST, "0");
fcqn = FQCN_SUBSTITUE;
} else {
fcqn = FQCN_FLUENT;
}
ThrowableInformation ti = null;
Throwable t = event.getThrowable();
if (t != null)
ti = new ThrowableInformation(t);
org.apache.log4j.spi.LoggingEvent log4jEvent = new org.apache.log4j.spi.LoggingEvent(fcqn, logger, event.getTimeStamp(), log4jLevel, formattedMessage,
event.getThreadName(), ti, null, locationInfo, null);
return log4jEvent;
}
private Level toLog4jLevel(int slf4jLevelInt) {
Level log4jLevel;
switch (slf4jLevelInt) {
case LocationAwareLogger.TRACE_INT:
log4jLevel = traceCapable ? Level.TRACE : Level.DEBUG;
break;
case LocationAwareLogger.DEBUG_INT:
log4jLevel = Level.DEBUG;
break;
case LocationAwareLogger.INFO_INT:
log4jLevel = Level.INFO;
break;
case LocationAwareLogger.WARN_INT:
log4jLevel = Level.WARN;
break;
case LocationAwareLogger.ERROR_INT:
log4jLevel = Level.ERROR;
break;
default:
throw new IllegalStateException("Level number " + slf4jLevelInt + " is not recognized.");
}
return log4jLevel;
}
@Override
protected String getFullyQualifiedCallerName() {
return FQCN_NOMINAL;
}
}

View File

@ -0,0 +1,90 @@
/**
* 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.reload4j;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.log4j.LogManager;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.helpers.Util;
/**
* Log4jLoggerFactory is an implementation of {@link ILoggerFactory} returning
* the appropriate named {@link Reload4jLoggerAdapter} instance.
*
* @author Ceki G&uuml;lc&uuml;
*/
public class Reload4jLoggerFactory implements ILoggerFactory {
private static final String LOG4J_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#log4jDelegationLoop";
// check for delegation loops
static {
try {
Class.forName("org.apache.log4j.Log4jLoggerFactory");
String part1 = "Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. ";
String part2 = "See also " + LOG4J_DELEGATION_LOOP_URL + " for more details.";
Util.report(part1);
Util.report(part2);
throw new IllegalStateException(part1 + part2);
} catch (ClassNotFoundException e) {
// this is the good case
}
}
// key: name (String), value: a Log4jLoggerAdapter;
ConcurrentMap<String, Logger> loggerMap;
public Reload4jLoggerFactory() {
loggerMap = new ConcurrentHashMap<>();
// force log4j to initialize
org.apache.log4j.LogManager.getRootLogger();
}
/*
* (non-Javadoc)
*
* @see org.slf4j.ILoggerFactory#getLogger(java.lang.String)
*/
public Logger getLogger(String name) {
Logger slf4jLogger = loggerMap.get(name);
if (slf4jLogger != null) {
return slf4jLogger;
} else {
org.apache.log4j.Logger log4jLogger;
if (name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME))
log4jLogger = LogManager.getRootLogger();
else
log4jLogger = LogManager.getLogger(name);
Logger newInstance = new Reload4jLoggerAdapter(log4jLogger);
Logger oldInstance = loggerMap.putIfAbsent(name, newInstance);
return oldInstance == null ? newInstance : oldInstance;
}
}
}

View File

@ -0,0 +1,126 @@
/**
* Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland)
* 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.reload4j;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.helpers.ThreadLocalMapOfStacks;
import org.slf4j.spi.MDCAdapter;
public class Reload4jMDCAdapter implements MDCAdapter {
private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();
@Override
public void clear() {
@SuppressWarnings("rawtypes")
Map map = org.apache.log4j.MDC.getContext();
if (map != null) {
map.clear();
}
}
@Override
public String get(String key) {
return (String) org.apache.log4j.MDC.get(key);
}
/**
* Put a context value (the <code>val</code> parameter) as identified with
* the <code>key</code> parameter into the current thread's context map. The
* <code>key</code> parameter cannot be null. Log4j does <em>not</em>
* support null for the <code>val</code> parameter.
*
* <p>
* This method delegates all work to log4j's MDC.
*
* @throws IllegalArgumentException
* in case the "key" or <b>"val"</b> parameter is null
*/
@Override
public void put(String key, String val) {
org.apache.log4j.MDC.put(key, val);
}
@Override
public void remove(String key) {
org.apache.log4j.MDC.remove(key);
}
@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" })
@Override
public void setContextMap(Map<String, String> contextMap) {
Map old = org.apache.log4j.MDC.getContext();
// we must cater for the case where the contextMap argument is null
if (contextMap == null) {
if (old != null) {
old.clear();
}
return;
}
if (old == null) {
for (Map.Entry<String, String> mapEntry : contextMap.entrySet()) {
org.apache.log4j.MDC.put(mapEntry.getKey(), mapEntry);
}
} else {
old.clear();
old.putAll(contextMap);
}
}
@Override
public void pushByKey(String key, String value) {
threadLocalMapOfDeques.pushByKey(key, value);
}
@Override
public String popByKey(String key) {
return threadLocalMapOfDeques.popByKey(key);
}
@Override
public Deque<String> getCopyOfDequeByKey(String key) {
return threadLocalMapOfDeques.getCopyOfDequeByKey(key);
}
@Override
public void clearDequeByKey(String key) {
threadLocalMapOfDeques.clearDequeByKey(key);
}
}

View File

@ -0,0 +1,61 @@
package org.slf4j.reload4j;
import org.apache.log4j.Level;
import org.slf4j.ILoggerFactory;
import org.slf4j.IMarkerFactory;
import org.slf4j.helpers.BasicMarkerFactory;
import org.slf4j.helpers.Util;
import org.slf4j.spi.MDCAdapter;
import org.slf4j.spi.SLF4JServiceProvider;
public class Reload4jServiceProvider implements SLF4JServiceProvider {
/**
* 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 = "2.0.99"; // !final
private ILoggerFactory loggerFactory;
private IMarkerFactory markerFactory;
private MDCAdapter mdcAdapter;
public Reload4jServiceProvider() {
try {
@SuppressWarnings("unused")
Level level = Level.TRACE;
} catch (NoSuchFieldError nsfe) {
Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
}
}
@Override
public void initialize() {
loggerFactory = new Reload4jLoggerFactory();
markerFactory = new BasicMarkerFactory();
mdcAdapter = new Reload4jMDCAdapter();
}
@Override
public ILoggerFactory getLoggerFactory() {
return loggerFactory;
}
@Override
public IMarkerFactory getMarkerFactory() {
return markerFactory;
}
@Override
public MDCAdapter getMDCAdapter() {
return mdcAdapter;
}
@Override
public String getRequestedApiVersion() {
return REQUESTED_API_VERSION;
}
}

View File

@ -0,0 +1,12 @@
Implementation-Title: slf4j-reload4j
Bundle-ManifestVersion: 2
Bundle-SymbolicName: slf4j.reload4j
Bundle-Name: slf4j-reload4j
Bundle-Vendor: SLF4J.ORG
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: org.slf4j.reload4j;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},
org.apache.log4j

View File

@ -0,0 +1 @@
org.slf4j.reload4j.Reload4jServiceProvider

View File

@ -0,0 +1,209 @@
/**
* 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.reload4j;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
/**
* Test whether invoking the SLF4J API causes problems or not.
*
* @author Ceki Gulcu
*
*/
public class InvocationTest {
ListAppender listAppender = new ListAppender();
org.apache.log4j.Logger root;
@Before
public void setUp() throws Exception {
root = org.apache.log4j.Logger.getRootLogger();
root.addAppender(listAppender);
}
@After
public void tearDown() throws Exception {
root.getLoggerRepository().resetConfiguration();
}
@Test
public void test1() {
Logger logger = LoggerFactory.getLogger("test1");
logger.debug("Hello world.");
assertEquals(1, listAppender.list.size());
}
@Test
public void test2() {
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");
logger.trace("Hello trace.");
logger.debug("Hello world 1.");
logger.debug("Hello world {}", i1);
logger.debug("val={} val={}", i1, i2);
logger.debug("val={} val={} val={}", new Object[] { i1, i2, i3 });
logger.debug("Hello world 2", e);
logger.info("Hello world 2.");
logger.warn("Hello world 3.");
logger.warn("Hello world 3", e);
logger.error("Hello world 4.");
logger.error("Hello world {}", Integer.valueOf(3));
logger.error("Hello world 4.", e);
assertEquals(11, listAppender.list.size());
}
@Test
public void testNull() {
Logger logger = LoggerFactory.getLogger("testNull");
logger.trace(null);
logger.debug(null);
logger.info(null);
logger.warn(null);
logger.error(null);
Exception e = new Exception("This is a test exception.");
logger.debug(null, e);
logger.info(null, e);
logger.warn(null, e);
logger.error(null, e);
assertEquals(8, listAppender.list.size());
}
// http://jira.qos.ch/browse/SLF4J-69
// formerly http://bugzilla.slf4j.org/show_bug.cgi?id=78
@Test
public void testNullParameter_BUG78() {
Logger logger = LoggerFactory.getLogger("testNullParameter_BUG78");
String[] parameters = null;
String msg = "hello {}";
logger.debug(msg, (Object[]) parameters);
assertEquals(1, listAppender.list.size());
LoggingEvent e = (LoggingEvent) listAppender.list.get(0);
assertEquals(msg, e.getMessage());
}
@Test
public void testMarker() {
Logger logger = LoggerFactory.getLogger("testMarker");
Marker blue = MarkerFactory.getMarker("BLUE");
logger.trace(blue, "hello");
logger.debug(blue, "hello");
logger.info(blue, "hello");
logger.warn(blue, "hello");
logger.error(blue, "hello");
logger.debug(blue, "hello {}", "world");
logger.info(blue, "hello {}", "world");
logger.warn(blue, "hello {}", "world");
logger.error(blue, "hello {}", "world");
logger.debug(blue, "hello {} and {} ", "world", "universe");
logger.info(blue, "hello {} and {} ", "world", "universe");
logger.warn(blue, "hello {} and {} ", "world", "universe");
logger.error(blue, "hello {} and {} ", "world", "universe");
assertEquals(12, listAppender.list.size());
}
@Test
public void testMDC() {
MDC.put("k", "v");
assertNotNull(MDC.get("k"));
assertEquals("v", MDC.get("k"));
MDC.remove("k");
assertNull(MDC.get("k"));
MDC.put("k1", "v1");
assertEquals("v1", MDC.get("k1"));
MDC.clear();
assertNull(MDC.get("k1"));
try {
MDC.put(null, "x");
fail("null keys are invalid");
} catch (IllegalArgumentException e) {
}
}
@Test
public void testMDCContextMapValues() {
Map<String, String> map = new HashMap<>();
map.put("ka", "va");
map.put("kb", "vb");
MDC.put("k", "v");
assertEquals("v", MDC.get("k"));
MDC.setContextMap(map);
assertNull(MDC.get("k"));
assertEquals("va", MDC.get("ka"));
assertEquals("vb", MDC.get("kb"));
}
@Test
public void testCallerInfo() {
Logger logger = LoggerFactory.getLogger("testMarker");
listAppender.extractLocationInfo = true;
logger.debug("hello");
LoggingEvent event = listAppender.list.get(0);
assertEquals(this.getClass().getName(), event.getLocationInformation().getClassName());
}
@Test
public void testCallerInfoWithFluentAPI() {
Logger logger = LoggerFactory.getLogger("testMarker");
listAppender.extractLocationInfo = true;
logger.atDebug().log("hello");
LoggingEvent event = listAppender.list.get(0);
assertEquals(this.getClass().getName(), event.getLocationInformation().getClassName());
}
}

View File

@ -0,0 +1,53 @@
/**
* 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.reload4j;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class ListAppender extends AppenderSkeleton {
public List<LoggingEvent> list = new ArrayList<>();
public boolean extractLocationInfo = false;
protected void append(LoggingEvent event) {
list.add(event);
if (extractLocationInfo) {
event.getLocationInformation();
}
}
public void close() {
}
public boolean requiresLayout() {
return false;
}
}

View File

@ -0,0 +1,72 @@
/**
* 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.reload4j;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.slf4j.reload4j.testHarness.RecursiveAppender;
public class Log4j12MultithreadedInitializationTest extends org.slf4j.testHarness.MultithreadedInitializationTest {
static int NUM_LINES_BY_RECURSIVE_APPENDER = 3;
// value of LogManager.DEFAULT_CONFIGURATION_KEY;
static String CONFIG_FILE_KEY = "log4j.configuration";
final String loggerName = this.getClass().getName();
@Before
public void setup() {
System.setProperty(CONFIG_FILE_KEY, "recursiveInitWithActivationDelay.properties");
System.out.println("THREAD_COUNT=" + THREAD_COUNT);
}
@After
public void tearDown() throws Exception {
System.clearProperty(CONFIG_FILE_KEY);
}
protected long getRecordedEventCount() {
List<LoggingEvent> eventList = getRecordedEvents();
assertNotNull(eventList);
return eventList.size();
}
protected int extraLogEvents() {
return NUM_LINES_BY_RECURSIVE_APPENDER;
}
private List<LoggingEvent> getRecordedEvents() {
org.apache.log4j.Logger root = LogManager.getRootLogger();
RecursiveAppender ra = (RecursiveAppender) root.getAppender("RECURSIVE");
assertNotNull(ra);
return ra.events;
}
}

View File

@ -0,0 +1,28 @@
package org.slf4j.reload4j;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.slf4j.helpers.MDCAdapterTestBase;
import org.slf4j.reload4j.Reload4jMDCAdapter;
import org.slf4j.spi.MDCAdapter;
public class Log4jMDCAdapterTest extends MDCAdapterTestBase {
protected MDCAdapter instantiateMDC() {
return new Reload4jMDCAdapter();
}
@Test
public void testClearingMDC() {
mdc.put("testKey", "testValue");
assertFalse(mdc.getCopyOfContextMap().isEmpty());
mdc.clear();
assertTrue(mdc.getCopyOfContextMap().isEmpty());
}
}

View File

@ -0,0 +1,54 @@
/**
* 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.reload4j;
import java.util.Random;
import org.junit.After;
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);
String loggerName = "org.slf4j.impl.RecursiveInitializationTest";
@After
public void tearDown() throws Exception {
System.clearProperty(CONFIG_FILE_KEY);
}
@Test
public void loggingDuringInitialization() {
System.setProperty(CONFIG_FILE_KEY, "recursiveInit.properties");
Logger logger = LoggerFactory.getLogger(loggerName + ".loggingDuringInitialization-" + diff);
logger.info("hello");
}
}

View File

@ -0,0 +1,88 @@
/**
* 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.reload4j.testHarness;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RecursiveAppender extends AppenderSkeleton {
int diff = new Random().nextInt();
int activationDelay = 0;
String loggerName = "org.slf4j.impl.RecursiveAppender" + diff;
public List<LoggingEvent> events = new ArrayList<>();
public RecursiveAppender() {
System.out.println("XXXXXXX 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 e) {
events.add(e);
}
public void close() {
}
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;
}
}

View File

@ -0,0 +1,9 @@
log4j.debug=true
log4j.rootLogger=DEBUG, RECURSIVE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%t] %c - %m%n
log4j.appender.RECURSIVE=org.slf4j.reload4j.testHarness.RecursiveAppender

View File

@ -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 [%t] %c - %m%n
log4j.appender.RECURSIVE=org.slf4j.reload4j.testHarness.RecursiveAppender
log4j.appender.RECURSIVE.activationDelay=10