You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2022/01/09 21:26:14 UTC

[logging-log4j2] branch release-2.x updated (e730f06 -> aa59026)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git.


    from e730f06  Merge branch 'release-2.x' of https://gitbox.apache.org/repos/asf/logging-log4j2 into release-2.x
     new f64791b  Refactor 1.2 bridge internals to use a single private log manager and adapter.
     new aa59026  Refactor 1.2 bridge internals to use a single private log manager and adapter.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 log4j-1.2-api/pom.xml                              |  20 +-
 .../java/org/apache/log4j/BasicConfigurator.java   |  14 +-
 .../src/main/java/org/apache/log4j/Category.java   | 176 ++++-----------
 .../src/main/java/org/apache/log4j/Hierarchy.java  | 133 +++++++-----
 .../src/main/java/org/apache/log4j/LogManager.java | 237 ++++++++-------------
 .../src/main/java/org/apache/log4j/Logger.java     |  26 ++-
 ...CategoryFactory.java => LoggerRepository2.java} |  14 +-
 .../main/java/org/apache/log4j/spi/RootLogger.java |   3 +-
 .../test/java/org/apache/log4j/CategoryTest.java   |   4 +-
 .../test/java/org/apache/log4j/LogManagerTest.java |  12 +-
 10 files changed, 270 insertions(+), 369 deletions(-)
 copy log4j-1.2-api/src/main/java/org/apache/log4j/{DefaultCategoryFactory.java => LoggerRepository2.java} (73%)

[logging-log4j2] 02/02: Refactor 1.2 bridge internals to use a single private log manager and adapter.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit aa59026b7597bb4534de1f09cde61b3ab2694628
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Jan 9 16:26:11 2022 -0500

    Refactor 1.2 bridge internals to use a single private log manager and
    adapter.
    
    - Implement LogManager.getCurrentLoggers().
    - The class loader found in the bridge and passed down instead of a
    FQCN.
    - Adds a package private extension to LoggerRepository called
    LoggerRepository2 to allow class loader propagation.
    - Core availability is computed once in LogManager.
    - Move Log4j to the top of POM dependencies
    - Split commit 1/2 for cherry-picking to master.
---
 log4j-1.2-api/pom.xml | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/log4j-1.2-api/pom.xml b/log4j-1.2-api/pom.xml
index ca24cd3..0fab36a 100644
--- a/log4j-1.2-api/pom.xml
+++ b/log4j-1.2-api/pom.xml
@@ -35,6 +35,17 @@
     <maven.doap.skip>true</maven.doap.skip>
   </properties>
   <dependencies>
+    <!-- Log4j Runtime -->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <!-- JUnit -->
     <dependency>
       <groupId>org.junit.vintage</groupId>
       <artifactId>junit-vintage-engine</artifactId>
@@ -62,18 +73,9 @@
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-api</artifactId>
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-core</artifactId>
-      <optional>true</optional>
-    </dependency>
     <!-- Used for JMS appenders (needs an implementation of course) -->
     <dependency>
       <groupId>org.jboss.spec.javax.jms</groupId>

[logging-log4j2] 01/02: Refactor 1.2 bridge internals to use a single private log manager and adapter.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f64791b10cbcea8a8cf3ccbad924c74071f0211c
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Jan 9 16:26:07 2022 -0500

    Refactor 1.2 bridge internals to use a single private log manager and
    adapter.
    
    - Implement LogManager.getCurrentLoggers().
    - The class loader found in the bridge and passed down instead of a
    FQCN.
    - Adds a package private extension to LoggerRepository called
    LoggerRepository2 to allow class loader propagation.
    - Core availability is computed once in LogManager.
    - Move Log4j to the top of POM dependencies
    - Split commit 1/2 for cherry-picking to master.
---
 .../java/org/apache/log4j/BasicConfigurator.java   |  14 +-
 .../src/main/java/org/apache/log4j/Category.java   | 176 ++++-----------
 .../src/main/java/org/apache/log4j/Hierarchy.java  | 133 +++++++-----
 .../src/main/java/org/apache/log4j/LogManager.java | 237 ++++++++-------------
 .../src/main/java/org/apache/log4j/Logger.java     |  26 ++-
 .../java/org/apache/log4j/LoggerRepository2.java   |  31 +++
 .../main/java/org/apache/log4j/spi/RootLogger.java |   3 +-
 .../test/java/org/apache/log4j/CategoryTest.java   |   4 +-
 .../test/java/org/apache/log4j/LogManagerTest.java |  12 +-
 9 files changed, 283 insertions(+), 353 deletions(-)

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/BasicConfigurator.java b/log4j-1.2-api/src/main/java/org/apache/log4j/BasicConfigurator.java
index 2b7ec7f..da90e2c 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/BasicConfigurator.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/BasicConfigurator.java
@@ -18,12 +18,11 @@ package org.apache.log4j;
 
 /**
  * Provided for compatibility with Log4j 1.x.
+ *
+ * @since 0.8.1
  */
 public class BasicConfigurator {
 
-    protected BasicConfigurator() {
-    }
-
     public static void configure() {
         LogManager.reconfigure();
     }
@@ -36,10 +35,13 @@ public class BasicConfigurator {
         // no-op
     }
 
+    public static void resetConfiguration() {
+        LogManager.resetConfiguration();
+    }
+
     /**
-     * No-op implementation.
+     * Constructs a new instance.
      */
-    public static void resetConfiguration() {
-        // no-op
+    protected BasicConfigurator() {
     }
 }
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 7d0cb11..286ae32 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
@@ -19,8 +19,6 @@ package org.apache.log4j;
 import java.util.Enumeration;
 import java.util.Map;
 import java.util.ResourceBundle;
-import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 import org.apache.log4j.helpers.NullEnumeration;
@@ -28,18 +26,16 @@ import org.apache.log4j.legacy.core.CategoryUtil;
 import org.apache.log4j.or.ObjectRenderer;
 import org.apache.log4j.or.RendererMap;
 import org.apache.log4j.spi.AppenderAttachable;
-import org.apache.log4j.spi.LoggerFactory;
 import org.apache.log4j.spi.LoggerRepository;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.spi.RendererSupport;
 import org.apache.logging.log4j.message.LocalizedMessage;
 import org.apache.logging.log4j.message.MapMessage;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.ObjectMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.spi.AbstractLoggerAdapter;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.StackLocatorUtil;
 import org.apache.logging.log4j.util.Strings;
 
 /**
@@ -47,26 +43,8 @@ import org.apache.logging.log4j.util.Strings;
  */
 public class Category implements AppenderAttachable {
 
-    private static PrivateAdapter adapter = new PrivateAdapter();
-
-    private static final Map<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP =
-        new WeakHashMap<>();
-
     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;
-    }
-
     /**
      * The name of this category.
      */
@@ -79,14 +57,14 @@ public class Category implements AppenderAttachable {
      * to <code>false</code> too. See the user manual for more details.
      */
     protected boolean additive = true;
-    
+
     /**
      * The assigned level of this category. The <code>level</code> variable need not be assigned a value in which case it is
      * inherited form the hierarchy.
      */
     volatile protected Level level;
 
-    private final RendererMap rendererMap;
+    private RendererMap rendererMap;
 
     /**
      * The parent of this category. All categories have at least one ancestor which is the root category.
@@ -112,7 +90,7 @@ public class Category implements AppenderAttachable {
         this.name = name;
         this.logger = context.getLogger(name);
         this.repository = LogManager.getLoggerRepository();
-        this.rendererMap = ((RendererSupport) repository).getRendererMap();
+        //this.rendererMap = ((RendererSupport) repository).getRendererMap();
     }
 
     /**
@@ -120,50 +98,22 @@ public class Category implements AppenderAttachable {
      * @param name The name of the Logger.
      */
     protected Category(final String name) {
-        this(PrivateManager.getContext(), name);
+        this(Hierarchy.getContext(), name);
     }
 
-    private Category(final org.apache.logging.log4j.Logger logger) {
+    Category(final org.apache.logging.log4j.Logger logger) {
         this.logger = logger;
-        rendererMap = ((RendererSupport) LogManager.getLoggerRepository()).getRendererMap();
+        //rendererMap = ((RendererSupport) LogManager.getLoggerRepository()).getRendererMap();
     }
 
     public static Category getInstance(final String name) {
-        return getInstance(PrivateManager.getContext(), name, adapter);
-    }
-
-    static Logger getInstance(final LoggerContext context, final String name) {
-        return getInstance(context, name, adapter);
-    }
-
-    static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
-        final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
-        Logger logger = loggers.get(name);
-        if (logger != null) {
-            return logger;
-        }
-        logger = factory.makeNewLoggerInstance(name);
-        final Logger prev = loggers.putIfAbsent(name, logger);
-        return prev == null ? logger : prev;
-    }
-
-    static Logger getInstance(final LoggerContext context, final String name, final PrivateAdapter factory) {
-        final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
-        Logger logger = loggers.get(name);
-        if (logger != null) {
-            return logger;
-        }
-        logger = factory.newLogger(name, context);
-        final Logger prev = loggers.putIfAbsent(name, logger);
-        return prev == null ? logger : prev;
+        // Depth 2 gets the call site of this method.
+        return LogManager.getLogger(name, StackLocatorUtil.getCallerClassLoader(2));
     }
 
     public static Category getInstance(@SuppressWarnings("rawtypes") final Class clazz) {
-        return getInstance(clazz.getName());
-    }
-
-    static Logger getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) {
-        return getInstance(context, clazz.getName());
+        // Depth 2 gets the call site of this method.
+        return LogManager.getLogger(clazz.getName(), StackLocatorUtil.getCallerClassLoader(2));
     }
 
     public final String getName() {
@@ -175,15 +125,15 @@ public class Category implements AppenderAttachable {
     }
 
     public final Category getParent() {
-        if (!isCoreAvailable) {
+        if (!LogManager.isLog4jCorePresent()) {
             return null;
         }
-        org.apache.logging.log4j.Logger parent = CategoryUtil.getParent(logger);
-        LoggerContext loggerContext = CategoryUtil.getLoggerContext(logger);
+        final org.apache.logging.log4j.Logger parent = CategoryUtil.getParent(logger);
+        final LoggerContext loggerContext = CategoryUtil.getLoggerContext(logger);
         if (parent == null || loggerContext == null) {
             return null;
         }
-        final ConcurrentMap<String, Logger> loggers = getLoggersMap(loggerContext);
+        final ConcurrentMap<String, Logger> loggers = Hierarchy.getLoggersMap(loggerContext);
         final Logger parentLogger = loggers.get(parent.getName());
         return parentLogger == null ? new Category(parent) : parentLogger;
     }
@@ -192,38 +142,23 @@ public class Category implements AppenderAttachable {
         return getInstance(Strings.EMPTY);
     }
 
-    static Logger getRoot(final LoggerContext context) {
-        return getInstance(context, Strings.EMPTY);
-    }
-
-    private static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
-        synchronized (CONTEXT_MAP) {
-            ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context);
-            if (map == null) {
-                map = new ConcurrentHashMap<>();
-                CONTEXT_MAP.put(context, map);
-            }
-            return map;
-        }
-    }
-
     /**
      * Returns all the currently defined categories in the default hierarchy as an
      * {@link java.util.Enumeration Enumeration}.
-     * 
+     *
      * <p>
      * The root category is <em>not</em> included in the returned
      * {@link Enumeration}.
      * </p>
-     * 
+     *
      * @return and Enumeration of the Categories.
-     * 
+     *
      * @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
      */
     @SuppressWarnings("rawtypes")
     @Deprecated
     public static Enumeration getCurrentCategories() {
-        return LogManager.getCurrentLoggers();
+        return LogManager.getCurrentLoggers(StackLocatorUtil.getCallerClassLoader(2));
     }
 
     /**
@@ -262,7 +197,7 @@ public class Category implements AppenderAttachable {
 
     /**
      * Gets the the {@link LoggerRepository} where this <code>Category</code> instance is attached.
-     * 
+     *
      * @deprecated Please use {@link #getLoggerRepository()} instead.
      * @since 1.1
      */
@@ -273,7 +208,7 @@ public class Category implements AppenderAttachable {
 
     /**
      * Gets the the {@link LoggerRepository} where this <code>Category</code> is attached.
-     * 
+     *
      * @since 1.2
      */
     public LoggerRepository getLoggerRepository() {
@@ -305,7 +240,7 @@ public class Category implements AppenderAttachable {
     }
 
     private void setLevel(final String levelStr) {
-        if (isCoreAvailable) {
+        if (LogManager.isLog4jCorePresent()) {
             CategoryUtil.setLevel(logger, org.apache.logging.log4j.Level.toLevel(levelStr));
         }
     }
@@ -396,10 +331,10 @@ public class Category implements AppenderAttachable {
      * @since 1.0
      */
     synchronized void closeNestedAppenders() {
-        Enumeration enumeration = this.getAllAppenders();
+        final Enumeration enumeration = this.getAllAppenders();
         if (enumeration != null) {
             while (enumeration.hasMoreElements()) {
-                Appender a = (Appender) enumeration.nextElement();
+                final Appender a = (Appender) enumeration.nextElement();
                 if (a instanceof AppenderAttachable) {
                     a.close();
                 }
@@ -466,11 +401,12 @@ public class Category implements AppenderAttachable {
         final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
         if (logger instanceof ExtendedLogger) {
             @SuppressWarnings("unchecked")
+            final
             Message msg = message instanceof Message ? (Message) message : message instanceof Map ?
                     new MapMessage((Map) message) : new ObjectMessage(message);
             ((ExtendedLogger) logger).logMessage(fqcn, lvl, null, msg, t);
         } else {
-            ObjectRenderer renderer = get(message.getClass());
+            final ObjectRenderer renderer = get(message.getClass());
             final Message msg = message instanceof Message ? (Message) message : renderer != null ?
                     new RenderedMessage(renderer, message) : new ObjectMessage(message);
             logger.log(lvl, msg, t);
@@ -479,24 +415,24 @@ public class Category implements AppenderAttachable {
 
     /**
      * Tests if the named category exists (in the default hierarchy).
-     * 
+     *
      * @param name The name to test.
      * @return Whether the name exists.
-     * 
+     *
      * @deprecated Please use {@link LogManager#exists(String)} instead.
      * @since 0.8.5
      */
     @Deprecated
-    public static boolean exists(final String name) {
-        return PrivateManager.getContext().hasLogger(name);
+    public static Logger exists(final String name) {
+        return LogManager.exists(name);
     }
 
     public boolean getAdditivity() {
-        return isCoreAvailable ? CategoryUtil.isAdditive(logger) : false;
+        return LogManager.isLog4jCorePresent() ? CategoryUtil.isAdditive(logger) : false;
     }
 
     public void setAdditivity(final boolean additivity) {
-        if (isCoreAvailable) {
+        if (LogManager.isLog4jCorePresent()) {
             CategoryUtil.setAdditivity(logger, additivity);
         }
     }
@@ -504,7 +440,7 @@ public class Category implements AppenderAttachable {
     /**
      * Only the Hiearchy class can set the hiearchy of a category. Default package access is MANDATORY here.
      */
-    final void setHierarchy(LoggerRepository repository) {
+    final void setHierarchy(final LoggerRepository repository) {
         this.repository = repository;
     }
 
@@ -517,10 +453,10 @@ public class Category implements AppenderAttachable {
             return bundle;
         }
         String name = logger.getName();
-        if (isCoreAvailable) {
-            LoggerContext ctx = CategoryUtil.getLoggerContext(logger);
+        if (LogManager.isLog4jCorePresent()) {
+            final LoggerContext ctx = CategoryUtil.getLoggerContext(logger);
             if (ctx != null) {
-                final ConcurrentMap<String, Logger> loggers = getLoggersMap(ctx);
+                final ConcurrentMap<String, Logger> loggers = Hierarchy.getLoggersMap(ctx);
                 while ((name = getSubName(name)) != null) {
                     final Logger subLogger = loggers.get(name);
                     if (subLogger != null) {
@@ -546,7 +482,7 @@ public class Category implements AppenderAttachable {
     /**
      * If <code>assertion</code> parameter is {@code false}, then logs
      * <code>msg</code> as an {@link #error(Object) error} statement.
-     * 
+     *
      * <p>
      * The <code>assert</code> method has been renamed to <code>assertLog</code>
      * because <code>assert</code> is a language reserved word in JDK 1.4.
@@ -554,7 +490,7 @@ public class Category implements AppenderAttachable {
      *
      * @param assertion The assertion.
      * @param msg       The message to print if <code>assertion</code> is false.
-     * 
+     *
      * @since 1.2
      */
     public void assertLog(final boolean assertion, final String msg) {
@@ -629,39 +565,11 @@ public class Category implements AppenderAttachable {
         }
     }
 
-    private static class PrivateAdapter extends AbstractLoggerAdapter<Logger> {
-
-        @Override
-        protected Logger newLogger(final String name, final org.apache.logging.log4j.spi.LoggerContext context) {
-            return new Logger(context, name);
-        }
-
-        @Override
-        protected org.apache.logging.log4j.spi.LoggerContext getContext() {
-            return PrivateManager.getContext();
-        }
-    }
-
-    /**
-     * Private LogManager.
-     */
-    private static class PrivateManager extends org.apache.logging.log4j.LogManager {
-        private static final String FQCN = Category.class.getName();
-
-        public static LoggerContext getContext() {
-            return getContext(FQCN, false);
-        }
-
-        public static org.apache.logging.log4j.Logger getLogger(final String name) {
-            return getLogger(FQCN, name);
-        }
-    }
-
     private boolean isEnabledFor(final org.apache.logging.log4j.Level level) {
         return logger.isEnabled(level);
     }
 
-    private <T> ObjectRenderer get(Class<T> clazz) {
+    private <T> ObjectRenderer get(final Class<T> clazz) {
         ObjectRenderer renderer = null;
         for (Class<? super T> c = clazz; c != null; c = c.getSuperclass()) {
             renderer = rendererMap.get(c);
@@ -676,13 +584,13 @@ public class Category implements AppenderAttachable {
         return null;
     }
 
-    ObjectRenderer searchInterfaces(Class<?> c) {
+    ObjectRenderer searchInterfaces(final Class<?> c) {
         ObjectRenderer renderer = rendererMap.get(c);
         if (renderer != null) {
             return renderer;
         }
-        Class<?>[] ia = c.getInterfaces();
-        for (Class<?> clazz : ia) {
+        final Class<?>[] ia = c.getInterfaces();
+        for (final Class<?> clazz : ia) {
             renderer = searchInterfaces(clazz);
             if (renderer != null) {
                 return renderer;
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Hierarchy.java b/log4j-1.2-api/src/main/java/org/apache/log4j/Hierarchy.java
index b497706..a7a059a 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/Hierarchy.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Hierarchy.java
@@ -24,16 +24,22 @@ package org.apache.log4j;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Vector;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.log4j.helpers.LogLog;
 import org.apache.log4j.or.ObjectRenderer;
 import org.apache.log4j.or.RendererMap;
 import org.apache.log4j.spi.HierarchyEventListener;
 import org.apache.log4j.spi.LoggerFactory;
-import org.apache.log4j.spi.LoggerRepository;
 import org.apache.log4j.spi.RendererSupport;
 import org.apache.log4j.spi.ThrowableRenderer;
 import org.apache.log4j.spi.ThrowableRendererSupport;
+import org.apache.logging.log4j.core.appender.AsyncAppender;
+import org.apache.logging.log4j.spi.AbstractLoggerAdapter;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.Strings;
 
 /**
  * This class is specialized in retrieving loggers by name and also maintaining the logger hierarchy.
@@ -52,18 +58,77 @@ import org.apache.log4j.spi.ThrowableRendererSupport;
  * provision node.
  * </p>
  */
-public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
+public class Hierarchy implements LoggerRepository2, RendererSupport, ThrowableRendererSupport {
+
+    private static class PrivateLoggerAdapter extends AbstractLoggerAdapter<Logger> {
+
+        @Override
+        protected org.apache.logging.log4j.spi.LoggerContext getContext() {
+            return PrivateLogManager.getContext();
+        }
+
+        @Override
+        protected Logger newLogger(final String name, final org.apache.logging.log4j.spi.LoggerContext context) {
+            return new Logger(context, name);
+        }
+    }
+
+    /**
+     * Private LogManager.
+     */
+    private static class PrivateLogManager extends org.apache.logging.log4j.LogManager {
+        private static final String FQCN = Hierarchy.class.getName();
+
+        public static LoggerContext getContext() {
+            return getContext(FQCN, false);
+        }
+
+        public static org.apache.logging.log4j.Logger getLogger(final String name) {
+            return getLogger(FQCN, name);
+        }
+    }
+
+    private static final PrivateLoggerAdapter LOGGER_ADAPTER = new PrivateLoggerAdapter();
+
+    private static final WeakHashMap<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP = new WeakHashMap<>();
+
+    static LoggerContext getContext() {
+        return PrivateLogManager.getContext();
+    }
+
+    static Logger getInstance(final LoggerContext context, final String name) {
+        return getInstance(context, name, LOGGER_ADAPTER);
+    }
+
+    static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
+        return getLoggersMap(context).computeIfAbsent(name, k -> factory.makeNewLoggerInstance(name));
+    }
+
+    static Logger getInstance(final LoggerContext context, final String name, final PrivateLoggerAdapter factory) {
+        return getLoggersMap(context).computeIfAbsent(name, k -> factory.newLogger(name, context));
+    }
+
+    static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
+        synchronized (CONTEXT_MAP) {
+            return CONTEXT_MAP.computeIfAbsent(context, k -> new ConcurrentHashMap<>());
+        }
+    }
+
+    static Logger getRootLogger(final LoggerContext context) {
+        return getInstance(context, org.apache.logging.log4j.LogManager.ROOT_LOGGER_NAME);
+    }
 
     private final LoggerFactory defaultFactory;
     private final Vector listeners;
-
     Hashtable ht;
     Logger root;
     RendererMap rendererMap;
     int thresholdInt;
     Level threshold;
     boolean emittedNoAppenderWarning;
+
     boolean emittedNoResourceBundleWarning;
+
     private ThrowableRenderer throwableRenderer;
 
     /**
@@ -132,12 +197,11 @@ public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRe
      */
     @Override
     public Logger exists(final String name) {
-        final Object o = ht.get(new CategoryKey(name));
-        if (o instanceof Logger) {
-            return (Logger) o;
-        } else {
+        final LoggerContext ctx = getContext();
+        if (!ctx.hasLogger(name)) {
             return null;
         }
+        return Logger.getLogger(name);
     }
 
     @Override
@@ -207,18 +271,13 @@ public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRe
      */
     @Override
     public Logger getLogger(final String name) {
-        return getLogger(name, defaultFactory);
+        return getInstance(getContext(), name);
     }
 
-    /**
-     * Gets an integer representation of the this repository's threshold.
-     *
-     * @since 1.2
-     */
-    // public
-    // int getThresholdInt() {
-    // return thresholdInt;
-    // }
+    @Override
+    public Logger getLogger(final String name, final ClassLoader classLoader) {
+        return getInstance(LogManager.getContext(classLoader), name);
+    }
 
     /**
      * Gets a new logger instance named as the first parameter using <code>factory</code>.
@@ -233,36 +292,12 @@ public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRe
      */
     @Override
     public Logger getLogger(final String name, final LoggerFactory factory) {
-        // System.out.println("getInstance("+name+") called.");
-        final CategoryKey key = new CategoryKey(name);
-        // Synchronize to prevent write conflicts. Read conflicts (in
-        // getChainedLevel method) are possible only if variable
-        // assignments are non-atomic.
-        Logger logger;
+        return getInstance(getContext(), name, factory);
+    }
 
-        synchronized (ht) {
-            final Object o = ht.get(key);
-            if (o == null) {
-                logger = factory.makeNewLoggerInstance(name);
-                logger.setHierarchy(this);
-                ht.put(key, logger);
-                updateParents(logger);
-                return logger;
-            } else if (o instanceof Logger) {
-                return (Logger) o;
-            } else if (o instanceof ProvisionNode) {
-                // System.out.println("("+name+") ht.get(this) returned ProvisionNode");
-                logger = factory.makeNewLoggerInstance(name);
-                logger.setHierarchy(this);
-                ht.put(key, logger);
-                updateChildren((ProvisionNode) o, logger);
-                updateParents(logger);
-                return logger;
-            } else {
-                // It should be impossible to arrive here
-                return null; // but let's keep the compiler happy.
-            }
-        }
+    @Override
+    public Logger getLogger(final String name, final LoggerFactory factory, final ClassLoader classLoader) {
+        return getInstance(LogManager.getContext(classLoader), name, factory);
     }
 
     /**
@@ -280,7 +315,7 @@ public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRe
      */
     @Override
     public Logger getRootLogger() {
-        return root;
+        return getInstance(getContext(), org.apache.logging.log4j.LogManager.ROOT_LOGGER_NAME);
     }
 
     /**
@@ -336,7 +371,7 @@ public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRe
     @Override
     public void resetConfiguration() {
 
-        getRootLogger().setLevel((Level) Level.DEBUG);
+        getRootLogger().setLevel(Level.DEBUG);
         root.setResourceBundle(null);
         setThreshold(Level.ALL);
 
@@ -393,7 +428,7 @@ public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRe
      */
     @Override
     public void setThreshold(final String levelStr) {
-        final Level l = (Level) Level.toLevel(levelStr, null);
+        final Level l = Level.toLevel(levelStr, null);
         if (l != null) {
             setThreshold(l);
         } else {
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 3f92cdf..46bff05 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
@@ -16,22 +16,22 @@
  */
 package org.apache.log4j;
 
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.stream.Collectors;
 
-import org.apache.log4j.helpers.NullEnumeration;
 import org.apache.log4j.legacy.core.ContextUtil;
-import org.apache.log4j.or.ObjectRenderer;
-import org.apache.log4j.or.RendererMap;
-import org.apache.log4j.spi.HierarchyEventListener;
+import org.apache.log4j.spi.DefaultRepositorySelector;
 import org.apache.log4j.spi.LoggerFactory;
 import org.apache.log4j.spi.LoggerRepository;
-import org.apache.log4j.spi.RendererSupport;
+import org.apache.log4j.spi.NOPLoggerRepository;
 import org.apache.log4j.spi.RepositorySelector;
+import org.apache.log4j.spi.RootLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
-import org.apache.logging.log4j.util.Strings;
+import org.apache.logging.log4j.util.StackLocatorUtil;
 
 /**
- *
+ * The main entry point to Log4j 1.
  */
 public final class LogManager {
 
@@ -61,188 +61,133 @@ public final class LogManager {
 
     static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
 
-    private static final LoggerRepository REPOSITORY = new Repository();
+    static private RepositorySelector repositorySelector;
 
-    private static final boolean isLog4jCore;
+    private static final boolean LOG4J_CORE_PRESENT;
 
     static {
-        boolean core = false;
+        LOG4J_CORE_PRESENT = checkLog4jCore();
+        //
+        // By default we use a DefaultRepositorySelector which always returns 'hierarchy'.
+        Hierarchy hierarchy = new Hierarchy(new RootLogger(Level.DEBUG));
+        repositorySelector = new DefaultRepositorySelector(hierarchy);
+    }
+
+    private static boolean checkLog4jCore() {
         try {
-            if (Class.forName("org.apache.logging.log4j.core.LoggerContext") != null) {
-                core = true;
-            }
+            return Class.forName("org.apache.logging.log4j.core.LoggerContext") != null;
         } catch (Exception ex) {
-            // Ignore the exception;
+            return false;
         }
-        isLog4jCore = core;
     }
 
-    public static Logger getRootLogger() {
-        return Category.getInstance(PrivateManager.getContext(), Strings.EMPTY);
+    public static Logger exists(final String name) {
+        return getLoggerRepository().exists(name);
     }
 
-    public static Logger getLogger(final String name) {
-        return Category.getInstance(PrivateManager.getContext(), name);
+    /**
+     * Gets a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     *        ClassLoader.
+     * @return a LoggerContext.
+     */
+    static LoggerContext getContext(final ClassLoader classLoader) {
+        return org.apache.logging.log4j.LogManager.getContext(classLoader, false);
+    }
+
+    /**
+     * Gets an enumeration of the current loggers.
+     * 
+     * @return an enumeration of the current loggers.
+     */
+    @SuppressWarnings("rawtypes")
+    public static Enumeration getCurrentLoggers() {
+        return getCurrentLoggers(StackLocatorUtil.getCallerClassLoader(2));
+    }
+
+    @SuppressWarnings("rawtypes")
+    static Enumeration getCurrentLoggers(final ClassLoader classLoader) {
+        // @formatter:off
+        return Collections.enumeration(
+            LogManager.getContext(classLoader).getLoggerRegistry()
+                .getLoggers().stream().map(e -> LogManager.getLogger(e.getName(), classLoader))
+                .collect(Collectors.toList()));
+        // @formatter:on
     }
 
     public static Logger getLogger(final Class<?> clazz) {
-        return Category.getInstance(PrivateManager.getContext(), clazz.getName());
+        // Depth 2 gets the call site of this method.
+        return getLoggerRepository2().getLogger(clazz.getName(), StackLocatorUtil.getCallerClassLoader(2));
+    }
+
+    public static Logger getLogger(final String name) {
+        // Depth 2 gets the call site of this method.
+        return getLoggerRepository2().getLogger(name, StackLocatorUtil.getCallerClassLoader(2));
+    }
+
+    static Logger getLogger(final String name, final ClassLoader classLoader) {
+        return getLoggerRepository2().getLogger(name, classLoader);
     }
 
     public static Logger getLogger(final String name, final LoggerFactory factory) {
-        return Category.getInstance(PrivateManager.getContext(), name);
+        // Depth 2 gets the call site of this method.
+        return getLoggerRepository2().getLogger(name, factory, StackLocatorUtil.getCallerClassLoader(2));
     }
 
-    public static Logger exists(final String name) {
-        final LoggerContext ctx = PrivateManager.getContext();
-        if (!ctx.hasLogger(name)) {
-            return null;
+    static Logger getLogger(final String name, final LoggerFactory factory, final ClassLoader classLoader) {
+        return getLoggerRepository2().getLogger(name, factory, classLoader);
+    }
+
+    public static LoggerRepository getLoggerRepository() {
+        if (repositorySelector == null) {
+            repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
         }
-        return Logger.getLogger(name);
+        return repositorySelector.getLoggerRepository();
     }
 
-    @SuppressWarnings("rawtypes")
-    public static Enumeration getCurrentLoggers() {
-        return getLoggerRepository().getCurrentLoggers();
+    static LoggerRepository2 getLoggerRepository2() {
+        // TODO Hack
+        return (LoggerRepository2) getLoggerRepository();
     }
 
-    static void reconfigure() {
-        if (isLog4jCore) {
-            final LoggerContext ctx = PrivateManager.getContext();
-            ContextUtil.reconfigure(ctx);
-        }
+    public static Logger getRootLogger() {
+        return getLoggerRepository2().getRootLogger();
     }
 
-    /**
-     * No-op implementation.
-     */
-    public static void shutdown() {
+    static boolean isLog4jCorePresent() {
+        return LOG4J_CORE_PRESENT;
+    }
+
+    static void reconfigure() {
+        if (isLog4jCorePresent()) {
+            ContextUtil.reconfigure(Hierarchy.getContext());
+        }
     }
 
     /**
      * No-op implementation.
      */
     public static void resetConfiguration() {
+        // noop
     }
 
     /**
      * No-op implementation.
+     * 
      * @param selector The RepositorySelector.
      * @param guard prevents calls at the incorrect time.
      * @throws IllegalArgumentException if a parameter is invalid.
      */
-    public static void setRepositorySelector(final RepositorySelector selector, final Object guard)
-        throws IllegalArgumentException {
-    }
-
-    public static LoggerRepository getLoggerRepository() {
-        return REPOSITORY;
+    public static void setRepositorySelector(final RepositorySelector selector, final Object guard) throws IllegalArgumentException {
+        // noop
     }
 
     /**
-     * The Repository.
+     * No-op implementation.
      */
-    private static class Repository implements LoggerRepository, RendererSupport {
-
-        private final RendererMap rendererMap = new RendererMap();
-
-        @Override
-        public RendererMap getRendererMap() {
-            return rendererMap;
-        }
-
-        @Override
-        public void addHierarchyEventListener(final HierarchyEventListener listener) {
-
-        }
-
-        @Override
-        public boolean isDisabled(final int level) {
-            return false;
-        }
-
-        @Override
-        public void setThreshold(final Level level) {
-
-        }
-
-        @Override
-        public void setThreshold(final String val) {
-
-        }
-
-        @Override
-        public void emitNoAppenderWarning(final Category cat) {
-
-        }
-
-        @Override
-        public Level getThreshold() {
-            return Level.OFF;
-        }
-
-        @Override
-        public Logger getLogger(final String name) {
-            return Category.getInstance(PrivateManager.getContext(), name);
-        }
-
-        @Override
-        public Logger getLogger(final String name, final LoggerFactory factory) {
-            return Category.getInstance(PrivateManager.getContext(), name);
-        }
-
-        @Override
-        public Logger getRootLogger() {
-            return Category.getRoot(PrivateManager.getContext());
-        }
-
-        @Override
-        public Logger exists(final String name) {
-            return LogManager.exists(name);
-        }
-
-        @Override
-        public void shutdown() {
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        public Enumeration getCurrentLoggers() {
-            return NullEnumeration.getInstance();
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        public Enumeration getCurrentCategories() {
-            return NullEnumeration.getInstance();
-        }
-
-        @Override
-        public void fireAddAppenderEvent(final Category logger, final Appender appender) {
-        }
-
-        @Override
-        public void resetConfiguration() {
-        }
-
-        @Override
-        public void setRenderer(Class renderedClass, ObjectRenderer renderer) {
-            rendererMap.put(renderedClass, renderer);
-        }
+    public static void shutdown() {
+        // noop
     }
 
-    /**
-     * Internal LogManager.
-     */
-    private static class PrivateManager extends org.apache.logging.log4j.LogManager {
-        private static final String FQCN = LogManager.class.getName();
-
-        public static LoggerContext getContext() {
-            return getContext(FQCN, false);
-        }
-
-        public static org.apache.logging.log4j.Logger getLogger(final String name) {
-            return getLogger(FQCN, 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 674a0c1..19c523e 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,6 +18,7 @@ package org.apache.log4j;
 
 import org.apache.log4j.spi.LoggerFactory;
 import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.StackLocatorUtil;
 
 /**
  *
@@ -29,28 +30,31 @@ public class Logger extends Category {
      */
     private static final String FQCN = Logger.class.getName();
  
-    protected Logger(final String name) {
-        super(name);
-    }
-
-    Logger(final LoggerContext context, final String name) {
-        super(context, name);
+    public static Logger getLogger(final Class<?> clazz) {
+        // Depth 2 gets the call site of this method.
+        return LogManager.getLogger(clazz.getName(), StackLocatorUtil.getCallerClassLoader(2));
     }
 
     public static Logger getLogger(final String name) {
-        return LogManager.getLogger(name);
+        // Depth 2 gets the call site of this method.
+        return LogManager.getLogger(name, StackLocatorUtil.getCallerClassLoader(2)); 
     }
 
-    public static Logger getLogger(final Class<?> clazz) {
-        return LogManager.getLogger(clazz);
+    public static Logger getLogger(final String name, final LoggerFactory factory) {
+        // Depth 2 gets the call site of this method.
+        return LogManager.getLogger(name, factory, StackLocatorUtil.getCallerClassLoader(2));
     }
 
     public static Logger getRootLogger() {
         return LogManager.getRootLogger();
     }
 
-    public static Logger getLogger(final String name, final LoggerFactory factory) {
-        return LogManager.getLogger(name, factory);
+    Logger(final LoggerContext context, final String name) {
+        super(context, name);
+    }
+
+    protected Logger(final String name) {
+        super(name);
     }
 
     public boolean isTraceEnabled() {
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/LoggerRepository2.java b/log4j-1.2-api/src/main/java/org/apache/log4j/LoggerRepository2.java
new file mode 100644
index 0000000..30c88ee
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/LoggerRepository2.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+import org.apache.log4j.spi.LoggerFactory;
+import org.apache.log4j.spi.LoggerRepository;
+
+/**
+ * A LoggerRepository that accounts for the caller's class loader.
+ */
+interface LoggerRepository2 extends LoggerRepository {
+
+    Logger getLogger(String name, ClassLoader classLoader);
+
+    Logger getLogger(String name, LoggerFactory factory, ClassLoader classLoader);
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/RootLogger.java b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/RootLogger.java
index afd4619..79db491 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/spi/RootLogger.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/spi/RootLogger.java
@@ -34,7 +34,8 @@ public final class RootLogger extends Logger {
      * The root logger names itself as "root". However, the root logger cannot be retrieved by name.
      */
     public RootLogger(Level level) {
-        // Note that the Log4j 2 root logger name is "".
+        // The Log4j 1 root logger name is "root".
+        // The Log4j 2 root logger name is "".
         super("root");
         setLevel(level);
     }
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 a618136..a6e9510 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
@@ -18,8 +18,8 @@
 package org.apache.log4j;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.lang.reflect.Method;
@@ -74,7 +74,7 @@ public class CategoryTest {
 
     @Test
     public void testExist() throws Exception {
-        assertFalse(Category.exists("Does not exist for sure"));
+        assertNull(Category.exists("Does not exist for sure"));
     }
 
     /**
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/LogManagerTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/LogManagerTest.java
index d8fcd16..b3d56b2 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/LogManagerTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/LogManagerTest.java
@@ -24,21 +24,25 @@ import java.util.Enumeration;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
+/**
+ * Tests {@link LogManager}.
+ */
 public class LogManagerTest {
 
     private static final String SIMPLE_NAME = LogManagerTest.class.getSimpleName();
 
+    List<String> getCurrentLoggerNames() {
+        return Collections.list((Enumeration<Logger>) LogManager.getCurrentLoggers()).stream().map(Logger::getName).collect(Collectors.toList());
+    }
+
     @Test
-    @Ignore("WIP")
     public void testGetCurrentLoggers() {
         Logger.getLogger(SIMPLE_NAME);
         Logger.getLogger(SIMPLE_NAME + ".foo");
         Logger.getLogger(SIMPLE_NAME + ".foo.bar");
-        final List<String> names = Collections.list((Enumeration<Logger>) LogManager.getCurrentLoggers()).stream().map(Logger::getName)
-            .collect(Collectors.toList());
+        final List<String> names = getCurrentLoggerNames();
         assertTrue(names.contains(SIMPLE_NAME));
         assertTrue(names.contains(SIMPLE_NAME + ".foo"));
         assertTrue(names.contains(SIMPLE_NAME + ".foo.bar"));