You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2013/01/07 01:29:31 UTC

svn commit: r1429628 - in /logging/log4j/log4j2/trunk: ./ api/src/main/java/org/apache/logging/log4j/ api/src/main/java/org/apache/logging/log4j/spi/ api/src/main/java/org/apache/logging/log4j/util/ log4j-to-slf4j/ log4j-to-slf4j/src/ log4j-to-slf4j/sr...

Author: rgoers
Date: Mon Jan  7 00:29:30 2013
New Revision: 1429628

URL: http://svn.apache.org/viewvc?rev=1429628&view=rev
Log:
Add Log4j 2 to SLF4J adapter

Added:
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/Provider.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/   (with props)
    logging/log4j/log4j2/trunk/log4j-to-slf4j/pom.xml
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/META-INF/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/site.xml
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/xdoc/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/xdoc/index.xml
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/resources/
    logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/resources/logback-slf4j.xml
Modified:
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/LogManager.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java
    logging/log4j/log4j2/trunk/pom.xml
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/site.xml

Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/LogManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/LogManager.java?rev=1429628&r1=1429627&r2=1429628&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/LogManager.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/LogManager.java Mon Jan  7 00:29:30 2013
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.net.URL;
 import java.util.Enumeration;
 import java.util.Formatter;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Properties;
 import java.util.SortedMap;
@@ -30,8 +31,10 @@ import org.apache.logging.log4j.message.
 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.PropsUtil;
+import org.apache.logging.log4j.util.ProviderUtil;
 
 /**
  * The anchor point for the logging system.
@@ -62,9 +65,9 @@ public class LogManager {
      */
     static {
         // Shortcut binding to force a specific logging implementation.
-        final PropsUtil managerProps = new PropsUtil("log4j2.LogManager.properties");
+        final PropsUtil managerProps = PropsUtil.getComponentProperties();
         final String factoryClass = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
-        final ClassLoader cl = findClassLoader();
+        final ClassLoader cl = ProviderUtil.findClassLoader();
         if (factoryClass != null) {
             try {
                 final Class<?> clazz = cl.loadClass(factoryClass);
@@ -81,48 +84,33 @@ public class LogManager {
         if (factory == null) {
             final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>();
 
-            Enumeration<URL> enumResources = null;
-            try {
-                enumResources = cl.getResources(LOGGER_RESOURCE);
-            } catch (final IOException e) {
-                logger.fatal("Unable to locate " + LOGGER_RESOURCE, e);
-            }
-
-            if (enumResources != null) {
-                while (enumResources.hasMoreElements()) {
-                    final Properties props = new Properties();
-                    final URL url = enumResources.nextElement();
-                    try {
-                        props.load(url.openStream());
-                    } catch (final IOException ioe) {
-                        logger.error("Unable to read " + url.toString(), ioe);
-                    }
-                    if (!validVersion(props.getProperty(API_VERSION))) {
-                        continue;
-                    }
-                    final String weight = props.getProperty(FACTORY_PRIORITY);
-                    final Integer priority = weight == null ? -1 : Integer.valueOf(weight);
-                    final String className = props.getProperty(LOGGER_CONTEXT_FACTORY);
+            if (ProviderUtil.hasProviders()) {
+                Iterator<Provider> providers = ProviderUtil.getProviders();
+                while (providers.hasNext()) {
+                    Provider provider = providers.next();
+                    String className = provider.getClassName();
                     if (className != null) {
                         try {
                             final Class<?> clazz = cl.loadClass(className);
                             if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
-                                factories.put(priority, (LoggerContextFactory) clazz.newInstance());
+                                factories.put(provider.getPriority(), (LoggerContextFactory) clazz.newInstance());
                             } else {
                                 logger.error(className + " does not implement " + LoggerContextFactory.class.getName());
                             }
                         } catch (final ClassNotFoundException cnfe) {
-                            logger.error("Unable to locate class " + className + " specified in " + url.toString(),
-                                cnfe);
+                            logger.error("Unable to locate class " + className + " specified in " +
+                                provider.getURL().toString(), cnfe);
                         } catch (final IllegalAccessException iae) {
-                            logger.error("Unable to create class " + className + " specified in " + url.toString(),
-                                iae);
+                            logger.error("Unable to create class " + className + " specified in " +
+                                provider.getURL().toString(), iae);
                         } catch (final Exception e) {
-                            logger.error("Unable to create class " + className + " specified in " + url.toString(), e);
+                            logger.error("Unable to create class " + className + " specified in " +
+                                provider.getURL().toString(), e);
                             e.printStackTrace();
                         }
                     }
                 }
+
                 if (factories.size() == 0) {
                     logger.error("Unable to locate a logging implementation, using SimpleLogger");
                     factory = new SimpleLoggerContextFactory();
@@ -144,26 +132,6 @@ public class LogManager {
         }
     }
 
-    private static ClassLoader findClassLoader() {
-        ClassLoader cl;
-        if (System.getSecurityManager() == null) {
-            cl = Thread.currentThread().getContextClassLoader();
-        } else {
-            cl = java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<ClassLoader>() {
-                    public ClassLoader run() {
-                        return Thread.currentThread().getContextClassLoader();
-                    }
-                }
-            );
-        }
-        if (cl == null) {
-            cl = LogManager.class.getClassLoader();
-        }
-
-        return cl;
-    }
-
     /**
      * Returns the current LoggerContext.
      * <p>
@@ -247,7 +215,7 @@ public class LogManager {
      * <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}
@@ -277,7 +245,7 @@ public class LogManager {
      * <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}
@@ -307,7 +275,7 @@ public class LogManager {
      * <p>
      * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)}
      * </p>
-     * 
+     *
      * @param name
      *            The logger name.
      * @return The Logger, created with a {@link StringFormatterMessageFactory}

Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java?rev=1429628&r1=1429627&r2=1429628&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/ThreadContext.java Mon Jan  7 00:29:30 2013
@@ -18,11 +18,19 @@
 package org.apache.logging.log4j;
 
 import org.apache.logging.log4j.message.ParameterizedMessage;
+import org.apache.logging.log4j.spi.DefaultThreadContextMap;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.spi.Provider;
+import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.PropsUtil;
+import org.apache.logging.log4j.util.ProviderUtil;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -34,7 +42,7 @@ import java.util.NoSuchElementException;
  * the mapped diagnostic context of its parent.
  * </p>
  */
-public final class ThreadContext {
+public final class ThreadContext  {
 
     /**
      * Empty, immutable Map.
@@ -52,19 +60,65 @@ public final class ThreadContext {
 
     private static final String DISABLE_ALL = "disableThreadContext";
 
+    private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
+
     private static boolean all = Boolean.getBoolean(DISABLE_ALL);
 
     private static boolean useMap = !(Boolean.getBoolean(DISABLE_MAP) || all);
 
     private static boolean useStack = !(Boolean.getBoolean(DISABLE_STACK) || all);
 
-    private static ThreadLocal<Map<String, String>> localMap =
-        new InheritableThreadLocal<Map<String, String>>() {
-            @Override
-            protected Map<String, String> childValue(final Map<String, String> parentValue) {
-                return parentValue == null || !useMap ? null : new HashMap<String, String>(parentValue);
+    private static ThreadContextMap contextMap;
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    static {
+        final PropsUtil managerProps = PropsUtil.getComponentProperties();
+        String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
+        final ClassLoader cl = ProviderUtil.findClassLoader();
+        if (threadContextMapName != null) {
+            try {
+                final Class<?> clazz = cl.loadClass(threadContextMapName);
+                if (ThreadContextMap.class.isAssignableFrom(clazz)) {
+                    contextMap = (ThreadContextMap) clazz.newInstance();
+                }
+            } catch (final ClassNotFoundException cnfe) {
+                LOGGER.error("Unable to locate configured LoggerContextFactory {}", threadContextMapName);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create configured LoggerContextFactory {}", threadContextMapName, ex);
+            }
+        }
+        if (contextMap == null && ProviderUtil.hasProviders()) {
+            LoggerContextFactory factory = LogManager.getFactory();
+            Iterator<Provider> providers = ProviderUtil.getProviders();
+            while (providers.hasNext()) {
+                Provider provider = providers.next();
+                threadContextMapName = provider.getThreadContextMap();
+                String factoryClassName = provider.getClassName();
+                if (threadContextMapName != null && factory.getClass().getName().equals(factoryClassName)) {
+                    try {
+                        final Class<?> clazz = cl.loadClass(threadContextMapName);
+                        if (ThreadContextMap.class.isAssignableFrom(clazz)) {
+                            contextMap = (ThreadContextMap) clazz.newInstance();
+                            break;
+                        }
+                    } catch (final ClassNotFoundException cnfe) {
+                        LOGGER.error("Unable to locate configured LoggerContextFactory {}", threadContextMapName);
+                        contextMap = new DefaultThreadContextMap(useMap);
+                    } catch (final Exception ex) {
+                        LOGGER.error("Unable to create configured LoggerContextFactory {}", threadContextMapName, ex);
+                        contextMap = new DefaultThreadContextMap(useMap);
+                    }
+                }
+            }
+            if (contextMap == null) {
+                contextMap = new DefaultThreadContextMap(useMap);
             }
-        };
+
+        } else {
+            contextMap = new DefaultThreadContextMap(useMap);
+        }
+    }
 
     private static ThreadLocal<ContextStack> localStack = new ThreadLocal<ContextStack>();
 
@@ -83,15 +137,7 @@ public final class ThreadContext {
      * @param value The key value.
      */
     public static void put(final String key, final String value) {
-        if (!useMap) {
-            return;
-        }
-        Map<String, String> map = localMap.get();
-        if (map == null) {
-            map = new HashMap<String, String>();
-            localMap.set(map);
-        }
-        map.put(key, value);
+        contextMap.put(key, value);
     }
 
     /**
@@ -102,8 +148,7 @@ public final class ThreadContext {
      * @return The value associated with the key or null.
      */
     public static String get(final String key) {
-        final Map<String, String> map = localMap.get();
-        return map == null ? null : map.get(key);
+        return contextMap.get(key);
     }
 
     /**
@@ -112,17 +157,14 @@ public final class ThreadContext {
      * @param key The key to remove.
      */
     public static void remove(final String key) {
-        final Map<String, String> map = localMap.get();
-        if (map != null) {
-            map.remove(key);
-        }
+        contextMap.remove(key);
     }
 
     /**
      * Clear the context.
      */
     public static void clear() {
-        localMap.remove();
+        contextMap.clear();
     }
 
     /**
@@ -131,8 +173,7 @@ public final class ThreadContext {
      * @return True if the key is in the context, false otherwise.
      */
     public static boolean containsKey(final String key) {
-        final Map<String, String> map = localMap.get();
-        return map == null ? false : map.containsKey(key);
+        return contextMap.containsKey(key);
     }
 
     /**
@@ -140,8 +181,7 @@ public final class ThreadContext {
      * @return a copy of the context.
      */
     public static Map<String, String> getContext() {
-        final Map<String, String> map = localMap.get();
-        return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
+        return contextMap.getContext();
     }
 
     /**
@@ -149,7 +189,7 @@ public final class ThreadContext {
      * @return An immutable copy of the ThreadContext Map.
      */
     public static Map<String, String> getImmutableContext() {
-        final Map<String, String> map = localMap.get();
+        final Map<String, String> map = contextMap.get();
         return map == null ? new ImmutableMap() : new ImmutableMap(map);
     }
 
@@ -158,8 +198,7 @@ public final class ThreadContext {
      * @return true if the Map is empty, false otherwise.
      */
     public static boolean isEmpty() {
-        final Map<String, String> map = localMap.get();
-        return map == null || map.size() == 0;
+        return contextMap.isEmpty();
     }
 
     /**

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,129 @@
+/*
+ * 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.spi;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class DefaultThreadContextMap implements ThreadContextMap {
+
+    private boolean useMap;
+
+    private ThreadLocal<Map<String, String>> localMap =
+        new InheritableThreadLocal<Map<String, String>>() {
+            @Override
+            protected Map<String, String> childValue(final Map<String, String> parentValue) {
+                return parentValue == null || !useMap ? null : new HashMap<String, String>(parentValue);
+            }
+        };
+
+    public DefaultThreadContextMap(boolean useMap) {
+        this.useMap = useMap;
+    }
+
+    /**
+     * Put a context value (the <code>o</code> parameter) as identified
+     * with the <code>key</code> parameter into the current thread's
+     * context map.
+     * <p/>
+     * <p>If the current thread does not have a context map it is
+     * created as a side effect.
+     * @param key The key name.
+     * @param value The key value.
+     */
+    public void put(final String key, final String value) {
+        if (!useMap) {
+            return;
+        }
+        Map<String, String> map = localMap.get();
+        if (map == null) {
+            map = new HashMap<String, String>();
+            localMap.set(map);
+        }
+        map.put(key, value);
+    }
+
+    /**
+     * Get the context identified by the <code>key</code> parameter.
+     * <p/>
+     * <p>This method has no side effects.
+     * @param key The key to locate.
+     * @return The value associated with the key or null.
+     */
+    public String get(final String key) {
+        final Map<String, String> map = localMap.get();
+        return map == null ? null : map.get(key);
+    }
+
+    /**
+     * Remove the the context identified by the <code>key</code>
+     * parameter.
+     * @param key The key to remove.
+     */
+    public void remove(final String key) {
+        final Map<String, String> map = localMap.get();
+        if (map != null) {
+            map.remove(key);
+        }
+    }
+
+    /**
+     * Clear the context.
+     */
+    public void clear() {
+        localMap.remove();
+    }
+
+    /**
+     * Determine if the key is in the context.
+     * @param key The key to locate.
+     * @return True if the key is in the context, false otherwise.
+     */
+    public boolean containsKey(final String key) {
+        final Map<String, String> map = localMap.get();
+        return map == null ? false : map.containsKey(key);
+    }
+
+    /**
+     * Get a copy of current thread's context Map.
+     * @return a copy of the context.
+     */
+    public Map<String, String> getContext() {
+        final Map<String, String> map = localMap.get();
+        return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
+    }
+
+    /**
+     * Return the context Map.
+     * @return the Context Map.
+     */
+    public Map<String, String> get() {
+        return localMap.get();
+    }
+
+    /**
+     * Returns true if the Map is empty.
+     * @return true if the Map is empty, false otherwise.
+     */
+    public boolean isEmpty() {
+        final Map<String, String> map = localMap.get();
+        return map == null || map.size() == 0;
+    }
+}

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/Provider.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/Provider.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/Provider.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/Provider.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.spi;
+
+import java.net.URL;
+import java.util.Properties;
+
+/**
+ *
+ */
+public class Provider {
+    private static final String FACTORY_PRIORITY = "FactoryPriority";
+    private static final String THREAD_CONTEXT_MAP = "ThreadContextMap";
+    private static final String LOGGER_CONTEXT_FACTORY = "LoggerContextFactory";
+
+    private final Integer priority;
+    private final String className;
+    private final String threadContextMap;
+    private final URL url;
+
+    public Provider(Properties props, URL url) {
+        this.url = url;
+        final String weight = props.getProperty(FACTORY_PRIORITY);
+        priority = weight == null ? -1 : Integer.valueOf(weight);
+        className = props.getProperty(LOGGER_CONTEXT_FACTORY);
+        threadContextMap = props.getProperty(THREAD_CONTEXT_MAP);
+    }
+
+    public Integer getPriority() {
+        return priority;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public String getThreadContextMap() {
+        return threadContextMap;
+    }
+
+    public URL getURL() {
+        return url;
+    }
+}

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMap.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,66 @@
+package org.apache.logging.log4j.spi;
+
+import java.util.Map;
+
+/**
+ *
+ */
+public interface ThreadContextMap {
+    /**
+     * Put a context value (the <code>o</code> parameter) as identified
+     * with the <code>key</code> parameter into the current thread's
+     * context map.
+     * <p/>
+     * <p>If the current thread does not have a context map it is
+     * created as a side effect.
+     * @param key The key name.
+     * @param value The key value.
+     */
+    void put(final String key, final String value);
+
+    /**
+     * Get the context identified by the <code>key</code> parameter.
+     * <p/>
+     * <p>This method has no side effects.
+     * @param key The key to locate.
+     * @return The value associated with the key or null.
+     */
+    String get(final String key);
+
+    /**
+     * Remove the the context identified by the <code>key</code>
+     * parameter.
+     * @param key The key to remove.
+     */
+    void remove(final String key);
+
+    /**
+     * Clear the context.
+     */
+    void clear();
+
+    /**
+     * Determine if the key is in the context.
+     * @param key The key to locate.
+     * @return True if the key is in the context, false otherwise.
+     */
+    boolean containsKey(final String key);
+
+    /**
+     * Get a copy of current thread's context Map.
+     * @return a copy of the context.
+     */
+    Map<String, String> getContext();
+
+    /**
+     * Return the actual context Map.
+     * @return the actual context Map.
+     */
+    Map<String, String> get();
+
+    /**
+     * Returns true if the Map is empty.
+     * @return true if the Map is empty, false otherwise.
+     */
+    boolean isEmpty();
+}

Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java?rev=1429628&r1=1429627&r2=1429628&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java Mon Jan  7 00:29:30 2013
@@ -26,13 +26,20 @@ public class PropsUtil {
 
     private final Properties props;
 
+    private static final PropsUtil LOG4J_PROPERTIES = new PropsUtil("log4j2.component.properties");
+
+    public static PropsUtil getComponentProperties() {
+        return LOG4J_PROPERTIES;
+    }
+
+
     public PropsUtil(final Properties props) {
         this.props = props;
     }
 
     public PropsUtil(final String propsLocn) {
         this.props = new Properties();
-        final ClassLoader loader = findClassLoader();
+        final ClassLoader loader = ProviderUtil.findClassLoader();
         final InputStream in = loader.getResourceAsStream(propsLocn);
         if (null != in) {
             try {
@@ -63,24 +70,4 @@ public class PropsUtil {
         final String prop = getStringProperty(name);
         return (prop == null) ? defaultValue : "true".equalsIgnoreCase(prop);
     }
-
-    private static ClassLoader findClassLoader() {
-        ClassLoader cl;
-        if (System.getSecurityManager() == null) {
-            cl = Thread.currentThread().getContextClassLoader();
-        } else {
-            cl = java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<ClassLoader>() {
-                    public ClassLoader run() {
-                        return Thread.currentThread().getContextClassLoader();
-                    }
-                }
-            );
-        }
-        if (cl == null) {
-            cl = PropsUtil.class.getClassLoader();
-        }
-
-        return cl;
-    }
 }

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,112 @@
+/*
+ * 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.util;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.spi.Provider;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ *
+ */
+public final class ProviderUtil {
+
+    private static final String PROVIDER_RESOURCE = "META-INF/log4j-provider.properties";
+    private static final String API_VERSION = "Log4jAPIVersion";
+
+    private static final String[] COMPATIBLE_API_VERSIONS = {
+        "2.0.0"
+    };
+
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private static final List<Provider> providers = new ArrayList<Provider>();
+
+    private ProviderUtil() {
+    }
+
+    static {
+        ClassLoader cl = findClassLoader();
+        Enumeration<URL> enumResources = null;
+        try {
+            enumResources = cl.getResources(PROVIDER_RESOURCE);
+        } catch (final IOException e) {
+            LOGGER.fatal("Unable to locate " + PROVIDER_RESOURCE, e);
+        }
+
+        if (enumResources != null) {
+            while (enumResources.hasMoreElements()) {
+                final Properties props = new Properties();
+                final URL url = enumResources.nextElement();
+                try {
+                    props.load(url.openStream());
+                } catch (final IOException ioe) {
+                    LOGGER.error("Unable to read " + url.toString(), ioe);
+                }
+                if (!validVersion(props.getProperty(API_VERSION))) {
+                    continue;
+                }
+                providers.add(new Provider(props, url));
+            }
+        }
+    }
+
+    public static Iterator<Provider> getProviders() {
+        return providers.iterator();
+    }
+
+    public static boolean hasProviders() {
+        return providers.size() > 0;
+    }
+
+    public static ClassLoader findClassLoader() {
+        ClassLoader cl;
+        if (System.getSecurityManager() == null) {
+            cl = Thread.currentThread().getContextClassLoader();
+        } else {
+            cl = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ClassLoader>() {
+                    public ClassLoader run() {
+                        return Thread.currentThread().getContextClassLoader();
+                    }
+                }
+            );
+        }
+        if (cl == null) {
+            cl = ProviderUtil.class.getClassLoader();
+        }
+
+        return cl;
+    }
+
+    private static boolean validVersion(final String version) {
+        for (final String v : COMPATIBLE_API_VERSIONS) {
+            if (version.startsWith(v)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

Propchange: logging/log4j/log4j2/trunk/log4j-to-slf4j/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Mon Jan  7 00:29:30 2013
@@ -0,0 +1,2 @@
+target
+*.iml

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/pom.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/pom.xml?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/pom.xml (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/pom.xml Mon Jan  7 00:29:30 2013
@@ -0,0 +1,187 @@
+<!--
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.logging.log4j</groupId>
+    <artifactId>log4j</artifactId>
+    <version>2.0-beta4-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+  <groupId>org.apache.logging.log4j.adapters</groupId>
+  <artifactId>log4j-to-slf4j</artifactId>
+  <packaging>jar</packaging>
+  <name>Apache Log4j to SLF4J Adapter</name>
+  <description>Binding between LOG4J 2 API and SLF4J</description>
+  <properties>
+    <log4jParentDir>${basedir}/..</log4jParentDir>
+    <docLabel>SLF4J Documentation</docLabel>
+    <projectDir>/log4j-to-slf4j</projectDir>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-core</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+      <reporting>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-changes-plugin</artifactId>
+            <version>${changes.plugin.version}</version>
+            <reportSets>
+              <reportSet>
+                <reports>
+                  <report>changes-report</report>
+                </reports>
+              </reportSet>
+            </reportSets>
+            <configuration>
+              <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-checkstyle-plugin</artifactId>
+            <version>2.7</version>
+            <configuration>
+              <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> -->
+              <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+              <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+              <enableRulesSummary>false</enableRulesSummary>
+              <propertyExpansion>basedir=${basedir}</propertyExpansion>
+              <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>${javadoc.plugin.version}</version>
+            <configuration>
+              <bottom> <![CDATA[<p align="center">Copyright &#169; {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
+            Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo,
+            and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom>
+              <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating
+                   project -->
+              <detectOfflineLinks>false</detectOfflineLinks>
+              <linksource>true</linksource>
+              <tags>
+                <tag>
+                  <name>issue</name>
+                  <placement>a</placement>
+                  <head>JIRA issue:</head>
+                </tag>
+                <tag>
+                  <name>doubt</name>
+                  <placement>a</placement>
+                  <head>Troublesome:</head>
+                </tag>
+                <tag>
+                  <name>compare</name>
+                  <placement>a</placement>
+                  <head>Compare with:</head>
+                </tag>
+              </tags>
+            </configuration>
+            <reportSets>
+              <reportSet>
+                <id>non-aggregate</id>
+                <reports>
+                  <report>javadoc</report>
+                </reports>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>findbugs-maven-plugin</artifactId>
+            <version>2.3.2</version>
+            <configuration>
+              <threshold>Normal</threshold>
+              <effort>Default</effort>
+              <excludeFilterFile>findbugs-exclude-filter.xml</excludeFilterFile>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jxr-plugin</artifactId>
+            <version>2.3</version>
+            <reportSets>
+              <reportSet>
+                <id>non-aggregate</id>
+                <reports>
+                  <report>jxr</report>
+                </reports>
+              </reportSet>
+              <reportSet>
+                <id>aggregate</id>
+                <reports>
+                  <report>aggregate</report>
+                </reports>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-pmd-plugin</artifactId>
+            <version>${pmd.plugin.version}</version>
+            <configuration>
+              <targetJdk>1.5</targetJdk>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>cobertura-maven-plugin</artifactId>
+            <version>2.2</version>
+            <reportSets>
+              <reportSet>
+                <!-- Disabled at it kills the site generation via a NoClassDefFoundError -->
+                <reports />
+              </reportSet>
+            </reportSets>
+          </plugin>
+        </plugins>
+      </reporting>
+</project>
+

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,59 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.slf4j.MDC;
+
+import java.util.Map;
+
+/**
+ * Bind the ThreadContextMap to the SLF4J MDC.
+ */
+public class MDCContextMap implements ThreadContextMap {
+    public void put(String key, String value) {
+        MDC.put(key, value);
+    }
+
+    public String get(String key) {
+        return MDC.get(key);
+    }
+
+    public void remove(String key) {
+        MDC.remove(key);
+    }
+
+    public void clear() {
+        MDC.clear();
+    }
+
+    public boolean containsKey(String key) {
+        return MDC.getCopyOfContextMap().containsKey(key);
+    }
+
+    public Map<String, String> getContext() {
+        return MDC.getCopyOfContextMap();
+    }
+
+    public Map<String, String> get() {
+        return MDC.getCopyOfContextMap();
+    }
+
+    public boolean isEmpty() {
+        return MDC.getCopyOfContextMap().isEmpty();
+    }
+}

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,152 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.message.LoggerNameAwareMessage;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.slf4j.MarkerFactory;
+import org.slf4j.spi.LocationAwareLogger;
+
+/**
+ *
+ */
+public class SLF4JLogger extends AbstractLogger {
+
+    private final org.slf4j.Logger logger;
+    private final LocationAwareLogger locationAwareLogger;
+
+    public SLF4JLogger(final String name, final org.slf4j.Logger logger) {
+        super(name);
+        this.logger = logger;
+        this.locationAwareLogger = logger instanceof LocationAwareLogger ? (LocationAwareLogger) logger : null;
+    }
+
+    public SLF4JLogger(final String name, final MessageFactory messageFactory, final org.slf4j.Logger logger) {
+        super(name, messageFactory);
+        this.logger = logger;
+        this.locationAwareLogger = logger instanceof LocationAwareLogger ? (LocationAwareLogger) logger : null;
+    }
+
+    @Override
+    protected void log(Marker marker, String fqcn, Level level, Message data, Throwable t) {
+        if (locationAwareLogger != null) {
+            if (data instanceof LoggerNameAwareMessage) {
+                ((LoggerNameAwareMessage) data).setLoggerName(getName());
+            }
+            locationAwareLogger.log(getMarker(marker), fqcn, convertLevel(level), data.getFormattedMessage(),
+                data.getParameters(), t);
+        } else {
+            switch (level) {
+                case DEBUG :
+                    logger.debug(getMarker(marker), data.getFormattedMessage(), data.getParameters(), t);
+                case TRACE :
+                    logger.trace(getMarker(marker), data.getFormattedMessage(), data.getParameters(), t);
+                case INFO :
+                    logger.info(getMarker(marker), data.getFormattedMessage(), data.getParameters(), t);
+                case WARN :
+                    logger.warn(getMarker(marker), data.getFormattedMessage(), data.getParameters(), t);
+                case ERROR :
+                    logger.error(getMarker(marker), data.getFormattedMessage(), data.getParameters(), t);
+                default :
+                    logger.error(getMarker(marker), data.getFormattedMessage(), data.getParameters(), t);
+            }
+        }
+    }
+
+    private org.slf4j.Marker getMarker(Marker marker) {
+        if (marker == null) {
+            return null;
+        }
+        Marker parent = marker.getParent();
+        org.slf4j.Marker parentMarker = parent == null ? null : getMarker(parent);
+        org.slf4j.Marker slf4jMarker = MarkerFactory.getMarker(marker.getName());
+        if (parentMarker != null && !slf4jMarker.contains(parentMarker)) {
+            slf4jMarker.add(parentMarker);
+        }
+        return slf4jMarker;
+    }
+
+    private int convertLevel(Level level) {
+        switch (level) {
+            case DEBUG :
+                return LocationAwareLogger.DEBUG_INT;
+            case TRACE :
+                return LocationAwareLogger.TRACE_INT;
+            case INFO :
+                return LocationAwareLogger.INFO_INT;
+            case WARN :
+                return LocationAwareLogger.WARN_INT;
+            case ERROR :
+                return LocationAwareLogger.ERROR_INT;
+            default :
+                return LocationAwareLogger.ERROR_INT;
+        }
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data) {
+        return isEnabledFor(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Throwable t) {
+        return isEnabledFor(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String data, Object... p1) {
+        return isEnabledFor(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Object data, Throwable t) {
+        return isEnabledFor(level, marker);
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Message data, Throwable t) {
+        return isEnabledFor(level, marker);
+    }
+
+    private boolean isEnabledFor(Level level, Marker marker) {
+        org.slf4j.Marker slf4jMarker = getMarker(marker);
+        switch (level) {
+            case DEBUG :
+                return logger.isDebugEnabled(slf4jMarker);
+            case TRACE :
+                return logger.isTraceEnabled(slf4jMarker);
+            case INFO :
+                return logger.isInfoEnabled(slf4jMarker);
+            case WARN :
+                return logger.isWarnEnabled(slf4jMarker);
+            case ERROR :
+                return logger.isErrorEnabled(slf4jMarker);
+            default :
+                return logger.isErrorEnabled(slf4jMarker);
+
+        }
+    }
+
+    public org.slf4j.Logger getLogger() {
+        return locationAwareLogger != null ? locationAwareLogger : logger;
+    }
+
+}

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContext.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,54 @@
+/*
+ * 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.slf4j;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ *
+ */
+public class SLF4JLoggerContext implements LoggerContext {
+    private final ConcurrentMap<String, SLF4JLogger> loggers = new ConcurrentHashMap<String, SLF4JLogger>();
+
+    public Object getExternalContext() {
+        return null;
+    }
+
+    public Logger getLogger(String name) {
+        if (!loggers.containsKey(name)) {
+            loggers.putIfAbsent(name, new SLF4JLogger(name, LoggerFactory.getLogger(name)));
+        }
+        return loggers.get(name);
+    }
+
+    public Logger getLogger(String name, MessageFactory messageFactory) {
+        if (!loggers.containsKey(name)) {
+            loggers.putIfAbsent(name, new SLF4JLogger(name, messageFactory, LoggerFactory.getLogger(name)));
+        }
+        return loggers.get(name);
+    }
+
+    public boolean hasLogger(String name) {
+        return loggers.containsKey(name);
+    }
+}

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLoggerContextFactory.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.slf4j;
+
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+
+/**
+ *
+ */
+public class SLF4JLoggerContextFactory implements LoggerContextFactory {
+    private static LoggerContext context = new SLF4JLoggerContext();
+
+    public LoggerContext getContext(final String FQCN, final ClassLoader loader, final boolean currentContext) {
+        return context;
+    }
+}

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/package-info.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+/**
+ * SLF4J support.
+ */
+package org.apache.logging.slf4j;

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/main/resources/META-INF/log4j-provider.properties Mon Jan  7 00:29:30 2013
@@ -0,0 +1,19 @@
+# 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.
+
+LoggerContextFactory = org.apache.logging.slf4j.SLF4JLoggerContextFactory
+Log4jAPIVersion = 2.0.0
+FactoryPriority= 15
+ThreadContextMap = org.apache.logging.slf4j.MDCContextMap
\ No newline at end of file

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/site.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/site.xml?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/site.xml (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/site.xml Mon Jan  7 00:29:30 2013
@@ -0,0 +1,27 @@
+<!--
+ 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.
+
+-->
+<project name="Log4jToSLF4J">
+  <body>
+    <links>
+      <item name="Apache" href="http://www.apache.org/" />
+      <item name="Logging Services" href="http://logging.apache.org/"/>
+      <item name="Log4j" href="../index.html"/>
+    </links>
+    <menu ref="reports"/>
+  </body>
+</project>

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/xdoc/index.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/xdoc/index.xml?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/xdoc/index.xml (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/site/xdoc/index.xml Mon Jan  7 00:29:30 2013
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!--
+    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.
+-->
+
+<document>
+    <properties>
+        <title>Log4j to SLF4J Adapter</title>
+        <author email="rgoers@apache.org">Ralph Goers</author>
+    </properties>
+
+    <body>
+        <section name="Log4j 2 to SLF4J Adapter">
+
+            <p>
+              The Log4j 2 to SLF4J Adapter allows applications coded to the Log4j 2 API to be routed to SLF4J.
+              Use of this adapter may cause some loss of performance as the Log4j 2 Messages must be formatted
+              before they can be passed to SLF4J. With Log4j 2 as the implementation these would normally be
+              formatted only when they are accessed by a Filter or Appender.
+            </p>
+
+        </section>
+
+        <section name="Requirements">
+           <p>
+             The Log4j 2 to SLF4J adapter requires at least Java 5. Use of this adapter together with the
+             SLF4J bridge should never be attempted as it will cause a events to endlessly be routed between
+             SLF4J and Log4j 2.
+          </p>
+        </section>
+
+      <section name="Usage">
+        <p>
+          Include this jar, the SLF4J jar(s) and an SLF4J logging implementation jar together. Configure
+          the logging implementation as required.
+        </p>
+      </section>
+
+    </body>
+</document>
\ No newline at end of file

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/java/org/apache/logging/slf4j/LoggerTest.java Mon Jan  7 00:29:30 2013
@@ -0,0 +1,174 @@
+
+/*
+* 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.slf4j;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Date;
+import java.util.List;
+
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.message.ParameterizedMessageFactory;
+import org.apache.logging.log4j.message.StringFormatterMessageFactory;
+import ch.qos.logback.core.testUtil.StringListAppender;
+import ch.qos.logback.classic.LoggerContext;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class LoggerTest {
+
+    private static final String CONFIG = "target/test-classes/logback-slf4j.xml";
+    private static Logger logger;
+    private static org.slf4j.Logger slf4jLogger;
+    private static LoggerContext context;
+    private static Logger root;
+    private static ch.qos.logback.classic.Logger rootLogger;
+    private static StringListAppender<ILoggingEvent> list;
+
+    @BeforeClass
+    public static void setupClass() throws Exception {
+        slf4jLogger = LoggerFactory.getLogger(LoggerTest.class);
+        context = ((ch.qos.logback.classic.Logger) slf4jLogger).getLoggerContext();
+        configure(CONFIG);
+        logger = LogManager.getLogger(LoggerTest.class);
+        assertTrue("Incorrect SLF4J Logger", ((SLF4JLogger) logger).getLogger() == slf4jLogger);
+        root = LogManager.getLogger("");
+        rootLogger = context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
+        list = (StringListAppender<ILoggingEvent>) rootLogger.getAppender("LIST");
+        rootLogger.detachAppender("console");
+    }
+
+    private static void configure(String file) throws JoranException {
+        JoranConfigurator jc = new JoranConfigurator();
+        jc.setContext(context);
+        jc.doConfigure(file);
+    }
+
+    @Before
+    public void before() {
+        list.strList.clear();
+    }
+
+    @Test
+    public void basicFlow() {
+        logger.entry();
+        logger.exit();
+        assertTrue("Incorrect number of events. Expected 2, actual " + list.strList.size(), list.strList.size() == 2);
+    }
+
+    @Test
+    public void simpleFlow() {
+        logger.entry(CONFIG);
+        logger.exit(0);
+        assertTrue("Incorrect number of events. Expected 2, actual " + list.strList.size(), list.strList.size() == 2);
+    }
+
+    @Test
+    public void throwing() {
+        logger.throwing(new IllegalArgumentException("Test Exception"));
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+    }
+
+    @Test
+    public void catching() {
+        try {
+            throw new NullPointerException();
+        } catch (final Exception e) {
+            logger.catching(e);
+        }
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+    }
+
+    @Test
+    public void debug() {
+        logger.debug("Debug message");
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+    }
+
+    @Test
+    public void getLogger_String_MessageFactoryMismatch() {
+        final Logger testLogger = testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatch",
+            StringFormatterMessageFactory.INSTANCE, ParameterizedMessageFactory.INSTANCE);
+        testLogger.debug("%,d", Integer.MAX_VALUE);
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+        assertEquals(String.format("%,d", Integer.MAX_VALUE), list.strList.get(0));
+    }
+
+    @Test
+    public void getLogger_String_MessageFactoryMismatchNull() {
+        final Logger testLogger =  testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatchNull",
+            StringFormatterMessageFactory.INSTANCE, null);
+        testLogger.debug("%,d", Integer.MAX_VALUE);
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+        assertEquals(String.format("%,d", Integer.MAX_VALUE), list.strList.get(0));
+    }
+
+    private Logger testMessageFactoryMismatch(final String name, final MessageFactory messageFactory1, final MessageFactory messageFactory2) {
+        final Logger testLogger = (Logger) LogManager.getLogger(name, messageFactory1);
+        assertNotNull(testLogger);
+        assertEquals(messageFactory1, testLogger.getMessageFactory());
+        final Logger testLogger2 = (Logger) LogManager.getLogger(name, messageFactory2);
+        assertEquals(messageFactory1, testLogger2.getMessageFactory());
+        return testLogger;
+    }
+
+    @Test
+    public void debugObject() {
+        logger.debug(new Date());
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+    }
+
+    @Test
+    public void debugWithParms() {
+        logger.debug("Hello, {}", "World");
+        assertTrue("Incorrect number of events. Expected 1, actual " + list.strList.size(), list.strList.size() == 1);
+    }
+
+    @Test
+    public void testImpliedThrowable() {
+        logger.debug("This is a test", new Throwable("Testing"));
+        final List<String> msgs = list.strList;
+        assertTrue("Incorrect number of messages. Expected 1, actual " + msgs.size(), msgs.size() == 1);
+        String expected = "java.lang.Throwable: Testing";
+        assertTrue("Incorrect message data", msgs.get(0).contains(expected));
+    }
+    @Test
+    public void mdc() {
+        ThreadContext.put("TestYear", new Integer(2010).toString());
+        logger.debug("Debug message");
+        ThreadContext.clear();
+        logger.debug("Debug message");
+        assertTrue("Incorrect number of events. Expected 2, actual " + list.strList.size(), list.strList.size() == 2);
+        assertTrue("Incorrect year", list.strList.get(0).startsWith("2010"));
+    }
+}
+

Added: logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/resources/logback-slf4j.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/resources/logback-slf4j.xml?rev=1429628&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/resources/logback-slf4j.xml (added)
+++ logging/log4j/log4j2/trunk/log4j-to-slf4j/src/test/resources/logback-slf4j.xml Mon Jan  7 00:29:30 2013
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+  <appender name="LIST" class="ch.qos.logback.core.testUtil.StringListAppender">
+    <layout class="ch.qos.logback.classic.PatternLayout">
+      <Pattern>%X{TestYear}%msg</Pattern>
+    </layout>
+  </appender>
+
+  <root level="trace">
+    <appender-ref ref="LIST" />
+  </root>
+</configuration>

Modified: logging/log4j/log4j2/trunk/pom.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/pom.xml?rev=1429628&r1=1429627&r2=1429628&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/pom.xml (original)
+++ logging/log4j/log4j2/trunk/pom.xml Mon Jan  7 00:29:30 2013
@@ -139,6 +139,13 @@
       </dependency>
       <dependency>
         <groupId>ch.qos.logback</groupId>
+        <artifactId>logback-core</artifactId>
+        <type>test-jar</type>
+        <version>${logback.version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
         <version>${logback.version}</version>
       </dependency>
@@ -526,6 +533,7 @@
     <module>core</module>
     <module>log4j12-api</module>
     <module>slf4j-impl</module>
+    <module>log4j-to-slf4j</module>
     <module>jcl-bridge</module>
     <module>flume-ng</module>
     <module>web</module>

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1429628&r1=1429627&r2=1429628&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Mon Jan  7 00:29:30 2013
@@ -23,6 +23,9 @@
 
   <body>
     <release version="2.0-beta4" date="TBD" description="Bug fixes and enhancements">
+      <action dev="rgoers" type="add">
+        Added Log4j 2 to SLF4J adapter.
+      </action>
       <action issue="LOG4J2-140" dev="ggregory" type="fix" due-to="Joern Huxhorn">
         Typo in documentation of SocketAppender.
       </action>

Modified: logging/log4j/log4j2/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/site.xml?rev=1429628&r1=1429627&r2=1429628&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/site.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/site.xml Mon Jan  7 00:29:30 2013
@@ -124,6 +124,7 @@
       <item name="Commons Logging Bridge" href="log4j-jcl/index.html"/>
       <item name="Log4J 1.2 API" href="log4j-1.2-api/index.html"/>
       <item name="SLF4J Binding" href="log4j-slf4j-impl/index.html"/>
+      <item name="Log4j 2 to SLF4J Adapter" href="log4j-to-slf4j/index.html"/>
       <item name="Apache Flume" href="log4j-flume-ng/index.html"/>
       <item name="Log4j Web" href="log4j-web/index.html"/>
     </menu>