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 2015/07/27 19:03:50 UTC

logging-log4j2 git commit: [LOG4J2-1084] Misleading StatusLogger WARN event in LogManager with java.util.Map.

Repository: logging-log4j2
Updated Branches:
  refs/heads/master 753b79df2 -> a60368c01


[LOG4J2-1084] Misleading StatusLogger WARN event in LogManager with
java.util.Map.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/a60368c0
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/a60368c0
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/a60368c0

Branch: refs/heads/master
Commit: a60368c015b343b37c3537cb67d594b547a61cd5
Parents: 753b79d
Author: ggregory <gg...@apache.org>
Authored: Mon Jul 27 10:02:56 2015 -0700
Committer: ggregory <gg...@apache.org>
Committed: Mon Jul 27 10:02:56 2015 -0700

----------------------------------------------------------------------
 .../org/apache/logging/log4j/LogManager.java    | 1100 +++++++++---------
 src/changes/changes.xml                         |    5 +-
 2 files changed, 555 insertions(+), 550 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a60368c0/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
index d190543..d5ad911 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
@@ -1,549 +1,551 @@
-/*
- * 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.logging.log4j;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.StringFormatterMessageFactory;
-import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
-import org.apache.logging.log4j.spi.LoggerContext;
-import org.apache.logging.log4j.spi.LoggerContextFactory;
-import org.apache.logging.log4j.spi.Provider;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.LoaderUtil;
-import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.ProviderUtil;
-import org.apache.logging.log4j.util.ReflectionUtil;
-import org.apache.logging.log4j.util.Strings;
-
-/**
- * The anchor point for the logging system. The most common usage of this class is to obtain a named
- * {@link Logger}. The method {@link #getLogger()} is provided as the most convenient way to obtain a named Logger
- * based on the calling class name. This class also provides method for obtaining named Loggers that use
- * {@link String#format(String, Object...)} style messages instead of the default type of parameterized messages.
- * These are obtained through the {@link #getFormatterLogger(Class)} family of methods. Other service provider methods
- * are given through the {@link #getContext()} and {@link #getFactory()} family of methods; these methods are not
- * normally useful for typical usage of Log4j.
- */
-public class LogManager {
-
-    private static volatile LoggerContextFactory factory;
-
-    /**
-     * Log4j property to set to the fully qualified class name of a custom implementation of
-     * {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
-     */
-    public static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory";
-
-    private static final Logger LOGGER = StatusLogger.getLogger();
-
-    /**
-     * The name of the root Logger.
-     */
-    public static final String ROOT_LOGGER_NAME = Strings.EMPTY;
-
-    // for convenience
-    private static final String FQCN = LogManager.class.getName();
-
-    /**
-     * Scans the classpath to find all logging implementation. Currently, only one will
-     * be used but this could be extended to allow multiple implementations to be used.
-     */
-    static {
-        // Shortcut binding to force a specific logging implementation.
-        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
-        final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
-        if (factoryClassName != null) {
-            try {
-                final Class<?> clazz = LoaderUtil.loadClass(factoryClassName);
-                if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
-                    factory = clazz.asSubclass(LoggerContextFactory.class).newInstance();
-                }
-            } catch (final ClassNotFoundException cnfe) {
-                LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName);
-            } catch (final Exception ex) {
-                LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex);
-            }
-        }
-
-        if (factory == null) {
-            final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>();
-            // note that the following initial call to ProviderUtil may block until a Provider has been installed when
-            // running in an OSGi environment
-            if (ProviderUtil.hasProviders()) {
-                for (final Provider provider : ProviderUtil.getProviders()) {
-                    final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory();
-                    if (factoryClass != null) {
-                        try {
-                            factories.put(provider.getPriority(), factoryClass.newInstance());
-                        } catch (final Exception e) {
-                            LOGGER.error("Unable to create class {} specified in {}", factoryClass.getName(),
-                                provider.getUrl().toString(), e);
-                        }
-                    }
-                }
-
-                if (factories.isEmpty()) {
-                    LOGGER.error("Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
-                    factory = new SimpleLoggerContextFactory();
-                } else {
-                    final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
-                    for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) {
-                        sb.append("Factory: ").append(entry.getValue().getClass().getName());
-                        sb.append(", Weighting: ").append(entry.getKey()).append('\n');
-                    }
-                    factory = factories.get(factories.lastKey());
-                    sb.append("Using factory: ").append(factory.getClass().getName());
-                    LOGGER.warn(sb.toString());
-
-                }
-            } else {
-                LOGGER.error("Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
-                factory = new SimpleLoggerContextFactory();
-            }
-        }
-    }
-
-    /**
-     * Detects if a Logger with the specified name exists. This is a convenience method for porting from version 1.
-     *
-     * @param name
-     *            The Logger name to search for.
-     * @return true if the Logger exists, false otherwise.
-     * @see LoggerContext#hasLogger(String)
-     */
-    public static boolean exists(final String name) {
-        return getContext().hasLogger(name);
-    }
-
-    /**
-     * Returns the current LoggerContext.
-     * <p>
-     * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger
-     * for the calling class.
-     * </p>
-     * @return  The current LoggerContext.
-     */
-    public static LoggerContext getContext() {
-        return factory.getContext(FQCN, null, null, true);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final boolean currentContext) {
-        // TODO: would it be a terrible idea to try and find the caller ClassLoader here?
-        return factory.getContext(FQCN, null, null, currentContext, null, null);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) {
-        return factory.getContext(FQCN, loader, null, currentContext);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
-                                           final Object externalContext) {
-        return factory.getContext(FQCN, loader, externalContext, currentContext);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param configLocation The URI for the configuration to use.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
-                                           final URI configLocation) {
-        return factory.getContext(FQCN, loader, null, currentContext, configLocation, null);
-    }
-
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
-     * @param configLocation The URI for the configuration to use.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
-                                           final Object externalContext, final URI configLocation) {
-        return factory.getContext(FQCN, loader, externalContext, currentContext, configLocation, null);
-    }
-
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
-     * @param configLocation The URI for the configuration to use.
-     * @param name The LoggerContext name.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
-                                           final Object externalContext, final URI configLocation,
-                                           final String name) {
-        return factory.getContext(FQCN, loader, externalContext, currentContext, configLocation, name);
-    }
-
-    /**
-     * Returns a LoggerContext
-     * @param fqcn The fully qualified class name of the Class that this method is a member of.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    protected static LoggerContext getContext(final String fqcn, final boolean currentContext) {
-        return factory.getContext(fqcn, null, null, currentContext);
-    }
-
-    /**
-     * Returns a LoggerContext
-     * @param fqcn The fully qualified class name of the Class that this method is a member of.
-     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
-     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    protected static LoggerContext getContext(final String fqcn, final ClassLoader loader,
-                                              final boolean currentContext) {
-        return factory.getContext(fqcn, loader, null, currentContext);
-    }
-
-    /**
-     * Returns the current LoggerContextFactory.
-     * @return The LoggerContextFactory.
-     */
-    public static LoggerContextFactory getFactory() {
-        return factory;
-    }
-
-    /**
-     * Sets the current LoggerContextFactory to use. Normally, the appropriate LoggerContextFactory is created at
-     * startup, but in certain environments, a LoggerContextFactory implementation may not be available at this point.
-     * Thus, an alternative LoggerContextFactory can be set at runtime.
-     *
-     * <p>
-     * Note that any Logger or LoggerContext objects already created will still be valid, but they will no longer be
-     * accessible through LogManager. Thus, <strong>it is a bad idea to use this method without a good reason</strong>!
-     * Generally, this method should be used only during startup before any code starts caching Logger objects.
-     * </p>
-     *
-     * @param factory the LoggerContextFactory to use.
-     */
-    // FIXME: should we allow only one update of the factory?
-    public static void setFactory(final LoggerContextFactory factory) {
-        LogManager.factory = factory;
-    }
-
-    /**
-     * Returns a formatter Logger using the fully qualified name of the calling Class as the Logger name.
-     * <p>
-     * This logger lets you use a {@link java.util.Formatter} string in the message to format parameters.
-     * </p>
-     * @return The Logger for the calling class.
-     * @throws UnsupportedOperationException if the calling class cannot be determined.
-     * @since 2.4
-     */
-    public static Logger getFormatterLogger() {
-        return getFormatterLogger(ReflectionUtil.getCallerClass(2));
-    }
-
-
-    /**
-     * Returns a formatter Logger using the fully qualified name of the Class as the Logger name.
-     * <p>
-     * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
-     * </p>
-     * <p>
-     * Short-hand for {@code getLogger(clazz, StringFormatterMessageFactory.INSTANCE)}
-     * </p>
-     *
-     * @param clazz
-     *            The Class whose name should be used as the Logger name.
-     * @return The Logger, created with a {@link StringFormatterMessageFactory}
-     * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
-     * @see Logger#fatal(Marker, String, Object...)
-     * @see Logger#fatal(String, Object...)
-     * @see Logger#error(Marker, String, Object...)
-     * @see Logger#error(String, Object...)
-     * @see Logger#warn(Marker, String, Object...)
-     * @see Logger#warn(String, Object...)
-     * @see Logger#info(Marker, String, Object...)
-     * @see Logger#info(String, Object...)
-     * @see Logger#debug(Marker, String, Object...)
-     * @see Logger#debug(String, Object...)
-     * @see Logger#trace(Marker, String, Object...)
-     * @see Logger#trace(String, Object...)
-     * @see StringFormatterMessageFactory
-     */
-    public static Logger getFormatterLogger(final Class<?> clazz) {
-        return getLogger(clazz != null ? clazz : ReflectionUtil.getCallerClass(2),
-            StringFormatterMessageFactory.INSTANCE);
-    }
-
-    /**
-     * Returns a formatter Logger using the fully qualified name of the value's Class as the Logger name.
-     * <p>
-     * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
-     * </p>
-     * <p>
-     * Short-hand for {@code getLogger(value, StringFormatterMessageFactory.INSTANCE)}
-     * </p>
-     *
-     * @param value
-     *            The value's whose class name should be used as the Logger name.
-     * @return The Logger, created with a {@link StringFormatterMessageFactory}
-     * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be determined.
-     * @see Logger#fatal(Marker, String, Object...)
-     * @see Logger#fatal(String, Object...)
-     * @see Logger#error(Marker, String, Object...)
-     * @see Logger#error(String, Object...)
-     * @see Logger#warn(Marker, String, Object...)
-     * @see Logger#warn(String, Object...)
-     * @see Logger#info(Marker, String, Object...)
-     * @see Logger#info(String, Object...)
-     * @see Logger#debug(Marker, String, Object...)
-     * @see Logger#debug(String, Object...)
-     * @see Logger#trace(Marker, String, Object...)
-     * @see Logger#trace(String, Object...)
-     * @see StringFormatterMessageFactory
-     */
-    public static Logger getFormatterLogger(final Object value) {
-        return getLogger(value != null ? value.getClass() : ReflectionUtil.getCallerClass(2),
-            StringFormatterMessageFactory.INSTANCE);
-    }
-
-    /**
-     * Returns a formatter Logger with the specified name.
-     * <p>
-     * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
-     * </p>
-     * <p>
-     * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)}
-     * </p>
-     *
-     * @param name The logger name. If null it will default to the name of the calling class.
-     * @return The Logger, created with a {@link StringFormatterMessageFactory}
-     * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
-     * @see Logger#fatal(Marker, String, Object...)
-     * @see Logger#fatal(String, Object...)
-     * @see Logger#error(Marker, String, Object...)
-     * @see Logger#error(String, Object...)
-     * @see Logger#warn(Marker, String, Object...)
-     * @see Logger#warn(String, Object...)
-     * @see Logger#info(Marker, String, Object...)
-     * @see Logger#info(String, Object...)
-     * @see Logger#debug(Marker, String, Object...)
-     * @see Logger#debug(String, Object...)
-     * @see Logger#trace(Marker, String, Object...)
-     * @see Logger#trace(String, Object...)
-     * @see StringFormatterMessageFactory
-     */
-    public static Logger getFormatterLogger(final String name) {
-        return name == null ? getFormatterLogger(ReflectionUtil.getCallerClass(2)) : getLogger(name,
-            StringFormatterMessageFactory.INSTANCE);
-    }
-
-    /**
-     * Returns a Logger with the name of the calling class.
-     * @return The Logger for the calling class.
-     * @throws UnsupportedOperationException if the calling class cannot be determined.
-     */
-    public static Logger getLogger() {
-        return getLogger(ReflectionUtil.getCallerClass(2));
-    }
-
-    /**
-     * Returns a Logger using the fully qualified name of the Class as the Logger name.
-     * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling
-     *              class.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Class<?> clazz) {
-        if (clazz == null) {
-            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
-            if (candidate == null) {
-                throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
-            }
-            return getLogger(candidate);
-        }
-        return getContext(clazz.getClassLoader(), false).getLogger(clazz.getName());
-    }
-
-    /**
-     * Returns a Logger using the fully qualified name of the Class as the Logger name.
-     * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling
-     *              class.
-     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if mismatched.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) {
-        if (clazz == null) {
-            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
-            if (candidate == null) {
-                throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
-            }
-            return getLogger(candidate, messageFactory);
-        }
-        return getContext(clazz.getClassLoader(), false).getLogger(clazz.getName(), messageFactory);
-    }
-
-    /**
-     * Returns a Logger with the name of the calling class.
-     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if mismatched.
-     * @return The Logger for the calling class.
-     * @throws UnsupportedOperationException if the calling class cannot be determined.
-     */
-    public static Logger getLogger(final MessageFactory messageFactory) {
-        return getLogger(ReflectionUtil.getCallerClass(2), messageFactory);
-    }
-
-    /**
-     * Returns a Logger using the fully qualified class name of the value as the Logger name.
-     * @param value The value whose class name should be used as the Logger name. If null the name of the calling
-     *              class will be used as the logger name.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Object value) {
-        return getLogger(value != null ? value.getClass() : ReflectionUtil.getCallerClass(2));
-    }
-
-    /**
-     * Returns a Logger using the fully qualified class name of the value as the Logger name.
-     * @param value The value whose class name should be used as the Logger name. If null the name of the calling
-     *              class will be used as the logger name.
-     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if mismatched.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Object value, final MessageFactory messageFactory) {
-        return getLogger(value != null ? value.getClass() : ReflectionUtil.getCallerClass(2), messageFactory);
-    }
-
-    /**
-     * Returns a Logger with the specified name.
-     *
-     * @param name The logger name. If null the name of the calling class will be used.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final String name) {
-        return name != null ? getContext(false).getLogger(name) : getLogger(ReflectionUtil.getCallerClass(2));
-    }
-
-    /**
-     * Returns a Logger with the specified name.
-     *
-     * @param name The logger name. If null the name of the calling class will be used.
-     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if mismatched.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final String name, final MessageFactory messageFactory) {
-        return name != null ? getContext(false).getLogger(name, messageFactory) : getLogger(
-            ReflectionUtil.getCallerClass(2), messageFactory);
-    }
-
-    /**
-     * Returns a Logger with the specified name.
-     *
-     * @param fqcn The fully qualified class name of the class that this method is a member of.
-     * @param name The logger name.
-     * @return The Logger.
-     */
-    protected static Logger getLogger(final String fqcn, final String name) {
-        return factory.getContext(fqcn, null, null, false).getLogger(name);
-    }
-
-    /**
-     * Returns the root logger.
-     *
-     * @return the root logger, named {@link #ROOT_LOGGER_NAME}.
-     */
-    public static Logger getRootLogger() {
-        return getLogger(ROOT_LOGGER_NAME);
-    }
-
-    /**
-     * Prevents instantiation
-     */
-    protected LogManager() {
-    }
-
-}
+/*
+ * 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.logging.log4j;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.message.StringFormatterMessageFactory;
+import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.spi.Provider;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.ProviderUtil;
+import org.apache.logging.log4j.util.ReflectionUtil;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * The anchor point for the logging system. The most common usage of this class is to obtain a named
+ * {@link Logger}. The method {@link #getLogger()} is provided as the most convenient way to obtain a named Logger
+ * based on the calling class name. This class also provides method for obtaining named Loggers that use
+ * {@link String#format(String, Object...)} style messages instead of the default type of parameterized messages.
+ * These are obtained through the {@link #getFormatterLogger(Class)} family of methods. Other service provider methods
+ * are given through the {@link #getContext()} and {@link #getFactory()} family of methods; these methods are not
+ * normally useful for typical usage of Log4j.
+ */
+public class LogManager {
+
+    private static volatile LoggerContextFactory factory;
+
+    /**
+     * Log4j property to set to the fully qualified class name of a custom implementation of
+     * {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
+     */
+    public static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory";
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * The name of the root Logger.
+     */
+    public static final String ROOT_LOGGER_NAME = Strings.EMPTY;
+
+    // for convenience
+    private static final String FQCN = LogManager.class.getName();
+
+    /**
+     * Scans the classpath to find all logging implementation. Currently, only one will
+     * be used but this could be extended to allow multiple implementations to be used.
+     */
+    static {
+        // Shortcut binding to force a specific logging implementation.
+        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+        final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
+        if (factoryClassName != null) {
+            try {
+                final Class<?> clazz = LoaderUtil.loadClass(factoryClassName);
+                if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
+                    factory = clazz.asSubclass(LoggerContextFactory.class).newInstance();
+                }
+            } catch (final ClassNotFoundException cnfe) {
+                LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex);
+            }
+        }
+
+        if (factory == null) {
+            final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>();
+            // note that the following initial call to ProviderUtil may block until a Provider has been installed when
+            // running in an OSGi environment
+            if (ProviderUtil.hasProviders()) {
+                for (final Provider provider : ProviderUtil.getProviders()) {
+                    final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory();
+                    if (factoryClass != null) {
+                        try {
+                            factories.put(provider.getPriority(), factoryClass.newInstance());
+                        } catch (final Exception e) {
+                            LOGGER.error("Unable to create class {} specified in {}", factoryClass.getName(),
+                                provider.getUrl().toString(), e);
+                        }
+                    }
+                }
+
+                if (factories.isEmpty()) {
+                    LOGGER.error("Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
+                    factory = new SimpleLoggerContextFactory();
+                } else if (factories.size() == 1) {
+					factory = factories.get(factories.lastKey());
+                } else {
+                    final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
+                    for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) {
+                        sb.append("Factory: ").append(entry.getValue().getClass().getName());
+                        sb.append(", Weighting: ").append(entry.getKey()).append('\n');
+                    }
+                    factory = factories.get(factories.lastKey());
+                    sb.append("Using factory: ").append(factory.getClass().getName());
+                    LOGGER.warn(sb.toString());
+
+                }
+            } else {
+                LOGGER.error("Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
+                factory = new SimpleLoggerContextFactory();
+            }
+        }
+    }
+
+    /**
+     * Detects if a Logger with the specified name exists. This is a convenience method for porting from version 1.
+     *
+     * @param name
+     *            The Logger name to search for.
+     * @return true if the Logger exists, false otherwise.
+     * @see LoggerContext#hasLogger(String)
+     */
+    public static boolean exists(final String name) {
+        return getContext().hasLogger(name);
+    }
+
+    /**
+     * Returns the current LoggerContext.
+     * <p>
+     * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger
+     * for the calling class.
+     * </p>
+     * @return  The current LoggerContext.
+     */
+    public static LoggerContext getContext() {
+        return factory.getContext(FQCN, null, null, true);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final boolean currentContext) {
+        // TODO: would it be a terrible idea to try and find the caller ClassLoader here?
+        return factory.getContext(FQCN, null, null, currentContext, null, null);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) {
+        return factory.getContext(FQCN, loader, null, currentContext);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
+                                           final Object externalContext) {
+        return factory.getContext(FQCN, loader, externalContext, currentContext);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param configLocation The URI for the configuration to use.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
+                                           final URI configLocation) {
+        return factory.getContext(FQCN, loader, null, currentContext, configLocation, null);
+    }
+
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
+     * @param configLocation The URI for the configuration to use.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
+                                           final Object externalContext, final URI configLocation) {
+        return factory.getContext(FQCN, loader, externalContext, currentContext, configLocation, null);
+    }
+
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
+     * @param configLocation The URI for the configuration to use.
+     * @param name The LoggerContext name.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
+                                           final Object externalContext, final URI configLocation,
+                                           final String name) {
+        return factory.getContext(FQCN, loader, externalContext, currentContext, configLocation, name);
+    }
+
+    /**
+     * Returns a LoggerContext
+     * @param fqcn The fully qualified class name of the Class that this method is a member of.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    protected static LoggerContext getContext(final String fqcn, final boolean currentContext) {
+        return factory.getContext(fqcn, null, null, currentContext);
+    }
+
+    /**
+     * Returns a LoggerContext
+     * @param fqcn The fully qualified class name of the Class that this method is a member of.
+     * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
+     * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    protected static LoggerContext getContext(final String fqcn, final ClassLoader loader,
+                                              final boolean currentContext) {
+        return factory.getContext(fqcn, loader, null, currentContext);
+    }
+
+    /**
+     * Returns the current LoggerContextFactory.
+     * @return The LoggerContextFactory.
+     */
+    public static LoggerContextFactory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Sets the current LoggerContextFactory to use. Normally, the appropriate LoggerContextFactory is created at
+     * startup, but in certain environments, a LoggerContextFactory implementation may not be available at this point.
+     * Thus, an alternative LoggerContextFactory can be set at runtime.
+     *
+     * <p>
+     * Note that any Logger or LoggerContext objects already created will still be valid, but they will no longer be
+     * accessible through LogManager. Thus, <strong>it is a bad idea to use this method without a good reason</strong>!
+     * Generally, this method should be used only during startup before any code starts caching Logger objects.
+     * </p>
+     *
+     * @param factory the LoggerContextFactory to use.
+     */
+    // FIXME: should we allow only one update of the factory?
+    public static void setFactory(final LoggerContextFactory factory) {
+        LogManager.factory = factory;
+    }
+
+    /**
+     * Returns a formatter Logger using the fully qualified name of the calling Class as the Logger name.
+     * <p>
+     * This logger lets you use a {@link java.util.Formatter} string in the message to format parameters.
+     * </p>
+     * @return The Logger for the calling class.
+     * @throws UnsupportedOperationException if the calling class cannot be determined.
+     * @since 2.4
+     */
+    public static Logger getFormatterLogger() {
+        return getFormatterLogger(ReflectionUtil.getCallerClass(2));
+    }
+
+
+    /**
+     * Returns a formatter Logger using the fully qualified name of the Class as the Logger name.
+     * <p>
+     * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
+     * </p>
+     * <p>
+     * Short-hand for {@code getLogger(clazz, StringFormatterMessageFactory.INSTANCE)}
+     * </p>
+     *
+     * @param clazz
+     *            The Class whose name should be used as the Logger name.
+     * @return The Logger, created with a {@link StringFormatterMessageFactory}
+     * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
+     * @see Logger#fatal(Marker, String, Object...)
+     * @see Logger#fatal(String, Object...)
+     * @see Logger#error(Marker, String, Object...)
+     * @see Logger#error(String, Object...)
+     * @see Logger#warn(Marker, String, Object...)
+     * @see Logger#warn(String, Object...)
+     * @see Logger#info(Marker, String, Object...)
+     * @see Logger#info(String, Object...)
+     * @see Logger#debug(Marker, String, Object...)
+     * @see Logger#debug(String, Object...)
+     * @see Logger#trace(Marker, String, Object...)
+     * @see Logger#trace(String, Object...)
+     * @see StringFormatterMessageFactory
+     */
+    public static Logger getFormatterLogger(final Class<?> clazz) {
+        return getLogger(clazz != null ? clazz : ReflectionUtil.getCallerClass(2),
+            StringFormatterMessageFactory.INSTANCE);
+    }
+
+    /**
+     * Returns a formatter Logger using the fully qualified name of the value's Class as the Logger name.
+     * <p>
+     * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
+     * </p>
+     * <p>
+     * Short-hand for {@code getLogger(value, StringFormatterMessageFactory.INSTANCE)}
+     * </p>
+     *
+     * @param value
+     *            The value's whose class name should be used as the Logger name.
+     * @return The Logger, created with a {@link StringFormatterMessageFactory}
+     * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be determined.
+     * @see Logger#fatal(Marker, String, Object...)
+     * @see Logger#fatal(String, Object...)
+     * @see Logger#error(Marker, String, Object...)
+     * @see Logger#error(String, Object...)
+     * @see Logger#warn(Marker, String, Object...)
+     * @see Logger#warn(String, Object...)
+     * @see Logger#info(Marker, String, Object...)
+     * @see Logger#info(String, Object...)
+     * @see Logger#debug(Marker, String, Object...)
+     * @see Logger#debug(String, Object...)
+     * @see Logger#trace(Marker, String, Object...)
+     * @see Logger#trace(String, Object...)
+     * @see StringFormatterMessageFactory
+     */
+    public static Logger getFormatterLogger(final Object value) {
+        return getLogger(value != null ? value.getClass() : ReflectionUtil.getCallerClass(2),
+            StringFormatterMessageFactory.INSTANCE);
+    }
+
+    /**
+     * Returns a formatter Logger with the specified name.
+     * <p>
+     * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
+     * </p>
+     * <p>
+     * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)}
+     * </p>
+     *
+     * @param name The logger name. If null it will default to the name of the calling class.
+     * @return The Logger, created with a {@link StringFormatterMessageFactory}
+     * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
+     * @see Logger#fatal(Marker, String, Object...)
+     * @see Logger#fatal(String, Object...)
+     * @see Logger#error(Marker, String, Object...)
+     * @see Logger#error(String, Object...)
+     * @see Logger#warn(Marker, String, Object...)
+     * @see Logger#warn(String, Object...)
+     * @see Logger#info(Marker, String, Object...)
+     * @see Logger#info(String, Object...)
+     * @see Logger#debug(Marker, String, Object...)
+     * @see Logger#debug(String, Object...)
+     * @see Logger#trace(Marker, String, Object...)
+     * @see Logger#trace(String, Object...)
+     * @see StringFormatterMessageFactory
+     */
+    public static Logger getFormatterLogger(final String name) {
+        return name == null ? getFormatterLogger(ReflectionUtil.getCallerClass(2)) : getLogger(name,
+            StringFormatterMessageFactory.INSTANCE);
+    }
+
+    /**
+     * Returns a Logger with the name of the calling class.
+     * @return The Logger for the calling class.
+     * @throws UnsupportedOperationException if the calling class cannot be determined.
+     */
+    public static Logger getLogger() {
+        return getLogger(ReflectionUtil.getCallerClass(2));
+    }
+
+    /**
+     * Returns a Logger using the fully qualified name of the Class as the Logger name.
+     * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling
+     *              class.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Class<?> clazz) {
+        if (clazz == null) {
+            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
+            if (candidate == null) {
+                throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
+            }
+            return getLogger(candidate);
+        }
+        return getContext(clazz.getClassLoader(), false).getLogger(clazz.getName());
+    }
+
+    /**
+     * Returns a Logger using the fully qualified name of the Class as the Logger name.
+     * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling
+     *              class.
+     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if mismatched.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) {
+        if (clazz == null) {
+            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
+            if (candidate == null) {
+                throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
+            }
+            return getLogger(candidate, messageFactory);
+        }
+        return getContext(clazz.getClassLoader(), false).getLogger(clazz.getName(), messageFactory);
+    }
+
+    /**
+     * Returns a Logger with the name of the calling class.
+     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if mismatched.
+     * @return The Logger for the calling class.
+     * @throws UnsupportedOperationException if the calling class cannot be determined.
+     */
+    public static Logger getLogger(final MessageFactory messageFactory) {
+        return getLogger(ReflectionUtil.getCallerClass(2), messageFactory);
+    }
+
+    /**
+     * Returns a Logger using the fully qualified class name of the value as the Logger name.
+     * @param value The value whose class name should be used as the Logger name. If null the name of the calling
+     *              class will be used as the logger name.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Object value) {
+        return getLogger(value != null ? value.getClass() : ReflectionUtil.getCallerClass(2));
+    }
+
+    /**
+     * Returns a Logger using the fully qualified class name of the value as the Logger name.
+     * @param value The value whose class name should be used as the Logger name. If null the name of the calling
+     *              class will be used as the logger name.
+     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if mismatched.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Object value, final MessageFactory messageFactory) {
+        return getLogger(value != null ? value.getClass() : ReflectionUtil.getCallerClass(2), messageFactory);
+    }
+
+    /**
+     * Returns a Logger with the specified name.
+     *
+     * @param name The logger name. If null the name of the calling class will be used.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final String name) {
+        return name != null ? getContext(false).getLogger(name) : getLogger(ReflectionUtil.getCallerClass(2));
+    }
+
+    /**
+     * Returns a Logger with the specified name.
+     *
+     * @param name The logger name. If null the name of the calling class will be used.
+     * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if mismatched.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final String name, final MessageFactory messageFactory) {
+        return name != null ? getContext(false).getLogger(name, messageFactory) : getLogger(
+            ReflectionUtil.getCallerClass(2), messageFactory);
+    }
+
+    /**
+     * Returns a Logger with the specified name.
+     *
+     * @param fqcn The fully qualified class name of the class that this method is a member of.
+     * @param name The logger name.
+     * @return The Logger.
+     */
+    protected static Logger getLogger(final String fqcn, final String name) {
+        return factory.getContext(fqcn, null, null, false).getLogger(name);
+    }
+
+    /**
+     * Returns the root logger.
+     *
+     * @return the root logger, named {@link #ROOT_LOGGER_NAME}.
+     */
+    public static Logger getRootLogger() {
+        return getLogger(ROOT_LOGGER_NAME);
+    }
+
+    /**
+     * Prevents instantiation
+     */
+    protected LogManager() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a60368c0/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6114e94..35bfbd1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -50,7 +50,10 @@
       </action>     
       <action issue="LOG4J2-1066" dev="ggregory" type="add" due-to="Charles Allen">
         Expose Log4jContextFactory's ShutdownCallbackRegistry.
-      </action>     
+      </action>          
+      <action issue="LOG4J2-1084" dev="ggregory" type="fix" due-to="Philipp Schneider">
+        Misleading StatusLogger WARN event in LogManager with java.util.Map.
+      </action>
       <action issue="LOG4J2-1051" dev="ggregory" type="fix" due-to="Lukasz Lenart">
         NoClassDefFoundError when starting app on Google App Engine.
       </action>


Fwd: logging-log4j2 git commit: [LOG4J2-1084] Misleading StatusLogger WARN event in LogManager with java.util.Map.

Posted by Gary Gregory <ga...@gmail.com>.
Crud, I'm not sure why the change is coming through like this as opposed to
the few lines I changed.

Gary

---------- Forwarded message ----------
From: <gg...@apache.org>
Date: Mon, Jul 27, 2015 at 10:03 AM
Subject: logging-log4j2 git commit: [LOG4J2-1084] Misleading StatusLogger
WARN event in LogManager with java.util.Map.
To: commits@logging.apache.org


Repository: logging-log4j2
Updated Branches:
  refs/heads/master 753b79df2 -> a60368c01


[LOG4J2-1084] Misleading StatusLogger WARN event in LogManager with
java.util.Map.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit:
http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/a60368c0
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/a60368c0
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/a60368c0

Branch: refs/heads/master
Commit: a60368c015b343b37c3537cb67d594b547a61cd5
Parents: 753b79d
Author: ggregory <gg...@apache.org>
Authored: Mon Jul 27 10:02:56 2015 -0700
Committer: ggregory <gg...@apache.org>
Committed: Mon Jul 27 10:02:56 2015 -0700

----------------------------------------------------------------------
 .../org/apache/logging/log4j/LogManager.java    | 1100 +++++++++---------
 src/changes/changes.xml                         |    5 +-
 2 files changed, 555 insertions(+), 550 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a60368c0/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
----------------------------------------------------------------------
diff --git
a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
index d190543..d5ad911 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/LogManager.java
@@ -1,549 +1,551 @@
-/*
- * 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.logging.log4j;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.StringFormatterMessageFactory;
-import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
-import org.apache.logging.log4j.spi.LoggerContext;
-import org.apache.logging.log4j.spi.LoggerContextFactory;
-import org.apache.logging.log4j.spi.Provider;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.LoaderUtil;
-import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.ProviderUtil;
-import org.apache.logging.log4j.util.ReflectionUtil;
-import org.apache.logging.log4j.util.Strings;
-
-/**
- * The anchor point for the logging system. The most common usage of this
class is to obtain a named
- * {@link Logger}. The method {@link #getLogger()} is provided as the most
convenient way to obtain a named Logger
- * based on the calling class name. This class also provides method for
obtaining named Loggers that use
- * {@link String#format(String, Object...)} style messages instead of the
default type of parameterized messages.
- * These are obtained through the {@link #getFormatterLogger(Class)}
family of methods. Other service provider methods
- * are given through the {@link #getContext()} and {@link #getFactory()}
family of methods; these methods are not
- * normally useful for typical usage of Log4j.
- */
-public class LogManager {
-
-    private static volatile LoggerContextFactory factory;
-
-    /**
-     * Log4j property to set to the fully qualified class name of a custom
implementation of
-     * {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
-     */
-    public static final String FACTORY_PROPERTY_NAME =
"log4j2.loggerContextFactory";
-
-    private static final Logger LOGGER = StatusLogger.getLogger();
-
-    /**
-     * The name of the root Logger.
-     */
-    public static final String ROOT_LOGGER_NAME = Strings.EMPTY;
-
-    // for convenience
-    private static final String FQCN = LogManager.class.getName();
-
-    /**
-     * Scans the classpath to find all logging implementation. Currently,
only one will
-     * be used but this could be extended to allow multiple
implementations to be used.
-     */
-    static {
-        // Shortcut binding to force a specific logging implementation.
-        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
-        final String factoryClassName =
managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
-        if (factoryClassName != null) {
-            try {
-                final Class<?> clazz =
LoaderUtil.loadClass(factoryClassName);
-                if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
-                    factory =
clazz.asSubclass(LoggerContextFactory.class).newInstance();
-                }
-            } catch (final ClassNotFoundException cnfe) {
-                LOGGER.error("Unable to locate configured
LoggerContextFactory {}", factoryClassName);
-            } catch (final Exception ex) {
-                LOGGER.error("Unable to create configured
LoggerContextFactory {}", factoryClassName, ex);
-            }
-        }
-
-        if (factory == null) {
-            final SortedMap<Integer, LoggerContextFactory> factories = new
TreeMap<>();
-            // note that the following initial call to ProviderUtil may
block until a Provider has been installed when
-            // running in an OSGi environment
-            if (ProviderUtil.hasProviders()) {
-                for (final Provider provider :
ProviderUtil.getProviders()) {
-                    final Class<? extends LoggerContextFactory>
factoryClass = provider.loadLoggerContextFactory();
-                    if (factoryClass != null) {
-                        try {
-                            factories.put(provider.getPriority(),
factoryClass.newInstance());
-                        } catch (final Exception e) {
-                            LOGGER.error("Unable to create class {}
specified in {}", factoryClass.getName(),
-                                provider.getUrl().toString(), e);
-                        }
-                    }
-                }
-
-                if (factories.isEmpty()) {
-                    LOGGER.error("Log4j2 could not find a logging
implementation. Please add log4j-core to the classpath. Using SimpleLogger
to log to the console...");
-                    factory = new SimpleLoggerContextFactory();
-                } else {
-                    final StringBuilder sb = new StringBuilder("Multiple
logging implementations found: \n");
-                    for (final Map.Entry<Integer, LoggerContextFactory>
entry : factories.entrySet()) {
-                        sb.append("Factory:
").append(entry.getValue().getClass().getName());
-                        sb.append(", Weighting:
").append(entry.getKey()).append('\n');
-                    }
-                    factory = factories.get(factories.lastKey());
-                    sb.append("Using factory:
").append(factory.getClass().getName());
-                    LOGGER.warn(sb.toString());
-
-                }
-            } else {
-                LOGGER.error("Log4j2 could not find a logging
implementation. Please add log4j-core to the classpath. Using SimpleLogger
to log to the console...");
-                factory = new SimpleLoggerContextFactory();
-            }
-        }
-    }
-
-    /**
-     * Detects if a Logger with the specified name exists. This is a
convenience method for porting from version 1.
-     *
-     * @param name
-     *            The Logger name to search for.
-     * @return true if the Logger exists, false otherwise.
-     * @see LoggerContext#hasLogger(String)
-     */
-    public static boolean exists(final String name) {
-        return getContext().hasLogger(name);
-    }
-
-    /**
-     * Returns the current LoggerContext.
-     * <p>
-     * WARNING - The LoggerContext returned by this method may not be the
LoggerContext used to create a Logger
-     * for the calling class.
-     * </p>
-     * @return  The current LoggerContext.
-     */
-    public static LoggerContext getContext() {
-        return factory.getContext(FQCN, null, null, true);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final boolean currentContext) {
-        // TODO: would it be a terrible idea to try and find the caller
ClassLoader here?
-        return factory.getContext(FQCN, null, null, currentContext, null,
null);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext) {
-        return factory.getContext(FQCN, loader, null, currentContext);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param externalContext An external context (such as a
ServletContext) to be associated with the LoggerContext.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
-                                           final Object externalContext) {
-        return factory.getContext(FQCN, loader, externalContext,
currentContext);
-    }
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param configLocation The URI for the configuration to use.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
-                                           final URI configLocation) {
-        return factory.getContext(FQCN, loader, null, currentContext,
configLocation, null);
-    }
-
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param externalContext An external context (such as a
ServletContext) to be associated with the LoggerContext.
-     * @param configLocation The URI for the configuration to use.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
-                                           final Object externalContext,
final URI configLocation) {
-        return factory.getContext(FQCN, loader, externalContext,
currentContext, configLocation, null);
-    }
-
-
-    /**
-     * Returns a LoggerContext.
-     *
-     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @param externalContext An external context (such as a
ServletContext) to be associated with the LoggerContext.
-     * @param configLocation The URI for the configuration to use.
-     * @param name The LoggerContext name.
-     * @return a LoggerContext.
-     */
-    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
-                                           final Object externalContext,
final URI configLocation,
-                                           final String name) {
-        return factory.getContext(FQCN, loader, externalContext,
currentContext, configLocation, name);
-    }
-
-    /**
-     * Returns a LoggerContext
-     * @param fqcn The fully qualified class name of the Class that this
method is a member of.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    protected static LoggerContext getContext(final String fqcn, final
boolean currentContext) {
-        return factory.getContext(fqcn, null, null, currentContext);
-    }
-
-    /**
-     * Returns a LoggerContext
-     * @param fqcn The fully qualified class name of the Class that this
method is a member of.
-     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
-     * ClassLoader.
-     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
-     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
-     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
-     * returned. If true then only a single LoggerContext will be returned.
-     * @return a LoggerContext.
-     */
-    protected static LoggerContext getContext(final String fqcn, final
ClassLoader loader,
-                                              final boolean
currentContext) {
-        return factory.getContext(fqcn, loader, null, currentContext);
-    }
-
-    /**
-     * Returns the current LoggerContextFactory.
-     * @return The LoggerContextFactory.
-     */
-    public static LoggerContextFactory getFactory() {
-        return factory;
-    }
-
-    /**
-     * Sets the current LoggerContextFactory to use. Normally, the
appropriate LoggerContextFactory is created at
-     * startup, but in certain environments, a LoggerContextFactory
implementation may not be available at this point.
-     * Thus, an alternative LoggerContextFactory can be set at runtime.
-     *
-     * <p>
-     * Note that any Logger or LoggerContext objects already created will
still be valid, but they will no longer be
-     * accessible through LogManager. Thus, <strong>it is a bad idea to
use this method without a good reason</strong>!
-     * Generally, this method should be used only during startup before
any code starts caching Logger objects.
-     * </p>
-     *
-     * @param factory the LoggerContextFactory to use.
-     */
-    // FIXME: should we allow only one update of the factory?
-    public static void setFactory(final LoggerContextFactory factory) {
-        LogManager.factory = factory;
-    }
-
-    /**
-     * Returns a formatter Logger using the fully qualified name of the
calling Class as the Logger name.
-     * <p>
-     * This logger lets you use a {@link java.util.Formatter} string in
the message to format parameters.
-     * </p>
-     * @return The Logger for the calling class.
-     * @throws UnsupportedOperationException if the calling class cannot
be determined.
-     * @since 2.4
-     */
-    public static Logger getFormatterLogger() {
-        return getFormatterLogger(ReflectionUtil.getCallerClass(2));
-    }
-
-
-    /**
-     * Returns a formatter Logger using the fully qualified name of the
Class as the Logger name.
-     * <p>
-     * This logger let you use a {@link java.util.Formatter} string in the
message to format parameters.
-     * </p>
-     * <p>
-     * Short-hand for {@code getLogger(clazz,
StringFormatterMessageFactory.INSTANCE)}
-     * </p>
-     *
-     * @param clazz
-     *            The Class whose name should be used as the Logger name.
-     * @return The Logger, created with a {@link
StringFormatterMessageFactory}
-     * @throws UnsupportedOperationException if {@code clazz} is {@code
null} and the calling class cannot be determined.
-     * @see Logger#fatal(Marker, String, Object...)
-     * @see Logger#fatal(String, Object...)
-     * @see Logger#error(Marker, String, Object...)
-     * @see Logger#error(String, Object...)
-     * @see Logger#warn(Marker, String, Object...)
-     * @see Logger#warn(String, Object...)
-     * @see Logger#info(Marker, String, Object...)
-     * @see Logger#info(String, Object...)
-     * @see Logger#debug(Marker, String, Object...)
-     * @see Logger#debug(String, Object...)
-     * @see Logger#trace(Marker, String, Object...)
-     * @see Logger#trace(String, Object...)
-     * @see StringFormatterMessageFactory
-     */
-    public static Logger getFormatterLogger(final Class<?> clazz) {
-        return getLogger(clazz != null ? clazz :
ReflectionUtil.getCallerClass(2),
-            StringFormatterMessageFactory.INSTANCE);
-    }
-
-    /**
-     * Returns a formatter Logger using the fully qualified name of the
value's Class as the Logger name.
-     * <p>
-     * This logger let you use a {@link java.util.Formatter} string in the
message to format parameters.
-     * </p>
-     * <p>
-     * Short-hand for {@code getLogger(value,
StringFormatterMessageFactory.INSTANCE)}
-     * </p>
-     *
-     * @param value
-     *            The value's whose class name should be used as the
Logger name.
-     * @return The Logger, created with a {@link
StringFormatterMessageFactory}
-     * @throws UnsupportedOperationException if {@code value} is {@code
null} and the calling class cannot be determined.
-     * @see Logger#fatal(Marker, String, Object...)
-     * @see Logger#fatal(String, Object...)
-     * @see Logger#error(Marker, String, Object...)
-     * @see Logger#error(String, Object...)
-     * @see Logger#warn(Marker, String, Object...)
-     * @see Logger#warn(String, Object...)
-     * @see Logger#info(Marker, String, Object...)
-     * @see Logger#info(String, Object...)
-     * @see Logger#debug(Marker, String, Object...)
-     * @see Logger#debug(String, Object...)
-     * @see Logger#trace(Marker, String, Object...)
-     * @see Logger#trace(String, Object...)
-     * @see StringFormatterMessageFactory
-     */
-    public static Logger getFormatterLogger(final Object value) {
-        return getLogger(value != null ? value.getClass() :
ReflectionUtil.getCallerClass(2),
-            StringFormatterMessageFactory.INSTANCE);
-    }
-
-    /**
-     * Returns a formatter Logger with the specified name.
-     * <p>
-     * This logger let you use a {@link java.util.Formatter} string in the
message to format parameters.
-     * </p>
-     * <p>
-     * Short-hand for {@code getLogger(name,
StringFormatterMessageFactory.INSTANCE)}
-     * </p>
-     *
-     * @param name The logger name. If null it will default to the name of
the calling class.
-     * @return The Logger, created with a {@link
StringFormatterMessageFactory}
-     * @throws UnsupportedOperationException if {@code name} is {@code
null} and the calling class cannot be determined.
-     * @see Logger#fatal(Marker, String, Object...)
-     * @see Logger#fatal(String, Object...)
-     * @see Logger#error(Marker, String, Object...)
-     * @see Logger#error(String, Object...)
-     * @see Logger#warn(Marker, String, Object...)
-     * @see Logger#warn(String, Object...)
-     * @see Logger#info(Marker, String, Object...)
-     * @see Logger#info(String, Object...)
-     * @see Logger#debug(Marker, String, Object...)
-     * @see Logger#debug(String, Object...)
-     * @see Logger#trace(Marker, String, Object...)
-     * @see Logger#trace(String, Object...)
-     * @see StringFormatterMessageFactory
-     */
-    public static Logger getFormatterLogger(final String name) {
-        return name == null ?
getFormatterLogger(ReflectionUtil.getCallerClass(2)) : getLogger(name,
-            StringFormatterMessageFactory.INSTANCE);
-    }
-
-    /**
-     * Returns a Logger with the name of the calling class.
-     * @return The Logger for the calling class.
-     * @throws UnsupportedOperationException if the calling class cannot
be determined.
-     */
-    public static Logger getLogger() {
-        return getLogger(ReflectionUtil.getCallerClass(2));
-    }
-
-    /**
-     * Returns a Logger using the fully qualified name of the Class as the
Logger name.
-     * @param clazz The Class whose name should be used as the Logger
name. If null it will default to the calling
-     *              class.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code clazz} is {@code
null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Class<?> clazz) {
-        if (clazz == null) {
-            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
-            if (candidate == null) {
-                throw new UnsupportedOperationException("No class
provided, and an appropriate one cannot be found.");
-            }
-            return getLogger(candidate);
-        }
-        return getContext(clazz.getClassLoader(),
false).getLogger(clazz.getName());
-    }
-
-    /**
-     * Returns a Logger using the fully qualified name of the Class as the
Logger name.
-     * @param clazz The Class whose name should be used as the Logger
name. If null it will default to the calling
-     *              class.
-     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if
mismatched.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code clazz} is {@code
null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Class<?> clazz, final
MessageFactory messageFactory) {
-        if (clazz == null) {
-            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
-            if (candidate == null) {
-                throw new UnsupportedOperationException("No class
provided, and an appropriate one cannot be found.");
-            }
-            return getLogger(candidate, messageFactory);
-        }
-        return getContext(clazz.getClassLoader(),
false).getLogger(clazz.getName(), messageFactory);
-    }
-
-    /**
-     * Returns a Logger with the name of the calling class.
-     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if
mismatched.
-     * @return The Logger for the calling class.
-     * @throws UnsupportedOperationException if the calling class cannot
be determined.
-     */
-    public static Logger getLogger(final MessageFactory messageFactory) {
-        return getLogger(ReflectionUtil.getCallerClass(2), messageFactory);
-    }
-
-    /**
-     * Returns a Logger using the fully qualified class name of the value
as the Logger name.
-     * @param value The value whose class name should be used as the
Logger name. If null the name of the calling
-     *              class will be used as the logger name.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code value} is {@code
null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Object value) {
-        return getLogger(value != null ? value.getClass() :
ReflectionUtil.getCallerClass(2));
-    }
-
-    /**
-     * Returns a Logger using the fully qualified class name of the value
as the Logger name.
-     * @param value The value whose class name should be used as the
Logger name. If null the name of the calling
-     *              class will be used as the logger name.
-     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if
mismatched.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code value} is {@code
null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final Object value, final
MessageFactory messageFactory) {
-        return getLogger(value != null ? value.getClass() :
ReflectionUtil.getCallerClass(2), messageFactory);
-    }
-
-    /**
-     * Returns a Logger with the specified name.
-     *
-     * @param name The logger name. If null the name of the calling class
will be used.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code name} is {@code
null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final String name) {
-        return name != null ? getContext(false).getLogger(name) :
getLogger(ReflectionUtil.getCallerClass(2));
-    }
-
-    /**
-     * Returns a Logger with the specified name.
-     *
-     * @param name The logger name. If null the name of the calling class
will be used.
-     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
-     *                       the logger but will log a warning if
mismatched.
-     * @return The Logger.
-     * @throws UnsupportedOperationException if {@code name} is {@code
null} and the calling class cannot be determined.
-     */
-    public static Logger getLogger(final String name, final MessageFactory
messageFactory) {
-        return name != null ? getContext(false).getLogger(name,
messageFactory) : getLogger(
-            ReflectionUtil.getCallerClass(2), messageFactory);
-    }
-
-    /**
-     * Returns a Logger with the specified name.
-     *
-     * @param fqcn The fully qualified class name of the class that this
method is a member of.
-     * @param name The logger name.
-     * @return The Logger.
-     */
-    protected static Logger getLogger(final String fqcn, final String
name) {
-        return factory.getContext(fqcn, null, null, false).getLogger(name);
-    }
-
-    /**
-     * Returns the root logger.
-     *
-     * @return the root logger, named {@link #ROOT_LOGGER_NAME}.
-     */
-    public static Logger getRootLogger() {
-        return getLogger(ROOT_LOGGER_NAME);
-    }
-
-    /**
-     * Prevents instantiation
-     */
-    protected LogManager() {
-    }
-
-}
+/*
+ * 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.logging.log4j;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.message.StringFormatterMessageFactory;
+import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.spi.Provider;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.ProviderUtil;
+import org.apache.logging.log4j.util.ReflectionUtil;
+import org.apache.logging.log4j.util.Strings;
+
+/**
+ * The anchor point for the logging system. The most common usage of this
class is to obtain a named
+ * {@link Logger}. The method {@link #getLogger()} is provided as the most
convenient way to obtain a named Logger
+ * based on the calling class name. This class also provides method for
obtaining named Loggers that use
+ * {@link String#format(String, Object...)} style messages instead of the
default type of parameterized messages.
+ * These are obtained through the {@link #getFormatterLogger(Class)}
family of methods. Other service provider methods
+ * are given through the {@link #getContext()} and {@link #getFactory()}
family of methods; these methods are not
+ * normally useful for typical usage of Log4j.
+ */
+public class LogManager {
+
+    private static volatile LoggerContextFactory factory;
+
+    /**
+     * Log4j property to set to the fully qualified class name of a custom
implementation of
+     * {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
+     */
+    public static final String FACTORY_PROPERTY_NAME =
"log4j2.loggerContextFactory";
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * The name of the root Logger.
+     */
+    public static final String ROOT_LOGGER_NAME = Strings.EMPTY;
+
+    // for convenience
+    private static final String FQCN = LogManager.class.getName();
+
+    /**
+     * Scans the classpath to find all logging implementation. Currently,
only one will
+     * be used but this could be extended to allow multiple
implementations to be used.
+     */
+    static {
+        // Shortcut binding to force a specific logging implementation.
+        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+        final String factoryClassName =
managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
+        if (factoryClassName != null) {
+            try {
+                final Class<?> clazz =
LoaderUtil.loadClass(factoryClassName);
+                if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
+                    factory =
clazz.asSubclass(LoggerContextFactory.class).newInstance();
+                }
+            } catch (final ClassNotFoundException cnfe) {
+                LOGGER.error("Unable to locate configured
LoggerContextFactory {}", factoryClassName);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create configured
LoggerContextFactory {}", factoryClassName, ex);
+            }
+        }
+
+        if (factory == null) {
+            final SortedMap<Integer, LoggerContextFactory> factories = new
TreeMap<>();
+            // note that the following initial call to ProviderUtil may
block until a Provider has been installed when
+            // running in an OSGi environment
+            if (ProviderUtil.hasProviders()) {
+                for (final Provider provider :
ProviderUtil.getProviders()) {
+                    final Class<? extends LoggerContextFactory>
factoryClass = provider.loadLoggerContextFactory();
+                    if (factoryClass != null) {
+                        try {
+                            factories.put(provider.getPriority(),
factoryClass.newInstance());
+                        } catch (final Exception e) {
+                            LOGGER.error("Unable to create class {}
specified in {}", factoryClass.getName(),
+                                provider.getUrl().toString(), e);
+                        }
+                    }
+                }
+
+                if (factories.isEmpty()) {
+                    LOGGER.error("Log4j2 could not find a logging
implementation. Please add log4j-core to the classpath. Using SimpleLogger
to log to the console...");
+                    factory = new SimpleLoggerContextFactory();
+                } else if (factories.size() == 1) {
+                                       factory =
factories.get(factories.lastKey());
+                } else {
+                    final StringBuilder sb = new StringBuilder("Multiple
logging implementations found: \n");
+                    for (final Map.Entry<Integer, LoggerContextFactory>
entry : factories.entrySet()) {
+                        sb.append("Factory:
").append(entry.getValue().getClass().getName());
+                        sb.append(", Weighting:
").append(entry.getKey()).append('\n');
+                    }
+                    factory = factories.get(factories.lastKey());
+                    sb.append("Using factory:
").append(factory.getClass().getName());
+                    LOGGER.warn(sb.toString());
+
+                }
+            } else {
+                LOGGER.error("Log4j2 could not find a logging
implementation. Please add log4j-core to the classpath. Using SimpleLogger
to log to the console...");
+                factory = new SimpleLoggerContextFactory();
+            }
+        }
+    }
+
+    /**
+     * Detects if a Logger with the specified name exists. This is a
convenience method for porting from version 1.
+     *
+     * @param name
+     *            The Logger name to search for.
+     * @return true if the Logger exists, false otherwise.
+     * @see LoggerContext#hasLogger(String)
+     */
+    public static boolean exists(final String name) {
+        return getContext().hasLogger(name);
+    }
+
+    /**
+     * Returns the current LoggerContext.
+     * <p>
+     * WARNING - The LoggerContext returned by this method may not be the
LoggerContext used to create a Logger
+     * for the calling class.
+     * </p>
+     * @return  The current LoggerContext.
+     */
+    public static LoggerContext getContext() {
+        return factory.getContext(FQCN, null, null, true);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final boolean currentContext) {
+        // TODO: would it be a terrible idea to try and find the caller
ClassLoader here?
+        return factory.getContext(FQCN, null, null, currentContext, null,
null);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext) {
+        return factory.getContext(FQCN, loader, null, currentContext);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param externalContext An external context (such as a
ServletContext) to be associated with the LoggerContext.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
+                                           final Object externalContext) {
+        return factory.getContext(FQCN, loader, externalContext,
currentContext);
+    }
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param configLocation The URI for the configuration to use.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
+                                           final URI configLocation) {
+        return factory.getContext(FQCN, loader, null, currentContext,
configLocation, null);
+    }
+
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param externalContext An external context (such as a
ServletContext) to be associated with the LoggerContext.
+     * @param configLocation The URI for the configuration to use.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
+                                           final Object externalContext,
final URI configLocation) {
+        return factory.getContext(FQCN, loader, externalContext,
currentContext, configLocation, null);
+    }
+
+
+    /**
+     * Returns a LoggerContext.
+     *
+     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @param externalContext An external context (such as a
ServletContext) to be associated with the LoggerContext.
+     * @param configLocation The URI for the configuration to use.
+     * @param name The LoggerContext name.
+     * @return a LoggerContext.
+     */
+    public static LoggerContext getContext(final ClassLoader loader, final
boolean currentContext,
+                                           final Object externalContext,
final URI configLocation,
+                                           final String name) {
+        return factory.getContext(FQCN, loader, externalContext,
currentContext, configLocation, name);
+    }
+
+    /**
+     * Returns a LoggerContext
+     * @param fqcn The fully qualified class name of the Class that this
method is a member of.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    protected static LoggerContext getContext(final String fqcn, final
boolean currentContext) {
+        return factory.getContext(fqcn, null, null, currentContext);
+    }
+
+    /**
+     * Returns a LoggerContext
+     * @param fqcn The fully qualified class name of the Class that this
method is a member of.
+     * @param loader The ClassLoader for the context. If null the context
will attempt to determine the appropriate
+     * ClassLoader.
+     * @param currentContext if false the LoggerContext appropriate for
the caller of this method is returned. For
+     * example, in a web application if the caller is a class in
WEB-INF/lib then one LoggerContext may be
+     * returned and if the caller is a class in the container's classpath
then a different LoggerContext may be
+     * returned. If true then only a single LoggerContext will be returned.
+     * @return a LoggerContext.
+     */
+    protected static LoggerContext getContext(final String fqcn, final
ClassLoader loader,
+                                              final boolean
currentContext) {
+        return factory.getContext(fqcn, loader, null, currentContext);
+    }
+
+    /**
+     * Returns the current LoggerContextFactory.
+     * @return The LoggerContextFactory.
+     */
+    public static LoggerContextFactory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Sets the current LoggerContextFactory to use. Normally, the
appropriate LoggerContextFactory is created at
+     * startup, but in certain environments, a LoggerContextFactory
implementation may not be available at this point.
+     * Thus, an alternative LoggerContextFactory can be set at runtime.
+     *
+     * <p>
+     * Note that any Logger or LoggerContext objects already created will
still be valid, but they will no longer be
+     * accessible through LogManager. Thus, <strong>it is a bad idea to
use this method without a good reason</strong>!
+     * Generally, this method should be used only during startup before
any code starts caching Logger objects.
+     * </p>
+     *
+     * @param factory the LoggerContextFactory to use.
+     */
+    // FIXME: should we allow only one update of the factory?
+    public static void setFactory(final LoggerContextFactory factory) {
+        LogManager.factory = factory;
+    }
+
+    /**
+     * Returns a formatter Logger using the fully qualified name of the
calling Class as the Logger name.
+     * <p>
+     * This logger lets you use a {@link java.util.Formatter} string in
the message to format parameters.
+     * </p>
+     * @return The Logger for the calling class.
+     * @throws UnsupportedOperationException if the calling class cannot
be determined.
+     * @since 2.4
+     */
+    public static Logger getFormatterLogger() {
+        return getFormatterLogger(ReflectionUtil.getCallerClass(2));
+    }
+
+
+    /**
+     * Returns a formatter Logger using the fully qualified name of the
Class as the Logger name.
+     * <p>
+     * This logger let you use a {@link java.util.Formatter} string in the
message to format parameters.
+     * </p>
+     * <p>
+     * Short-hand for {@code getLogger(clazz,
StringFormatterMessageFactory.INSTANCE)}
+     * </p>
+     *
+     * @param clazz
+     *            The Class whose name should be used as the Logger name.
+     * @return The Logger, created with a {@link
StringFormatterMessageFactory}
+     * @throws UnsupportedOperationException if {@code clazz} is {@code
null} and the calling class cannot be determined.
+     * @see Logger#fatal(Marker, String, Object...)
+     * @see Logger#fatal(String, Object...)
+     * @see Logger#error(Marker, String, Object...)
+     * @see Logger#error(String, Object...)
+     * @see Logger#warn(Marker, String, Object...)
+     * @see Logger#warn(String, Object...)
+     * @see Logger#info(Marker, String, Object...)
+     * @see Logger#info(String, Object...)
+     * @see Logger#debug(Marker, String, Object...)
+     * @see Logger#debug(String, Object...)
+     * @see Logger#trace(Marker, String, Object...)
+     * @see Logger#trace(String, Object...)
+     * @see StringFormatterMessageFactory
+     */
+    public static Logger getFormatterLogger(final Class<?> clazz) {
+        return getLogger(clazz != null ? clazz :
ReflectionUtil.getCallerClass(2),
+            StringFormatterMessageFactory.INSTANCE);
+    }
+
+    /**
+     * Returns a formatter Logger using the fully qualified name of the
value's Class as the Logger name.
+     * <p>
+     * This logger let you use a {@link java.util.Formatter} string in the
message to format parameters.
+     * </p>
+     * <p>
+     * Short-hand for {@code getLogger(value,
StringFormatterMessageFactory.INSTANCE)}
+     * </p>
+     *
+     * @param value
+     *            The value's whose class name should be used as the
Logger name.
+     * @return The Logger, created with a {@link
StringFormatterMessageFactory}
+     * @throws UnsupportedOperationException if {@code value} is {@code
null} and the calling class cannot be determined.
+     * @see Logger#fatal(Marker, String, Object...)
+     * @see Logger#fatal(String, Object...)
+     * @see Logger#error(Marker, String, Object...)
+     * @see Logger#error(String, Object...)
+     * @see Logger#warn(Marker, String, Object...)
+     * @see Logger#warn(String, Object...)
+     * @see Logger#info(Marker, String, Object...)
+     * @see Logger#info(String, Object...)
+     * @see Logger#debug(Marker, String, Object...)
+     * @see Logger#debug(String, Object...)
+     * @see Logger#trace(Marker, String, Object...)
+     * @see Logger#trace(String, Object...)
+     * @see StringFormatterMessageFactory
+     */
+    public static Logger getFormatterLogger(final Object value) {
+        return getLogger(value != null ? value.getClass() :
ReflectionUtil.getCallerClass(2),
+            StringFormatterMessageFactory.INSTANCE);
+    }
+
+    /**
+     * Returns a formatter Logger with the specified name.
+     * <p>
+     * This logger let you use a {@link java.util.Formatter} string in the
message to format parameters.
+     * </p>
+     * <p>
+     * Short-hand for {@code getLogger(name,
StringFormatterMessageFactory.INSTANCE)}
+     * </p>
+     *
+     * @param name The logger name. If null it will default to the name of
the calling class.
+     * @return The Logger, created with a {@link
StringFormatterMessageFactory}
+     * @throws UnsupportedOperationException if {@code name} is {@code
null} and the calling class cannot be determined.
+     * @see Logger#fatal(Marker, String, Object...)
+     * @see Logger#fatal(String, Object...)
+     * @see Logger#error(Marker, String, Object...)
+     * @see Logger#error(String, Object...)
+     * @see Logger#warn(Marker, String, Object...)
+     * @see Logger#warn(String, Object...)
+     * @see Logger#info(Marker, String, Object...)
+     * @see Logger#info(String, Object...)
+     * @see Logger#debug(Marker, String, Object...)
+     * @see Logger#debug(String, Object...)
+     * @see Logger#trace(Marker, String, Object...)
+     * @see Logger#trace(String, Object...)
+     * @see StringFormatterMessageFactory
+     */
+    public static Logger getFormatterLogger(final String name) {
+        return name == null ?
getFormatterLogger(ReflectionUtil.getCallerClass(2)) : getLogger(name,
+            StringFormatterMessageFactory.INSTANCE);
+    }
+
+    /**
+     * Returns a Logger with the name of the calling class.
+     * @return The Logger for the calling class.
+     * @throws UnsupportedOperationException if the calling class cannot
be determined.
+     */
+    public static Logger getLogger() {
+        return getLogger(ReflectionUtil.getCallerClass(2));
+    }
+
+    /**
+     * Returns a Logger using the fully qualified name of the Class as the
Logger name.
+     * @param clazz The Class whose name should be used as the Logger
name. If null it will default to the calling
+     *              class.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code clazz} is {@code
null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Class<?> clazz) {
+        if (clazz == null) {
+            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
+            if (candidate == null) {
+                throw new UnsupportedOperationException("No class
provided, and an appropriate one cannot be found.");
+            }
+            return getLogger(candidate);
+        }
+        return getContext(clazz.getClassLoader(),
false).getLogger(clazz.getName());
+    }
+
+    /**
+     * Returns a Logger using the fully qualified name of the Class as the
Logger name.
+     * @param clazz The Class whose name should be used as the Logger
name. If null it will default to the calling
+     *              class.
+     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if
mismatched.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code clazz} is {@code
null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Class<?> clazz, final
MessageFactory messageFactory) {
+        if (clazz == null) {
+            final Class<?> candidate = ReflectionUtil.getCallerClass(2);
+            if (candidate == null) {
+                throw new UnsupportedOperationException("No class
provided, and an appropriate one cannot be found.");
+            }
+            return getLogger(candidate, messageFactory);
+        }
+        return getContext(clazz.getClassLoader(),
false).getLogger(clazz.getName(), messageFactory);
+    }
+
+    /**
+     * Returns a Logger with the name of the calling class.
+     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if
mismatched.
+     * @return The Logger for the calling class.
+     * @throws UnsupportedOperationException if the calling class cannot
be determined.
+     */
+    public static Logger getLogger(final MessageFactory messageFactory) {
+        return getLogger(ReflectionUtil.getCallerClass(2), messageFactory);
+    }
+
+    /**
+     * Returns a Logger using the fully qualified class name of the value
as the Logger name.
+     * @param value The value whose class name should be used as the
Logger name. If null the name of the calling
+     *              class will be used as the logger name.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code value} is {@code
null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Object value) {
+        return getLogger(value != null ? value.getClass() :
ReflectionUtil.getCallerClass(2));
+    }
+
+    /**
+     * Returns a Logger using the fully qualified class name of the value
as the Logger name.
+     * @param value The value whose class name should be used as the
Logger name. If null the name of the calling
+     *              class will be used as the logger name.
+     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if
mismatched.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code value} is {@code
null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final Object value, final
MessageFactory messageFactory) {
+        return getLogger(value != null ? value.getClass() :
ReflectionUtil.getCallerClass(2), messageFactory);
+    }
+
+    /**
+     * Returns a Logger with the specified name.
+     *
+     * @param name The logger name. If null the name of the calling class
will be used.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code name} is {@code
null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final String name) {
+        return name != null ? getContext(false).getLogger(name) :
getLogger(ReflectionUtil.getCallerClass(2));
+    }
+
+    /**
+     * Returns a Logger with the specified name.
+     *
+     * @param name The logger name. If null the name of the calling class
will be used.
+     * @param messageFactory The message factory is used only when
creating a logger, subsequent use does not change
+     *                       the logger but will log a warning if
mismatched.
+     * @return The Logger.
+     * @throws UnsupportedOperationException if {@code name} is {@code
null} and the calling class cannot be determined.
+     */
+    public static Logger getLogger(final String name, final MessageFactory
messageFactory) {
+        return name != null ? getContext(false).getLogger(name,
messageFactory) : getLogger(
+            ReflectionUtil.getCallerClass(2), messageFactory);
+    }
+
+    /**
+     * Returns a Logger with the specified name.
+     *
+     * @param fqcn The fully qualified class name of the class that this
method is a member of.
+     * @param name The logger name.
+     * @return The Logger.
+     */
+    protected static Logger getLogger(final String fqcn, final String
name) {
+        return factory.getContext(fqcn, null, null, false).getLogger(name);
+    }
+
+    /**
+     * Returns the root logger.
+     *
+     * @return the root logger, named {@link #ROOT_LOGGER_NAME}.
+     */
+    public static Logger getRootLogger() {
+        return getLogger(ROOT_LOGGER_NAME);
+    }
+
+    /**
+     * Prevents instantiation
+     */
+    protected LogManager() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a60368c0/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6114e94..35bfbd1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -50,7 +50,10 @@
       </action>
       <action issue="LOG4J2-1066" dev="ggregory" type="add"
due-to="Charles Allen">
         Expose Log4jContextFactory's ShutdownCallbackRegistry.
-      </action>
+      </action>
+      <action issue="LOG4J2-1084" dev="ggregory" type="fix"
due-to="Philipp Schneider">
+        Misleading StatusLogger WARN event in LogManager with
java.util.Map.
+      </action>
       <action issue="LOG4J2-1051" dev="ggregory" type="fix" due-to="Lukasz
Lenart">
         NoClassDefFoundError when starting app on Google App Engine.
       </action>




-- 
E-Mail: garydgregory@gmail.com | ggregory@apache.org
Java Persistence with Hibernate, Second Edition
<http://www.manning.com/bauer3/>
JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
Spring Batch in Action <http://www.manning.com/templier/>
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory