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 2012/10/18 22:54:29 UTC

svn commit: r1399852 - in /logging/log4j/log4j2/trunk: api/src/main/java/org/apache/logging/log4j/ api/src/main/java/org/apache/logging/log4j/simple/ api/src/main/java/org/apache/logging/log4j/status/ api/src/main/java/org/apache/logging/log4j/util/ ap...

Author: rgoers
Date: Thu Oct 18 20:54:28 2012
New Revision: 1399852

URL: http://svn.apache.org/viewvc?rev=1399852&view=rev
Log:
Avoid NPE when duplicate LoggerContextFactorys are present. Allow factories to specify a weight to allow real implementations to outrank test implementations. Provide a simple default LoggerContextFactory.

Added:
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/
    logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLogger.java
      - copied, changed from r1397892, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLogger.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java
      - copied, changed from r1397892, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java
      - copied, changed from r1397892, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContextFactory.java
Removed:
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLogger.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContextFactory.java
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/status/StatusLogger.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/EventLoggerTest.java
    logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/LoggerTest.java
    logging/log4j/log4j2/trunk/api/src/test/resources/META-INF/log4j-provider.xml
    logging/log4j/log4j2/trunk/core/src/main/resources/META-INF/log4j-provider.xml
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java
    logging/log4j/log4j2/trunk/flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java
    logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/CategoryTest.java
    logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/LoggerTest.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.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=1399852&r1=1399851&r2=1399852&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 Thu Oct 18 20:54:28 2012
@@ -16,16 +16,19 @@
  */
 package org.apache.logging.log4j;
 
+import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.spi.LoggerContext;
 import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.util.PropsUtil;
 
 import java.io.IOException;
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.List;
+import java.util.Map;
 import java.util.Properties;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 /**
  * The anchor point for the logging system.
@@ -39,10 +42,13 @@ public class LogManager {
     private static final String LOGGER_RESOURCE = "META-INF/log4j-provider.xml";
     private static final String LOGGER_CONTEXT_FACTORY = "LoggerContextFactory";
     private static final String API_VERSION = "Log4jAPIVersion";
+    private static final String FACTORY_PRIORITY = "FactoryPriority";
     private static final String[] COMPATIBLE_API_VERSIONS = {
-        "1.99.0"
+        "2.0.0"
     };
 
+    private static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory";
+
     private static LoggerContextFactory factory;
 
     private static final Logger logger = StatusLogger.getLogger();
@@ -58,54 +64,85 @@ public class LogManager {
      * be used but this could be extended to allow multiple implementations to be used.
      */
     static {
+        PropsUtil managerProps = new PropsUtil("log4j2.LogManager.properties");
+        String factoryClass = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
         ClassLoader cl = findClassLoader();
-        List<LoggerContextFactory> factories = new ArrayList<LoggerContextFactory>();
-
-        Enumeration<URL> enumResources = null;
-        try {
-            enumResources = cl.getResources(LOGGER_RESOURCE);
-        } catch (IOException e) {
-            logger.fatal("Unable to locate " + LOGGER_RESOURCE, e);
+        if (factoryClass != null) {
+            try {
+                Class<?> clazz = cl.loadClass(factoryClass);
+                if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
+                    factory = (LoggerContextFactory) clazz.newInstance();
+                }
+            } catch (ClassNotFoundException cnfe) {
+                logger.error("Unable to locate configured LoggerContextFactory {}", factoryClass);
+            } catch (Exception ex) {
+                logger.error("Unable to create configured LoggerContextFactory {}", factoryClass, ex);
+            }
         }
 
-        if (enumResources != null) {
-            while (enumResources.hasMoreElements()) {
-                Properties props = new Properties();
-                URL url = enumResources.nextElement();
-                try {
-                    props.loadFromXML(url.openStream());
-                } catch (IOException ioe) {
-                    logger.error("Unable to read " + url.toString(), ioe);
-                }
-                if (!validVersion(props.getProperty(API_VERSION))) {
-                    continue;
-                }
-                String className = props.getProperty(LOGGER_CONTEXT_FACTORY);
-                if (className != null) {
+        if (factory == null) {
+            SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>();
+
+            Enumeration<URL> enumResources = null;
+            try {
+                enumResources = cl.getResources(LOGGER_RESOURCE);
+            } catch (IOException e) {
+                logger.fatal("Unable to locate " + LOGGER_RESOURCE, e);
+            }
+
+            if (enumResources != null) {
+                while (enumResources.hasMoreElements()) {
+                    Properties props = new Properties();
+                    URL url = enumResources.nextElement();
                     try {
-                        Class<?> clazz = cl.loadClass(className);
-                        if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
-                            factories.add((LoggerContextFactory) clazz.newInstance());
-                        } else {
-                            logger.error(className + " does not implement " + LoggerContextFactory.class.getName());
+                        props.loadFromXML(url.openStream());
+                    } catch (IOException ioe) {
+                        logger.error("Unable to read " + url.toString(), ioe);
+                    }
+                    if (!validVersion(props.getProperty(API_VERSION))) {
+                        continue;
+                    }
+                    String weight = props.getProperty(FACTORY_PRIORITY);
+                    Integer priority = weight == null ? -1 : Integer.valueOf(weight);
+                    String className = props.getProperty(LOGGER_CONTEXT_FACTORY);
+                    if (className != null) {
+                        try {
+                            Class<?> clazz = cl.loadClass(className);
+                            if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
+                                factories.put(priority, (LoggerContextFactory) clazz.newInstance());
+                            } else {
+                                logger.error(className + " does not implement " + LoggerContextFactory.class.getName());
+                            }
+                        } catch (ClassNotFoundException cnfe) {
+                            logger.error("Unable to locate class " + className + " specified in " + url.toString(),
+                                cnfe);
+                        } catch (IllegalAccessException iae) {
+                            logger.error("Unable to create class " + className + " specified in " + url.toString(),
+                                iae);
+                        } catch (Exception e) {
+                            logger.error("Unable to create class " + className + " specified in " + url.toString(), e);
+                            e.printStackTrace();
                         }
-                    } catch (ClassNotFoundException cnfe) {
-                        logger.error("Unable to locate class " + className + " specified in " + url.toString(), cnfe);
-                    } catch (IllegalAccessException iae) {
-                        logger.error("Unable to create class " + className + " specified in " + url.toString(), iae);
-                    } catch (Exception e) {
-                        logger.error("Unable to create class " + className + " specified in " + url.toString(), e);
-                        e.printStackTrace();
                     }
                 }
-            }
-            if (factories.size() != 1) {
-                logger.fatal("Unable to locate a logging implementation");
+                if (factories.size() == 0) {
+                    logger.error("Unable to locate a logging implementation, using SimpleLogger");
+                    factory = new SimpleLoggerContextFactory();
+                } else {
+                    StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
+                    for (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 {
-                factory = factories.get(0);
+                logger.error("Unable to locate a logging implementation, using SimpleLogger");
+                factory = new SimpleLoggerContextFactory();
             }
-        } else {
-            logger.fatal("Unable to locate a logging implementation");
         }
     }
 
@@ -238,9 +275,6 @@ public class LogManager {
                 }
             );
         }
-        if (cl != null && cl.getParent() != null) {
-
-        }
         if (cl == null) {
             cl = LogManager.class.getClassLoader();
         }

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java?rev=1399852&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLogger.java Thu Oct 18 20:54:28 2012
@@ -0,0 +1,168 @@
+/*
+ * 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.simple;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.spi.AbstractLogger;
+import org.apache.logging.log4j.util.PropsUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ *  This is the default logger that is used when no suitable logging implementation is available.
+ *
+ */
+public class SimpleLogger extends AbstractLogger {
+
+    /**
+     * Used to format times.
+     * <p>
+     * Note that DateFormat is not Thread-safe.
+     */
+    private DateFormat dateFormatter = null;
+
+    private Level level;
+
+    private boolean showDateTime;
+
+    private boolean showContextMap;
+
+    private PrintStream stream;
+
+    private String logName;
+
+
+    public SimpleLogger(String name, Level defaultLevel, boolean showLogName, boolean showShortLogName,
+                        boolean showDateTime, boolean showContextMap, String dateTimeFormat,
+                        PropsUtil props, PrintStream stream) {
+        super(name);
+        String lvl = props.getStringProperty(SimpleLoggerContext.SYSTEM_PREFIX + name + ".level");
+        this.level = Level.toLevel(lvl, defaultLevel);
+        if (showShortLogName) {
+            int index = name.lastIndexOf(".");
+            if (index > 0 && index < name.length()) {
+                this.logName = name.substring(index + 1);
+            } else {
+                this.logName = name;
+            }
+        } else if (showLogName) {
+            this.logName = name;
+        }
+        this.showDateTime = showDateTime;
+        this.showContextMap = showContextMap;
+        this.stream = stream;
+
+        if (showDateTime) {
+            try {
+                this.dateFormatter = new SimpleDateFormat(dateTimeFormat);
+            } catch(IllegalArgumentException e) {
+                // If the format pattern is invalid - use the default format
+                this.dateFormatter = new SimpleDateFormat(SimpleLoggerContext.DEFAULT_DATE_TIME_FORMAT);
+            }
+        }
+    }
+
+    public void setStream(PrintStream stream) {
+        this.stream = stream;
+    }
+
+    public void setLevel(Level level) {
+        if (level != null) {
+            this.level = level;
+        }
+    }
+
+    @Override
+    public void log(Marker marker, String fqcn, Level level, Message msg, Throwable throwable) {
+        StringBuilder sb = new StringBuilder();
+        // Append date-time if so configured
+        if(showDateTime) {
+            Date now = new Date();
+            String dateText;
+            synchronized(dateFormatter) {
+                dateText = dateFormatter.format(now);
+            }
+            sb.append(dateText);
+            sb.append(" ");
+        }
+
+        sb.append(level.toString());
+        sb.append(" ");
+        if (logName != null && logName.length() > 0) {
+            sb.append(logName);
+            sb.append(" ");
+        }
+        sb.append(msg.getFormattedMessage());
+        if (showContextMap) {
+            Map<String, String> mdc = ThreadContext.getContext();
+            if (mdc.size() > 0) {
+                sb.append(" ");
+                sb.append(mdc.toString());
+                sb.append(" ");
+            }
+        }
+        Object[] params = msg.getParameters();
+        Throwable t;
+        if (throwable == null && params != null && params[params.length -1] instanceof Throwable ) {
+            t = (Throwable) params[params.length - 1];
+        } else {
+            t = throwable;
+        }
+        if (t != null) {
+            sb.append(" ");
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            t.printStackTrace(new PrintStream(baos));
+            sb.append(baos.toString());
+        }
+        stream.println(sb.toString());
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg) {
+        return this.level.intLevel() >= level.intLevel();
+    }
+
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Throwable t) {
+        return this.level.intLevel() >= level.intLevel();
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, String msg, Object... p1) {
+        return this.level.intLevel() >= level.intLevel();
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Object msg, Throwable t) {
+        return this.level.intLevel() >= level.intLevel();
+    }
+
+    @Override
+    protected boolean isEnabled(Level level, Marker marker, Message msg, Throwable t) {
+        return this.level.intLevel() >= level.intLevel();
+    }
+
+}

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java?rev=1399852&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java Thu Oct 18 20:54:28 2012
@@ -0,0 +1,115 @@
+/*
+ * 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.simple;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.PropsUtil;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ *
+ */
+public class SimpleLoggerContext implements LoggerContext {
+
+    /** The default format to use when formating dates */
+    protected static final String DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss:SSS zzz";
+
+    /** All system properties used by <code>SimpleLog</code> start with this */
+    protected static final String SYSTEM_PREFIX = "org.apache.logging.log4j.simplelog.";
+
+    /** Properties loaded from simplelog.properties */
+    private Properties simpleLogProps = new Properties();
+
+    private PropsUtil props;
+
+    /** Include the instance name in the log message? */
+    private final boolean showLogName;
+    /** Include the short name ( last component ) of the logger in the log
+     *  message. Defaults to true - otherwise we'll be lost in a flood of
+     *  messages without knowing who sends them.
+     */
+    private final boolean showShortName;
+    /** Include the current time in the log message */
+    private final boolean showDateTime;
+    /** Include the ThreadContextMap in the log message */
+    private final boolean showContextMap;
+    /** The date and time format to use in the log message */
+    private final String dateTimeFormat;
+
+    private final Level defaultLevel;
+
+    private final PrintStream stream;
+
+    public SimpleLoggerContext() {
+        props = new PropsUtil("log4j2.simplelog.properties");
+
+        showContextMap = props.getBooleanProperty(SYSTEM_PREFIX + "showContextMap", false);
+        showLogName = props.getBooleanProperty(SYSTEM_PREFIX + "showlogname", false);
+        showShortName = props.getBooleanProperty(SYSTEM_PREFIX + "showShortLogname", true);
+        showDateTime = props.getBooleanProperty(SYSTEM_PREFIX + "showdatetime", false);
+        String lvl = props.getStringProperty(SYSTEM_PREFIX + "level");
+        defaultLevel = Level.toLevel(lvl, Level.ERROR);
+
+        dateTimeFormat = showDateTime ? props.getStringProperty(SimpleLoggerContext.SYSTEM_PREFIX + "dateTimeFormat",
+            DEFAULT_DATE_TIME_FORMAT) : null;
+
+        String fileName = props.getStringProperty(SYSTEM_PREFIX + "logFile", "system.err");
+        PrintStream ps;
+        if ("system.err".equalsIgnoreCase(fileName)) {
+            ps = System.err;
+        } else if ("system.out".equalsIgnoreCase(fileName)) {
+            ps = System.out;
+        } else {
+            try {
+                FileOutputStream os = new FileOutputStream(fileName);
+                ps = new PrintStream(os);
+            } catch (FileNotFoundException fnfe) {
+                ps = System.err;
+            }
+        }
+        this.stream = ps;
+    }
+
+    private ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<String, Logger>();
+
+    public Logger getLogger(String name) {
+        if (loggers.containsKey(name)) {
+            return loggers.get(name);
+        }
+
+        loggers.putIfAbsent(name, new SimpleLogger(name, defaultLevel, showLogName, showShortName, showDateTime,
+            showContextMap, dateTimeFormat, props, stream));
+        return loggers.get(name);
+    }
+
+    public boolean hasLogger(String name) {
+        return false;
+    }
+
+    public Object getExternalContext() {
+        return null;
+    }
+}

Added: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java?rev=1399852&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContextFactory.java Thu Oct 18 20:54:28 2012
@@ -0,0 +1,32 @@
+/*
+ * 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.simple;
+
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+
+/**
+ *
+ */
+public class SimpleLoggerContextFactory implements LoggerContextFactory {
+
+    private static LoggerContext ctx = new SimpleLoggerContext();
+
+    public LoggerContext getContext(String FQCN, ClassLoader loader, boolean currentContext) {
+        return ctx;
+    }
+}

Modified: logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java (original)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java Thu Oct 18 20:54:28 2012
@@ -16,11 +16,13 @@
  */
 package org.apache.logging.log4j.status;
 
+import org.apache.logging.log4j.simple.SimpleLogger;
+import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
 import org.apache.logging.log4j.spi.AbstractLogger;
 import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.util.PropsUtil;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -50,7 +52,7 @@ public final class StatusLogger extends 
 
     private static final StatusLogger statusLogger = new StatusLogger();
 
-    private Logger logger;
+    private final SimpleLogger logger;
 
     private final CopyOnWriteArrayList<StatusListener> listeners = new CopyOnWriteArrayList<StatusListener>();
     private final ReentrantReadWriteLock listenersLock = new ReentrantReadWriteLock();
@@ -59,6 +61,8 @@ public final class StatusLogger extends 
     private final ReentrantLock msgLock = new ReentrantLock();
 
     private StatusLogger() {
+        PropsUtil props = new PropsUtil("log4j2.StatusLogger.properties");
+        this.logger = new SimpleLogger("StatusLogger", Level.ERROR, false, true, false, false, "", props, System.err);
     }
 
     /**
@@ -69,6 +73,10 @@ public final class StatusLogger extends 
         return statusLogger;
     }
 
+    public void setLevel(Level level) {
+        logger.setLevel(level);
+    }
+
     /**
      * Register a new listener.
      * @param listener The StatusListener to register.
@@ -158,8 +166,12 @@ public final class StatusLogger extends 
         } finally {
             msgLock.unlock();
         }
-        for (StatusListener listener : listeners) {
-            listener.log(data);
+        if (listeners.size() > 0) {
+            for (StatusListener listener : listeners) {
+                listener.log(data);
+            }
+        } else {
+            logger.log(marker, fqcn, level, msg, t);
         }
     }
 
@@ -208,7 +220,7 @@ public final class StatusLogger extends 
     }
 
     protected boolean isEnabled(Level level, Marker marker) {
-        if (logger == null) {
+        if (listeners.size() > 0) {
             return true;
         }
         switch (level) {

Added: 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=1399852&view=auto
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java (added)
+++ logging/log4j/log4j2/trunk/api/src/main/java/org/apache/logging/log4j/util/PropsUtil.java Thu Oct 18 20:54:28 2012
@@ -0,0 +1,86 @@
+/*
+ * 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 java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Utility class to help with accessing System Properties.
+ */
+public class PropsUtil {
+
+    private Properties props;
+
+    public PropsUtil(Properties props) {
+        this.props = props;
+    }
+
+    public PropsUtil(String propsLocn) {
+        this.props = new Properties();
+        ClassLoader loader = findClassLoader();
+        InputStream in = loader.getResourceAsStream(propsLocn);
+        if (null != in) {
+            try {
+                this.props.load(in);
+                in.close();
+            } catch(java.io.IOException e) {
+                // ignored
+            }
+        }
+    }
+
+    public String getStringProperty(String name) {
+        String prop = null;
+        try {
+            prop = System.getProperty(name);
+        } catch (SecurityException e) {
+            // Ignore
+        }
+        return (prop == null) ? props.getProperty(name) : prop;
+    }
+
+    public String getStringProperty(String name, String defaultValue) {
+        String prop = getStringProperty(name);
+        return (prop == null) ? defaultValue : prop;
+    }
+
+    public boolean getBooleanProperty(String name, boolean defaultValue) {
+        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;
+    }
+}

Modified: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/EventLoggerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/EventLoggerTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/EventLoggerTest.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/EventLoggerTest.java Thu Oct 18 20:54:28 2012
@@ -31,7 +31,7 @@ import static org.junit.Assert.assertTru
  */
 public class EventLoggerTest {
 
-    SimpleLogger logger = (SimpleLogger) LogManager.getLogger("EventLogger");
+    TestLogger logger = (TestLogger) LogManager.getLogger("EventLogger");
     List<String> results = logger.getEntries();
 
     @Before

Modified: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/LoggerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/LoggerTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/LoggerTest.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/LoggerTest.java Thu Oct 18 20:54:28 2012
@@ -34,7 +34,7 @@ import static org.junit.Assert.assertEqu
  */
 public class LoggerTest {
 
-    SimpleLogger logger = (SimpleLogger) LogManager.getLogger("LoggerTest");
+    TestLogger logger = (TestLogger) LogManager.getLogger("LoggerTest");
     List<String> results = logger.getEntries();
 
     @Before

Copied: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLogger.java (from r1397892, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLogger.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLogger.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLogger.java&p1=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLogger.java&r1=1397892&r2=1399852&rev=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLogger.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLogger.java Thu Oct 18 20:54:28 2012
@@ -28,7 +28,7 @@ import java.util.Map;
 /**
  *
  */
-public class SimpleLogger extends AbstractLogger {
+public class TestLogger extends AbstractLogger {
     private List<String> array = new ArrayList<String>();
 
     public List<String> getEntries() {

Copied: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java (from r1397892, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java&p1=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java&r1=1397892&r2=1399852&rev=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContext.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContext.java Thu Oct 18 20:54:28 2012
@@ -21,8 +21,8 @@ import org.apache.logging.log4j.spi.Logg
 /**
  *
  */
-public class SimpleLoggerContext implements LoggerContext {
-    private Logger logger = new SimpleLogger();
+public class TestLoggerContext implements LoggerContext {
+    private Logger logger = new TestLogger();
 
     public Logger getLogger(String name) {
         return logger;

Copied: logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java (from r1397892, logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContextFactory.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java?p2=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java&p1=logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContextFactory.java&r1=1397892&r2=1399852&rev=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/SimpleLoggerContextFactory.java (original)
+++ logging/log4j/log4j2/trunk/api/src/test/java/org/apache/logging/log4j/TestLoggerContextFactory.java Thu Oct 18 20:54:28 2012
@@ -22,9 +22,9 @@ import org.apache.logging.log4j.spi.Logg
 /**
  *
  */
-public class SimpleLoggerContextFactory implements LoggerContextFactory {
+public class TestLoggerContextFactory implements LoggerContextFactory {
 
-    private static LoggerContext ctx = new SimpleLoggerContext();
+    private static LoggerContext ctx = new TestLoggerContext();
 
     public LoggerContext getContext(String FQCN, ClassLoader loader, boolean currentContext) {
         return ctx;

Modified: logging/log4j/log4j2/trunk/api/src/test/resources/META-INF/log4j-provider.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/api/src/test/resources/META-INF/log4j-provider.xml?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/api/src/test/resources/META-INF/log4j-provider.xml (original)
+++ logging/log4j/log4j2/trunk/api/src/test/resources/META-INF/log4j-provider.xml Thu Oct 18 20:54:28 2012
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
 <properties>
-    <entry key="LoggerContextFactory">org.apache.logging.log4j.SimpleLoggerContextFactory</entry>
-    <entry key="Log4jAPIVersion">1.99.0</entry>
+    <entry key="LoggerContextFactory">org.apache.logging.log4j.TestLoggerContextFactory</entry>
+    <entry key="Log4jAPIVersion">2.0.0</entry>
+    <entry key="FactoryPriority">0</entry>
 </properties>
\ No newline at end of file

Modified: logging/log4j/log4j2/trunk/core/src/main/resources/META-INF/log4j-provider.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/resources/META-INF/log4j-provider.xml?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/resources/META-INF/log4j-provider.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/main/resources/META-INF/log4j-provider.xml Thu Oct 18 20:54:28 2012
@@ -19,5 +19,6 @@
 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
 <properties>
     <entry key="LoggerContextFactory">org.apache.logging.log4j.core.impl.Log4jContextFactory</entry>
-    <entry key="Log4jAPIVersion">1.99.0</entry>
+    <entry key="Log4jAPIVersion">2.0.0</entry>
+    <entry key="FactoryPriority">10</entry>
 </properties>
\ No newline at end of file

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/filter/RegexFilterTest.java Thu Oct 18 20:54:28 2012
@@ -21,6 +21,8 @@ import org.apache.logging.log4j.core.Fil
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import static org.junit.Assert.assertTrue;
@@ -30,6 +32,10 @@ import static org.junit.Assert.assertNul
  *
  */
 public class RegexFilterTest {
+    @BeforeClass
+    public static void before() {
+        StatusLogger.getLogger().setLevel(Level.OFF);
+    }
 
     @Test
     public void testThresholds() {

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/layout/RFC5424LayoutTest.java Thu Oct 18 20:54:28 2012
@@ -23,6 +23,7 @@ import org.apache.logging.log4j.ThreadCo
 import org.apache.logging.log4j.core.BasicConfigurationFactory;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.test.appender.ListAppender;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.message.StructuredDataMessage;
@@ -54,6 +55,7 @@ public class RFC5424LayoutTest {
 
     @BeforeClass
     public static void setupClass() {
+        StatusLogger.getLogger().setLevel(Level.OFF);
         ConfigurationFactory.setConfigurationFactory(cf);
         LoggerContext ctx = (LoggerContext) LogManager.getContext();
         ctx.reconfigure();

Modified: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java Thu Oct 18 20:54:28 2012
@@ -96,7 +96,7 @@ public class SocketServerTest {
             "Test", null, null, null, socketFilter);
         appender.start();
         ListAppender listApp = new ListAppender("Events", serverFilter, null, false, false);
-        appender.start();
+        listApp.start();
         PatternLayout layout = PatternLayout.createLayout("%m %ex%n", null, null, null);
         ConsoleAppender console = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "true");
         Logger serverLogger = ctx.getLogger(SocketServer.class.getName());

Modified: logging/log4j/log4j2/trunk/flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java (original)
+++ logging/log4j/log4j2/trunk/flume-ng/src/test/java/org/apache/logging/log4j/flume/appender/FlumeAppenderTest.java Thu Oct 18 20:54:28 2012
@@ -35,6 +35,7 @@ import org.apache.logging.log4j.LogManag
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.status.StatusLogger;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -68,6 +69,7 @@ public class FlumeAppenderTest {
 
     @BeforeClass
     public static void setupClass() {
+        StatusLogger.getLogger().setLevel(Level.OFF);
         ctx = (LoggerContext) LogManager.getContext();
     }
 

Modified: logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/CategoryTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/CategoryTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/CategoryTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/CategoryTest.java Thu Oct 18 20:54:28 2012
@@ -25,7 +25,9 @@ import org.apache.logging.log4j.message.
 import org.apache.logging.log4j.test.appender.ListAppender;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.junit.After;
 import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -48,10 +50,11 @@ public class CategoryTest {
 
     private static final String LINE_SEP = System.getProperty("line.separator");
 
-    private ListAppender appender = new ListAppender("List");
+    private static ListAppender appender = new ListAppender("List");
 
     @BeforeClass
     public static void setupClass() {
+        appender.start();
         ConfigurationFactory.setConfigurationFactory(cf);
         LoggerContext ctx = (LoggerContext) org.apache.logging.log4j.LogManager.getContext();
         ctx.reconfigure();
@@ -60,6 +63,7 @@ public class CategoryTest {
     @AfterClass
     public static void cleanupClass() {
         ConfigurationFactory.removeConfigurationFactory(cf);
+        appender.stop();
     }
 
     /**

Modified: logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/LoggerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/LoggerTest.java?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/LoggerTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j12-api/src/test/java/org/apache/log4j/LoggerTest.java Thu Oct 18 20:54:28 2012
@@ -127,6 +127,7 @@ public class LoggerTest {
         Logger a = Logger.getLogger("a");
         Logger ab = Logger.getLogger("a.b");
         CountingAppender ca = new CountingAppender();
+        ca.start();
         a.getLogger().addAppender(ca);
 
         assertEquals(ca.counter, 0);
@@ -138,6 +139,8 @@ public class LoggerTest {
         assertEquals(ca.counter, 3);
         ab.error(MSG);
         assertEquals(ca.counter, 4);
+        ca.stop();
+        a.getLogger().removeAppender(ca);
     }
 
     /**
@@ -152,7 +155,9 @@ public class LoggerTest {
         Logger x = Logger.getLogger("x");
 
         CountingAppender ca1 = new CountingAppender();
+        ca1.start();
         CountingAppender ca2 = new CountingAppender();
+        ca2.start();
 
         a.getLogger().addAppender(ca1);
         abc.getLogger().addAppender(ca2);
@@ -171,6 +176,10 @@ public class LoggerTest {
         x.debug(MSG);
         assertEquals(ca1.counter, 2);
         assertEquals(ca2.counter, 1);
+        ca1.stop();
+        ca2.stop();
+        a.getLogger().removeAppender(ca1);
+        abc.getLogger().removeAppender(ca2);
     }
 
     /**
@@ -186,8 +195,11 @@ public class LoggerTest {
         Logger x = Logger.getLogger("x");
 
         CountingAppender caRoot = new CountingAppender();
+        caRoot.start();
         CountingAppender caA = new CountingAppender();
+        caA.start();
         CountingAppender caABC = new CountingAppender();
+        caABC.start();
 
         root.getLogger().addAppender(caRoot);
         a.getLogger().addAppender(caA);
@@ -214,6 +226,12 @@ public class LoggerTest {
         assertEquals(caRoot.counter, 1);
         assertEquals(caA.counter, 1);
         assertEquals(caABC.counter, 1);
+        caRoot.stop();
+        caA.stop();
+        caABC.stop();
+        root.getLogger().removeAppender(caRoot);
+        a.getLogger().removeAppender(caA);
+        abc.getLogger().removeAppender(caABC);
     }
 
     /* Don't support getLoggerRepository
@@ -391,6 +409,8 @@ public class LoggerTest {
         LogEvent event = (LogEvent) msgs.get(0);
         assertEquals(org.apache.logging.log4j.Level.TRACE, event.getLevel());
         assertEquals("Message 1", event.getMessage().getFormat());
+        appender.stop();
+        root.getLogger().removeAppender(appender);
     }
 
     /**
@@ -399,6 +419,7 @@ public class LoggerTest {
     @Test
     public void testTraceWithException() {
         ListAppender appender = new ListAppender("List");
+        appender.start();
         Logger root = Logger.getRootLogger();
         root.getLogger().addAppender(appender);
         root.setLevel(Level.INFO);
@@ -416,6 +437,8 @@ public class LoggerTest {
         LogEvent event = msgs.get(0);
         assertEquals(org.apache.logging.log4j.Level.TRACE, event.getLevel());
         assertEquals("Message 1", event.getMessage().getFormattedMessage());
+        appender.stop();
+        root.getLogger().removeAppender(appender);
     }
 
     /**
@@ -424,6 +447,7 @@ public class LoggerTest {
     @Test
     public void testIsTraceEnabled() {
         ListAppender appender = new ListAppender("List");
+        appender.start();
         Logger root = Logger.getRootLogger();
         root.getLogger().addAppender(appender);
         root.setLevel(Level.INFO);
@@ -433,12 +457,15 @@ public class LoggerTest {
 
         assertTrue(tracer.isTraceEnabled());
         assertFalse(root.isTraceEnabled());
+        appender.stop();
+        root.getLogger().removeAppender(appender);
     }
 
     @Test
     public void testLog() {
         PatternLayout layout = PatternLayout.createLayout("%d %C %L %m", null, null, null);
         ListAppender appender = new ListAppender("List", null, layout, false, false);
+        appender.start();
         Logger root = Logger.getRootLogger();
         root.getLogger().addAppender(appender);
         root.setLevel(Level.INFO);
@@ -450,6 +477,8 @@ public class LoggerTest {
         assertTrue("Incorrect number of messages", msgs.size() == 3);
         String msg = msgs.get(0);
         assertTrue("Message contains incorrect class name: " + msg, msg.contains(LoggerTest.class.getName()));
+        appender.stop();
+        root.getLogger().removeAppender(appender);
     }
 
     private static class MyLogger {

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Thu Oct 18 20:54:28 2012
@@ -23,6 +23,10 @@
 
   <body>
     <release version="2.0-beta3" date="TBD" description= "Bug fixes and enhancements">
+      <action dev="rgoers" type="fix">
+        Avoid NPE when duplicate LoggerContextFactorys are present. Allow factories to specify a weight to allow
+        real implementations to outrank test implementations. Provide a simple default LoggerContextFactory.
+      </action>
       <action issue="LOG4J2-97" dev="rgoers" type="fix">
         Added several missing classes and methods for Log4j 1.x compatibility.
       </action>

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml?rev=1399852&r1=1399851&r2=1399852&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml Thu Oct 18 20:54:28 2012
@@ -34,10 +34,25 @@
               locates a LoggerContextFactory by locating all instances of META-INF/log4j-provider.xml, a
               file that conforms to the java.util.Properties DTD, and then inspecting each to verify that it
               specifies a value for the "Log4jAPIVersion" property that conforms to the version required by the
-              LogManager. If more than one valid implementation is located an exception will be thrown.
+              LogManager. If more than one valid implementation is located the value for "FactoryPriority" will
+              be used to identify the factory with the highest priority.
               Finally, the value of the "LoggerContextFactory" property will be used to locate the
               LoggerContextFactory. In Log4j 2 this is provided by Log4jContextFactory.
             </p>
+            <p>
+              Applications may change the LoggerContextFactory that will be used by
+              <ol>
+                <li>Implementing a new LoggerContextFactory and creating a log4j-provider.xml to reference it making
+                  sure that it has the highest priority.</li>
+                <li>Create a new log4j-provider.xml and configure it with the desired LoggerContextFactory making
+                  sure that it has the highest priority.</li>
+                <li>Setting the system property "log4j2.LoggerContextFactory" to the name of the LoggerContextFactory
+                  class to use.</li>
+                <li>Setting the property "log4j2.LoggerContextFactory" in a properties file named
+                  "log4j2.LogManager.properties" to the name of the LoggerContextFactory class to use. The properties
+                  file must be on the classpath.</li>
+              </ol>
+            </p>
           </subsection>
           <subsection name="ContextSelector">
             <p>