This is an automated email from the ASF dual-hosted git repository. rgoers pushed a commit to branch release-2.x in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit be81f5922024b67ba9d4c52d79b98349cc03df4f Author: Ralph Goers <[email protected]> AuthorDate: Sat Jul 27 20:24:07 2019 -0700 LOG4J2-2556 - Make Log4j Core optional --- log4j-1.2-api/pom.xml | 1 + .../src/main/java/org/apache/log4j/Category.java | 100 +++++++++++++++------ .../src/main/java/org/apache/log4j/LogManager.java | 25 +++++- .../src/main/java/org/apache/log4j/Logger.java | 4 +- .../org/apache/log4j/legacy/core/CategoryUtil.java | 65 ++++++++++++++ .../org/apache/log4j/legacy/core/ContextUtil.java | 34 +++++++ log4j-1.2-api/src/site/markdown/index.md | 20 ++++- .../test/java/org/apache/log4j/CategoryTest.java | 4 +- .../src/test/java/org/apache/log4j/LoggerTest.java | 40 ++++----- src/site/xdoc/runtime-dependencies.xml | 2 +- 10 files changed, 236 insertions(+), 59 deletions(-) diff --git a/log4j-1.2-api/pom.xml b/log4j-1.2-api/pom.xml index 8a40ed6..d42fe62 100644 --- a/log4j-1.2-api/pom.xml +++ b/log4j-1.2-api/pom.xml @@ -63,6 +63,7 @@ <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> + <optional>true</optional> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java index 873aa0e..84a18d8 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java @@ -24,10 +24,11 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.log4j.helpers.NullEnumeration; +import org.apache.log4j.legacy.core.CategoryUtil; import org.apache.log4j.spi.LoggerFactory; import org.apache.log4j.spi.LoggingEvent; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.util.NameUtil; +import org.apache.logging.log4j.spi.ExtendedLogger; +import org.apache.logging.log4j.spi.LoggerContext; import org.apache.logging.log4j.message.LocalizedMessage; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.ObjectMessage; @@ -47,12 +48,26 @@ public class Category { private static final String FQCN = Category.class.getName(); + private static final boolean isCoreAvailable; + + + static { + boolean available; + + try { + available = Class.forName("org.apache.logging.log4j.core.Logger") != null; + } catch (Exception ex) { + available = false; + } + isCoreAvailable = available; + } + /** * Resource bundle for localized messages. */ protected ResourceBundle bundle = null; - private final org.apache.logging.log4j.core.Logger logger; + private final org.apache.logging.log4j.Logger logger; /** * Constructor used by Logger to specify a LoggerContext. @@ -71,7 +86,7 @@ public class Category { this(PrivateManager.getContext(), name); } - private Category(final org.apache.logging.log4j.core.Logger logger) { + private Category(final org.apache.logging.log4j.Logger logger) { this.logger = logger; } @@ -117,16 +132,20 @@ public class Category { return logger.getName(); } - org.apache.logging.log4j.core.Logger getLogger() { + org.apache.logging.log4j.Logger getLogger() { return logger; } public final Category getParent() { - final org.apache.logging.log4j.core.Logger parent = logger.getParent(); - if (parent == null) { + if (!isCoreAvailable) { + return null; + } + org.apache.logging.log4j.Logger parent = CategoryUtil.getParent(logger); + LoggerContext loggerContext = CategoryUtil.getLoggerContext(logger); + if (parent == null || loggerContext == null) { return null; } - final ConcurrentMap<String, Logger> loggers = getLoggersMap(logger.getContext()); + final ConcurrentMap<String, Logger> loggers = getLoggersMap(loggerContext); final Logger l = loggers.get(parent.getName()); return l == null ? new Category(parent) : l; } @@ -182,8 +201,6 @@ public class Category { return Level.ERROR; case FATAL: return Level.FATAL; - case OFF: - return Level.OFF; default: // TODO Should this be an IllegalStateException? return Level.OFF; @@ -199,7 +216,7 @@ public class Category { } public void setLevel(final Level level) { - logger.setLevel(org.apache.logging.log4j.Level.toLevel(level.levelStr)); + setLevel(level.levelStr); } public final Level getPriority() { @@ -207,7 +224,13 @@ public class Category { } public void setPriority(final Priority priority) { - logger.setLevel(org.apache.logging.log4j.Level.toLevel(priority.levelStr)); + setLevel(priority.levelStr); + } + + private void setLevel(final String levelStr) { + if (isCoreAvailable) { + CategoryUtil.setLevel(logger, org.apache.logging.log4j.Level.toLevel(levelStr)); + } } public void debug(final Object message) { @@ -354,7 +377,11 @@ public class Category { public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) { final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString()); final Message msg = message instanceof Message ? (Message) message : new ObjectMessage(message); - logger.logMessage(fqcn, lvl, null, msg, t); + if (logger instanceof ExtendedLogger) { + ((ExtendedLogger) logger).logMessage(fqcn, lvl, null, new ObjectMessage(message), t); + } else { + logger.log(lvl, msg, t); + } } public boolean exists(final String name) { @@ -362,11 +389,13 @@ public class Category { } public boolean getAdditivity() { - return logger.isAdditive(); + return isCoreAvailable ? CategoryUtil.isAdditive(logger) : false; } public void setAdditivity(final boolean additivity) { - logger.setAdditive(additivity); + if (isCoreAvailable) { + CategoryUtil.setAdditivity(logger, additivity); + } } public void setResourceBundle(final ResourceBundle bundle) { @@ -378,19 +407,32 @@ public class Category { return bundle; } String name = logger.getName(); - final ConcurrentMap<String, Logger> loggers = getLoggersMap(logger.getContext()); - while ((name = NameUtil.getSubName(name)) != null) { - final Logger subLogger = loggers.get(name); - if (subLogger != null) { - final ResourceBundle rb = subLogger.bundle; - if (rb != null) { - return rb; + if (isCoreAvailable) { + LoggerContext ctx = CategoryUtil.getLoggerContext(logger); + if (ctx != null) { + final ConcurrentMap<String, Logger> loggers = getLoggersMap(ctx); + while ((name = getSubName(name)) != null) { + final Logger subLogger = loggers.get(name); + if (subLogger != null) { + final ResourceBundle rb = subLogger.bundle; + if (rb != null) { + return rb; + } + } } } } return null; } + private static String getSubName(final String name) { + if (Strings.isEmpty(name)) { + return null; + } + final int i = name.lastIndexOf('.'); + return i > 0 ? name.substring(0, i) : Strings.EMPTY; + } + /** If <code>assertion</code> parameter is {@code false}, then logs <code>msg</code> as an {@link #error(Object) error} statement. @@ -448,8 +490,12 @@ public class Category { private void maybeLog(final String fqcn, final org.apache.logging.log4j.Level level, final Object message, final Throwable throwable) { - if (logger.isEnabled(level, null, message, throwable)) { - logger.logMessage(FQCN, level, null, new ObjectMessage(message), throwable); + if (logger.isEnabled(level)) { + if (logger instanceof ExtendedLogger) { + ((ExtendedLogger) logger).logMessage(fqcn, level, null, new ObjectMessage(message), throwable); + } else { + logger.log(level, message, throwable); + } } } @@ -457,7 +503,7 @@ public class Category { @Override protected Logger newLogger(final String name, final org.apache.logging.log4j.spi.LoggerContext context) { - return new Logger((LoggerContext) context, name); + return new Logger(context, name); } @Override @@ -473,7 +519,7 @@ public class Category { private static final String FQCN = Category.class.getName(); public static LoggerContext getContext() { - return (LoggerContext) getContext(FQCN, false); + return getContext(FQCN, false); } public static org.apache.logging.log4j.Logger getLogger(final String name) { @@ -482,7 +528,7 @@ public class Category { } private boolean isEnabledFor(final org.apache.logging.log4j.Level level) { - return logger.isEnabled(level, null, null); + return logger.isEnabled(level); } } diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java b/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java index 751cb86..a4b6802 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/LogManager.java @@ -19,11 +19,12 @@ package org.apache.log4j; import java.util.Enumeration; import org.apache.log4j.helpers.NullEnumeration; +import org.apache.log4j.legacy.core.ContextUtil; import org.apache.log4j.spi.HierarchyEventListener; import org.apache.log4j.spi.LoggerFactory; import org.apache.log4j.spi.LoggerRepository; import org.apache.log4j.spi.RepositorySelector; -import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.spi.LoggerContext; import org.apache.logging.log4j.util.Strings; /** @@ -63,6 +64,20 @@ public final class LogManager { private static final LoggerRepository REPOSITORY = new Repository(); + private static final boolean isLog4jCore; + + static { + boolean core = false; + try { + if (Class.forName("org.apache.logging.log4j.core.LoggerContext") != null) { + core = true; + } + } catch (Exception ex) { + // Ignore the exception; + } + isLog4jCore = core; + } + private LogManager() { } @@ -96,8 +111,10 @@ public final class LogManager { } static void reconfigure() { - final LoggerContext ctx = PrivateManager.getContext(); - ctx.reconfigure(); + if (isLog4jCore) { + final LoggerContext ctx = PrivateManager.getContext(); + ContextUtil.reconfigure(ctx); + } } /** @@ -212,7 +229,7 @@ public final class LogManager { private static final String FQCN = LogManager.class.getName(); public static LoggerContext getContext() { - return (LoggerContext) getContext(FQCN, false); + return getContext(FQCN, false); } public static org.apache.logging.log4j.Logger getLogger(final String name) { diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java index fb7277b..fe1f26a 100644 --- a/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Logger.java @@ -18,7 +18,7 @@ package org.apache.log4j; import org.apache.log4j.spi.LoggerFactory; -import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.spi.LoggerContext; /** * @@ -56,7 +56,7 @@ public class Logger extends Category { private static final String FQCN = Logger.class.getName(); public static LoggerContext getContext() { - return (LoggerContext) getContext(FQCN, false); + return getContext(FQCN, false); } public static org.apache.logging.log4j.Logger getLogger(final String name) { diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java b/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java new file mode 100644 index 0000000..f9e9f7c --- /dev/null +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/CategoryUtil.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.log4j.legacy.core; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.spi.LoggerContext; + +/** + * Provide access to Log4j Core Logger methods. + */ +public final class CategoryUtil { + + private CategoryUtil() { + } + + public static boolean isAdditive(Logger logger) { + if (logger instanceof org.apache.logging.log4j.core.Logger) { + return ((org.apache.logging.log4j.core.Logger) logger).isAdditive(); + } + return false; + } + + public static void setAdditivity(Logger logger, boolean additivity) { + if (logger instanceof org.apache.logging.log4j.core.Logger) { + ((org.apache.logging.log4j.core.Logger) logger).setAdditive(additivity); + } + } + + public static Logger getParent(Logger logger) { + if (logger instanceof org.apache.logging.log4j.core.Logger) { + return ((org.apache.logging.log4j.core.Logger) logger).getParent(); + + } + return null; + } + + public static LoggerContext getLoggerContext(Logger logger) { + if (logger instanceof org.apache.logging.log4j.core.Logger) { + return ((org.apache.logging.log4j.core.Logger) logger).getContext(); + } + return null; + } + + public static void setLevel(Logger logger, Level level) { + if (logger instanceof org.apache.logging.log4j.core.Logger) { + ((org.apache.logging.log4j.core.Logger) logger).setLevel(level); + + } + } +} diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/ContextUtil.java b/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/ContextUtil.java new file mode 100644 index 0000000..d3b99fa --- /dev/null +++ b/log4j-1.2-api/src/main/java/org/apache/log4j/legacy/core/ContextUtil.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ +package org.apache.log4j.legacy.core; + +import org.apache.logging.log4j.spi.LoggerContext; + +/** + * Implements LoggerContext methods specific to log4j-core. + */ +public final class ContextUtil { + + private ContextUtil() { + } + + public static void reconfigure(LoggerContext ctx) { + if (ctx instanceof org.apache.logging.log4j.core.LoggerContext) { + ((org.apache.logging.log4j.core.LoggerContext) ctx).reconfigure(); + } + } +} diff --git a/log4j-1.2-api/src/site/markdown/index.md b/log4j-1.2-api/src/site/markdown/index.md index a80e687..696e0bb 100644 --- a/log4j-1.2-api/src/site/markdown/index.md +++ b/log4j-1.2-api/src/site/markdown/index.md @@ -18,12 +18,26 @@ # Log4j 1.2 Bridge -The Log4j 1.2 Bridge allows applications coded to use Log4j 1.2 API to use -Log4j 2 instead. +The Log4j 1.2 Bridge allows applications coded to use Log4j 1.2 API to use Log4j 2 instead. ## Requirements -The Log4j 1.2 bridge is dependent on the Log4j 2 API and implementation. +The Log4j 1.2 bridge is dependent on the Log4j 2 API. The following Log4j 1.x methods will behave differently when +the Log4j 2 Core module is included then when it is not: + +| Method | Without log4j-core | With log4j-core | +| ----------------------------- | ------------------ | ------------------------------------ | +| Category.getParent() | Returns null | Returns parent logger | +| Category.setLevel() | NoOp | Sets Logger Level | +| Category.setPriority() | NoOp | Sets Logger Level | +| Category.getAdditivity() | Returns false | Returns Logger's additivity setting | +| Category.setAdditivity() | NoOp | Sets additivity of LoggerConfig | +| Category.getResourceBundle() | NoOp | Returns the resource bundle associated with the Logger | +| BasicConfigurator.configure() | NoOp | Reconfigures Log4j 2 | + +If log4j-core is not present location information will not be accurate in calls using the Log4j 1.2 API. The config +package which attempts tp convert Log4j 1.x configurations to Log4j 2 is not supported without Log4j 2. + For more information, see [Runtime Dependencies](../runtime-dependencies.html). ## Usage diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java index f671193..6a8af76 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java @@ -74,7 +74,7 @@ public class CategoryTest { public void testForcedLog() { final MockCategory category = new MockCategory("org.example.foo"); category.setAdditivity(false); - category.getLogger().addAppender(appender); + ((org.apache.logging.log4j.core.Logger) category.getLogger()).addAppender(appender); category.info("Hello, World"); final List<LogEvent> list = appender.getEvents(); int events = list.size(); @@ -172,7 +172,7 @@ public class CategoryTest { final ListAppender appender = new ListAppender("List2", null, layout, false, false); appender.start(); category.setAdditivity(false); - category.getLogger().addAppender(appender); + ((org.apache.logging.log4j.core.Logger) category.getLogger()).addAppender(appender); category.error("Test Message"); final List<String> msgs = appender.getMessages(); assertTrue("Incorrect number of messages. Expected 1 got " + msgs.size(), msgs.size() == 1); diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/LoggerTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/LoggerTest.java index 48b073d..0c4308f 100644 --- a/log4j-1.2-api/src/test/java/org/apache/log4j/LoggerTest.java +++ b/log4j-1.2-api/src/test/java/org/apache/log4j/LoggerTest.java @@ -122,7 +122,7 @@ public class LoggerTest { final CountingAppender coutingAppender = new CountingAppender(); coutingAppender.start(); try { - loggerA.getLogger().addAppender(coutingAppender); + ((org.apache.logging.log4j.core.Logger) loggerA.getLogger()).addAppender(coutingAppender); assertEquals(0, coutingAppender.counter); loggerAB.debug(MSG); @@ -135,7 +135,7 @@ public class LoggerTest { assertEquals(4, coutingAppender.counter); coutingAppender.stop(); } finally { - loggerA.getLogger().removeAppender(coutingAppender); + ((org.apache.logging.log4j.core.Logger) loggerA.getLogger()).removeAppender(coutingAppender); } } @@ -155,8 +155,8 @@ public class LoggerTest { ca2.start(); try { - a.getLogger().addAppender(ca1); - abc.getLogger().addAppender(ca2); + ((org.apache.logging.log4j.core.Logger) a.getLogger()).addAppender(ca1); + ((org.apache.logging.log4j.core.Logger) abc.getLogger()).addAppender(ca2); assertEquals(ca1.counter, 0); assertEquals(ca2.counter, 0); @@ -175,8 +175,8 @@ public class LoggerTest { ca1.stop(); ca2.stop(); } finally { - a.getLogger().removeAppender(ca1); - abc.getLogger().removeAppender(ca2); + ((org.apache.logging.log4j.core.Logger) a.getLogger()).removeAppender(ca1); + ((org.apache.logging.log4j.core.Logger) abc.getLogger()).removeAppender(ca2); }} /** @@ -197,9 +197,9 @@ public class LoggerTest { final CountingAppender caABC = new CountingAppender(); caABC.start(); try { - root.getLogger().addAppender(caRoot); - a.getLogger().addAppender(caA); - abc.getLogger().addAppender(caABC); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(caRoot); + ((org.apache.logging.log4j.core.Logger) a.getLogger()).addAppender(caA); + ((org.apache.logging.log4j.core.Logger) abc.getLogger()).addAppender(caABC); assertEquals(caRoot.counter, 0); assertEquals(caA.counter, 0); @@ -225,9 +225,9 @@ public class LoggerTest { caA.stop(); caABC.stop(); } finally { - root.getLogger().removeAppender(caRoot); - a.getLogger().removeAppender(caA); - abc.getLogger().removeAppender(caABC); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(caRoot); + ((org.apache.logging.log4j.core.Logger) a.getLogger()).removeAppender(caA); + ((org.apache.logging.log4j.core.Logger) abc.getLogger()).removeAppender(caABC); }} /* Don't support getLoggerRepository @@ -390,7 +390,7 @@ public class LoggerTest { final ListAppender appender = new ListAppender("List"); appender.start(); final Logger root = Logger.getRootLogger(); - root.getLogger().addAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender); root.setLevel(Level.INFO); final Logger tracer = Logger.getLogger("com.example.Tracer"); @@ -406,7 +406,7 @@ public class LoggerTest { assertEquals(org.apache.logging.log4j.Level.TRACE, event.getLevel()); assertEquals("Message 1", event.getMessage().getFormat()); appender.stop(); - root.getLogger().removeAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender); } /** @@ -418,7 +418,7 @@ public class LoggerTest { appender.start(); final Logger root = Logger.getRootLogger(); try { - root.getLogger().addAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender); root.setLevel(Level.INFO); final Logger tracer = Logger.getLogger("com.example.Tracer"); @@ -436,7 +436,7 @@ public class LoggerTest { assertEquals("Message 1", event.getMessage().getFormattedMessage()); appender.stop(); } finally { - root.getLogger().removeAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender); } } @@ -449,7 +449,7 @@ public class LoggerTest { appender.start(); final Logger root = Logger.getRootLogger(); try { - root.getLogger().addAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender); root.setLevel(Level.INFO); final Logger tracer = Logger.getLogger("com.example.Tracer"); @@ -459,7 +459,7 @@ public class LoggerTest { assertFalse(root.isTraceEnabled()); appender.stop(); } finally { - root.getLogger().removeAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender); } } @@ -471,7 +471,7 @@ public class LoggerTest { appender.start(); final Logger root = Logger.getRootLogger(); try { - root.getLogger().addAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).addAppender(appender); root.setLevel(Level.INFO); final MyLogger log = new MyLogger(root); log.logInfo("This is a test", null); @@ -483,7 +483,7 @@ public class LoggerTest { assertTrue("Message contains incorrect class name: " + msg, msg.contains(LoggerTest.class.getName())); appender.stop(); } finally { - root.getLogger().removeAppender(appender); + ((org.apache.logging.log4j.core.Logger) root.getLogger()).removeAppender(appender); } } diff --git a/src/site/xdoc/runtime-dependencies.xml b/src/site/xdoc/runtime-dependencies.xml index 4a5c118..5ce30ff 100644 --- a/src/site/xdoc/runtime-dependencies.xml +++ b/src/site/xdoc/runtime-dependencies.xml @@ -314,7 +314,7 @@ <h4>log4j-1.2-api</h4> <p> The <a href="log4j-1.2-api/index.html">Log4j 1.2 Bridge</a> has no external dependencies. - This only requires the Log4j API and Log4j Core. + This only requires the Log4j API. Including Log4j Core provides optional, extra functionality. </p> <a name="log4j-slf4j-impl" />
