This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/master by this push: new c4866d0 Refactor 1.2 bridge internals to use a single private log manager and adapter. new 1f74096 Merge branch 'master' of https://gitbox.apache.org/repos/asf/logging-log4j2.git c4866d0 is described below commit c4866d0d9027dbaf9b53a7c0ae9717fe67b7d2a2 Author: Gary Gregory <garydgreg...@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. - Cherry pick and resolve conflicts from release-2.x. - 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 --- .../java/org/apache/log4j/BasicConfigurator.java | 14 +- .../src/main/java/org/apache/log4j/Category.java | 218 ++++++------------- .../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 | 13 +- .../test/java/org/apache/log4j/LogManagerTest.java | 12 +- 9 files changed, 315 insertions(+), 372 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 3dc4ff7..8fba001 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 final 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,35 +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}. - @return and Enumeration of the Categories. - - @deprecated Please use {@link LogManager#getCurrentLoggers()} instead. + * 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)); } /** @@ -259,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 */ @@ -270,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() { @@ -302,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)); } } @@ -393,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(); } @@ -463,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); @@ -476,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); + return LogManager.isLog4jCorePresent() ? CategoryUtil.isAdditive(logger) : false; } public void setAdditivity(final boolean additivity) { - if (isCoreAvailable) { + if (LogManager.isLog4jCorePresent()) { CategoryUtil.setAdditivity(logger, additivity); } } @@ -501,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; } @@ -514,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) { @@ -541,18 +480,18 @@ 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. - - @param assertion The assertion. - @param msg The message to print if <code>assertion</code> is - false. - - @since 1.2 + * 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. + * </p> + * + * @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) { if (!assertion) { @@ -626,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 ObjectRenderer get(Class clazz) { + private <T> ObjectRenderer get(final Class<T> clazz) { ObjectRenderer renderer = null; for(Class c = clazz; c != null; c = c.getSuperclass()) { renderer = rendererMap.get(c); @@ -673,17 +584,16 @@ 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; - } else { - Class[] ia = c.getInterfaces(); - for (Class clazz : ia) { - renderer = searchInterfaces(clazz); - if (renderer != null) { - return renderer; - } + } + final Class<?>[] ia = c.getInterfaces(); + for (final Class<?> clazz : ia) { + renderer = searchInterfaces(clazz); + if (renderer != null) { + return renderer; } } return null; 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 2607556..86b8a3f 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 @@ -17,6 +17,17 @@ package org.apache.log4j; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.LoggerContext; @@ -74,7 +85,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"));