Merge pull request #68 from mbien/logger_renovations

Logger Renovations. Looks good! thanks @mbien 
diff --git a/app/pom.xml b/app/pom.xml
index 143041a..4f9f2c3 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -47,15 +47,14 @@
         <commons-codec.version>1.14</commons-codec.version>
         <eclipse-link.version>2.7.7</eclipse-link.version>
         <guice.version>4.2.3</guice.version>
-        <log4j.version>1.2.17</log4j.version>
-        <log4j2.version>2.10.0</log4j2.version>
+        <log4j2.version>2.12.1</log4j2.version>
         <lucene.version>8.5.1</lucene.version>
         <oauth-core.version>20100527</oauth-core.version>
         <maven-war.version>3.2.3</maven-war.version>
         <maven-surefire.version>2.17</maven-surefire.version>
         <maven-antrun.version>1.0b3</maven-antrun.version>
         <rome.version>1.13.1</rome.version>
-        <slf4j.version>1.7.26</slf4j.version>
+        <slf4j.version>1.7.30</slf4j.version>
         <spring.version>5.2.7.RELEASE</spring.version>
         <spring.security.version>5.3.3.RELEASE</spring.security.version>
         <struts.version>2.5.22</struts.version>
@@ -128,6 +127,13 @@
             <artifactId>org.eclipse.persistence.jpa</artifactId>
             <version>${eclipse-link.version}</version>
         </dependency>
+        
+        <!-- small dependency containing slf4j bridge for eclipselink -->
+        <dependency>
+            <groupId>org.eclipse.persistence</groupId>
+            <artifactId>org.eclipse.persistence.extension</artifactId>
+            <version>${eclipse-link.version}</version>
+        </dependency>
 
         <!-- Alternative testing with Hibernate (used by default with JBoss)
              Important: set hibernate.transaction.factory_class=org.hibernate.transaction.JDBCTransactionFactory
@@ -296,15 +302,26 @@
             <version>${lucene.version}</version>
         </dependency>
 
-        <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-            <version>${log4j.version}</version>
+        <!-- slf4j implementing the apache commons-logging interfaces -->
+        <!-- note: commons-logging needs to be excluded in all dependencies transitive depending on it.
+        See 2006 RFE https://issues.apache.org/jira/browse/MNG-1977 for maven's missing feature of global exclusions -->
+        <dependency> 
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+        
+        <!-- slf4j implementing java.util.logging interfaces (needed for WebJars, ..) -->
+        <dependency> 
+            <groupId>org.slf4j</groupId>
+            <artifactId>jul-to-slf4j</artifactId>
+            <version>${slf4j.version}</version>
         </dependency>
 
+        <!-- the actual logging impl below slf4j: log4j2 -->
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
-            <artifactId>log4j-core</artifactId>
+            <artifactId>log4j-slf4j-impl</artifactId>
             <version>${log4j2.version}</version>
         </dependency>
 
@@ -313,18 +330,36 @@
             <artifactId>commons-validator</artifactId>
             <version>${commons-validator.version}</version>
             <type>jar</type>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
             <groupId>commons-beanutils</groupId>
             <artifactId>commons-beanutils</artifactId>
             <version>${commons-beanutils.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
             <groupId>commons-httpclient</groupId>
             <artifactId>commons-httpclient</artifactId>
             <version>${commons-httpclient.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
@@ -360,6 +395,10 @@
                     <groupId>javax.servlet</groupId>
                     <artifactId>servlet-api</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
 
@@ -422,6 +461,10 @@
                     <groupId>com.google.inject</groupId>
                     <artifactId>guice</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
 
@@ -460,13 +503,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-            <scope>runtime</scope>
-        </dependency>
-
-        <dependency>
             <groupId>com.jgeppert.struts2.bootstrap</groupId>
             <artifactId>struts2-bootstrap-plugin</artifactId>
             <version>2.5.2</version>
diff --git a/app/src/main/java/org/apache/roller/weblogger/config/WebloggerConfig.java b/app/src/main/java/org/apache/roller/weblogger/config/WebloggerConfig.java
index 1c76ce8..c652c59 100644
--- a/app/src/main/java/org/apache/roller/weblogger/config/WebloggerConfig.java
+++ b/app/src/main/java/org/apache/roller/weblogger/config/WebloggerConfig.java
@@ -25,7 +25,6 @@
 import java.util.Properties;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.log4j.PropertyConfigurator;
 import org.apache.roller.util.PropertyExpander;
 
 
@@ -34,15 +33,14 @@
  */
 public final class WebloggerConfig {
     
-    private static String default_config = "/org/apache/roller/weblogger/config/roller.properties";
-    private static String custom_config = "/roller-custom.properties";
-    private static String junit_config = "/roller-junit.properties";
-    private static String custom_jvm_param = "roller.custom.config";
-    private static File custom_config_file = null;
+    private final static String default_config = "/org/apache/roller/weblogger/config/roller.properties";
+    private final static String custom_config = "/roller-custom.properties";
+    private final static String junit_config = "/roller-junit.properties";
+    private final static String custom_jvm_param = "roller.custom.config";
 
-    private static Properties config;
+    private final static Properties config;
 
-    private static Log log = LogFactory.getLog(WebloggerConfig.class);
+    private final static Log log;
     
 
     /*
@@ -58,48 +56,47 @@
             Class configClass = Class.forName("org.apache.roller.weblogger.config.WebloggerConfig");
 
             // first, lets load our default properties
-            InputStream is = configClass.getResourceAsStream(default_config);
-            config.load(is);
+            try (InputStream is = configClass.getResourceAsStream(default_config)) {
+                config.load(is);
+            }
             
             // first, see if we can find our junit testing config
-            is = configClass.getResourceAsStream(junit_config);
-            if (is != null) {
+            try (InputStream test = configClass.getResourceAsStream(junit_config)) {
+                
+                if (test != null) {
 
-                config.load(is);
-                System.out
-                        .println("Roller Weblogger: Successfully loaded junit properties file from classpath");
-                System.out.println("File path : "
-                        + configClass.getResource(junit_config).getFile());
+                    config.load(test);
+                    System.out.println("Roller Weblogger: Successfully loaded junit properties file from classpath");
+                    System.out.println("File path : " + configClass.getResource(junit_config).getFile());
 
-            } else {
-
-                // now, see if we can find our custom config
-                is = configClass.getResourceAsStream(custom_config);
-
-                if (is != null) {
-                    config.load(is);
-                    System.out
-                            .println("Roller Weblogger: Successfully loaded custom properties file from classpath");
-                    System.out.println("File path : "
-                            + configClass.getResource(custom_config).getFile());
                 } else {
-                    System.out
-                            .println("Roller Weblogger: No custom properties file found in classpath");
-                }
 
-                System.out
-                .println("(To run eclipse junit local tests see docs/testing/roller-junit.properties)");
+                    // now, see if we can find our custom config
+                    try(InputStream custom = configClass.getResourceAsStream(custom_config)) {
+
+                        if (custom != null) {
+                            config.load(custom);
+                            System.out.println("Roller Weblogger: Successfully loaded custom properties file from classpath");
+                            System.out.println("File path : " + configClass.getResource(custom_config).getFile());
+                        } else {
+                            System.out.println("Roller Weblogger: No custom properties file found in classpath");
+                        }
+
+                        System.out.println("(To run eclipse junit local tests see docs/testing/roller-junit.properties)");
+                    }
+                }
             }
 
             // finally, check for an external config file
             String env_file = System.getProperty(custom_jvm_param);
             if(env_file != null && env_file.length() > 0) {
-                custom_config_file = new File(env_file);
+                File custom_config_file = new File(env_file);
 
                 // make sure the file exists, then try and load it
-                if(custom_config_file != null && custom_config_file.exists()) {
-                    is = new FileInputStream(custom_config_file);
-                    config.load(is);
+                if(custom_config_file.exists()) {
+                    try(InputStream is = new FileInputStream(custom_config_file)) {
+                        config.load(is);
+                    }
                     System.out.println("Roller Weblogger: Successfully loaded custom properties from "+
                             custom_config_file.getAbsolutePath());
                 } else {
@@ -123,43 +120,60 @@
                     }
                 }
             }
-            
-            // initialize logging subsystem via WebloggerConfig
-            PropertyConfigurator.configure(WebloggerConfig.getPropertiesStartingWith("log4j."));
-            
-            // finally we can start logging...
-
-            // some debugging for those that want it
-            if(log.isDebugEnabled()) {
-                log.debug("WebloggerConfig looks like this ...");
-
-                String key = null;
-                Enumeration keys = config.keys();
-                while(keys.hasMoreElements()) {
-                    key = (String) keys.nextElement();
-                    log.debug(key+"="+config.getProperty(key));
-                }
-            }
 
         } catch (Exception e) {
             e.printStackTrace();
         }
 
+        // tell log4j2 to use the optionally specified config file instead of Roller's,
+        // but only if it hasn't already been set with -D at JVM startup.
+        String log4j2ConfigKey = "log4j.configurationFile";
+        String customLog4j2File = config.getProperty(log4j2ConfigKey);
+        if(customLog4j2File != null && !customLog4j2File.isBlank() && System.getProperty(log4j2ConfigKey) == null) {
+            System.setProperty(log4j2ConfigKey, customLog4j2File);
+        }
+        
+        // this bridges java.util.logging -> SLF4J which ends up being log4j2, probably.
+        org.slf4j.bridge.SLF4JBridgeHandler.removeHandlersForRootLogger();
+        org.slf4j.bridge.SLF4JBridgeHandler.install();
+        
+        // finally we can start logging...
+        log = LogFactory.getLog(WebloggerConfig.class);
+
+        // some debugging for those that want it
+        if(log.isDebugEnabled()) {
+            log.debug("WebloggerConfig looks like this ...");
+
+            String key;
+            Enumeration keys = config.keys();
+            while(keys.hasMoreElements()) {
+                key = (String) keys.nextElement();
+                log.debug(key+"="+config.getProperty(key));
+            }
+        }
+
     }
 
 
     // no, you may not instantiate this class :p
     private WebloggerConfig() {}
 
-
+    /**
+     * Loads Roller's configuration.
+     * Call this as early as possible in the lifecycle.
+     */
+    public static void init() {
+        // triggers static block
+    }
+    
     /**
      * Retrieve a property value
      * @param     key Name of the property
      * @return    String Value of property requested, null if not found
      */
     public static String getProperty(String key) {
-        log.debug("Fetching property ["+key+"="+config.getProperty(key)+"]");
         String value = config.getProperty(key);
+        log.debug("Fetching property ["+key+"="+value+"]");
         return value == null ? null : value.trim();
     }
     
@@ -170,8 +184,8 @@
      * @return    String Value of property requested or defaultValue
      */
     public static String getProperty(String key, String defaultValue) {
-        log.debug("Fetching property ["+key+"="+config.getProperty(key)+",defaultValue="+defaultValue+"]");
         String value = config.getProperty(key);
+        log.debug("Fetching property ["+key+"="+value+",defaultValue="+defaultValue+"]");
         if (value == null) {
             return defaultValue;
         }
@@ -227,21 +241,7 @@
      **/
     public static Enumeration keys() {
         return config.keys();
-    }
-    
-    
-    /**
-     * Get properties starting with a specified string.
-     */
-    public static Properties getPropertiesStartingWith(String startingWith) {
-        Properties props = new Properties();
-        for (Enumeration it = config.keys(); it.hasMoreElements();) {
-            String key = (String)it.nextElement();
-            props.put(key, config.get(key));
-        }
-        return props;
-    }
-    
+    } 
 
     /**
      * Set the "uploads.dir" property at runtime.
diff --git a/app/src/main/java/org/apache/roller/weblogger/ui/core/RollerSession.java b/app/src/main/java/org/apache/roller/weblogger/ui/core/RollerSession.java
index 79e4c5e..f107611 100644
--- a/app/src/main/java/org/apache/roller/weblogger/ui/core/RollerSession.java
+++ b/app/src/main/java/org/apache/roller/weblogger/ui/core/RollerSession.java
@@ -49,11 +49,16 @@
     // the id of the user represented by this session
     private String userName = null;
     
-    private static Log log = LogFactory.getLog(RollerSession.class);
+    private static final Log log;
     
     public static final String ROLLER_SESSION = "org.apache.roller.weblogger.rollersession";
     public static final String ERROR_MESSAGE   = "rollererror_message";
     public static final String STATUS_MESSAGE  = "rollerstatus_message";
+    
+    static{
+        WebloggerConfig.init(); // must be called before calls to logging APIs
+        log = LogFactory.getLog(RollerSession.class);
+    }
    
     /**
      * Get RollerSession from request (and add user if not already present).
diff --git a/app/src/main/resources/commons-logging.properties b/app/src/main/resources/commons-logging.properties
deleted file mode 100644
index c9e61d7..0000000
--- a/app/src/main/resources/commons-logging.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-#  contributor license agreements.  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.  For additional information regarding
-# copyright in this work, please see the NOTICE file in the top level
-# directory of this distribution.
-
-priority=1
-org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
-org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
diff --git a/app/src/main/resources/log4j.properties b/app/src/main/resources/log4j.properties
deleted file mode 100644
index 85691ec..0000000
--- a/app/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,39 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-#  contributor license agreements.  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.  For additional information regarding
-# copyright in this work, please see the NOTICE file in the top level
-# directory of this distribution.
-
-#
-# This is a bare bones Log4j setup that is present to catch any unexpected 
-# errors that occur before Roller is able to init the logging system defined
-# in Roller's built-in properties file and customized (e.g., logfile location
-# specified) via your roller-custom.properties override file.
-# See the Roller install guide for more details on the standard logfile
-# configuration.
-#
-# This configuration uses ConsoleAppender by default so it will work on
-# all installations.  If using Tomcat on *nix systems, or running Tomcat
-# as a Windows service, Console appender will write to the Tomcat
-# logs/catalina.out file.  See http://stackoverflow.com/a/7752389
-#
-# Otherwise, you may wish to customize below by specifying a log file
-# to write to.  However, such a file will usually remain empty as Roller's
-# standard logging is activated quite early in the startup process.
-#
-log4j.rootLogger=ERROR, roller-startup
-log4j.appender.roller-startup=org.apache.log4j.ConsoleAppender
-#log4j.appender.roller-startup=org.apache.log4j.DailyRollingFileAppender
-#log4j.appender.roller-startup.File=/path/to/a/roller-startup.log
-log4j.appender.roller-startup.layout=org.apache.log4j.PatternLayout
-log4j.appender.roller-startup.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %C{1}:%M - %m%n
diff --git a/app/src/main/resources/log4j2.xml b/app/src/main/resources/log4j2.xml
index 6fcf939..f7aba64 100644
--- a/app/src/main/resources/log4j2.xml
+++ b/app/src/main/resources/log4j2.xml
@@ -15,18 +15,77 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<Configuration status="WARN">
+
+<!-- to customize logging:
+    - copy this file into the servers classpath and tweak it
+    - set the log4j.configurationFile system property via roller-custom.properties or -D JVM arg -->
+
+<!--useful for testing: monitorInterval="10" -->
+<Configuration status="warn" name="Apache Roller" >
+    
+    <!-- folder is automatically created if needed -->
+    <properties>
+        <property name="logging.dir">logs</property>
+        <property name="logging.pattern">%-5p %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %m%n</property>
+    </properties>
+
     <Appenders>
-        <Console name="Console" target="SYSTEM_OUT">
-            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+
+        <!-- use as appenderRef if you like to log to console instead of files -->
+        <Console name="console" target="SYSTEM_OUT">
+            <PatternLayout pattern="${logging.pattern}"/>
         </Console>
+        
+        <RollingFile name="roller"
+                     fileName="${logging.dir}/roller.log" 
+                     filePattern="${logging.dir}/roller-%d{yyyy-MM-dd-HHmmss}.log.gz"
+                     ignoreExceptions="false">
+            <PatternLayout pattern="${logging.pattern}"/>
+            <Policies>
+                <OnStartupTriggeringPolicy />
+                <SizeBasedTriggeringPolicy size="8 MB"/>
+            </Policies>
+        </RollingFile>
+
+        <!-- if you use this log4j2 config in the server classpath.
+        <RollingFile name="server"
+                     fileName="${logging.dir}/server.log" 
+                     filePattern="${logging.dir}/server-%d{yyyy-MM-dd-HHmmss}.log.gz"
+                     ignoreExceptions="false">
+            <PatternLayout pattern="${logging.pattern}"/>
+            <Policies>
+                <SizeBasedTriggeringPolicy size="8 MB"/>
+            </Policies>
+            
+        </RollingFile>
+        -->
+        <!-- uses queue + thread for non blocking file IO -->
+        <Async name="asyncRoller">
+            <AppenderRef ref="roller"/>
+        </Async>
+        
     </Appenders>
+
     <Loggers>
-        <Root level="error">
-            <AppenderRef ref="Console"/>
+        
+        <!-- roller.log; everything not defined here will end up in server.log -->
+        <Logger name="org.apache.roller"       level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.apache.velocity"     level="error" additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.springframework"     level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.apache.struts2"      level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.openid4java"         level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.apache.tiles"        level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.eclipse.persistence" level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="com.opensymphony"        level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="com.rometools"           level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        <Logger name="org.webjars"             level="info"  additivity="false"> <AppenderRef ref="asyncRoller"/> </Logger>
+        
+        <!-- server.log catches everything that hasn't been logged yet-->
+        <Root level="info">
+        <!--<AppenderRef ref="server"/> -->
+            <AppenderRef ref="console"/>
         </Root>
-        <Logger name="org.apache.struts2" level="warn">
-            <AppenderRef ref="Console"/>
-        </Logger>
+        
     </Loggers>
-</Configuration>
+
+</Configuration>
\ No newline at end of file
diff --git a/app/src/main/resources/logback.xml b/app/src/main/resources/logback.xml
deleted file mode 100644
index 7d900d8..0000000
--- a/app/src/main/resources/logback.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<configuration>
-    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
-        <encoder>
-            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-            </pattern>
-        </encoder>
-    </appender>
-
-    <root level="INFO">
-        <appender-ref ref="STDOUT" />
-    </root>
-</configuration>
\ No newline at end of file
diff --git a/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties b/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties
index 5308ae7..c82086b 100644
--- a/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties
+++ b/app/src/main/resources/org/apache/roller/weblogger/config/roller.properties
@@ -54,7 +54,7 @@
 # -- Rendering system
 # -- Weblog ping system
 # -- Pluggable backend, page and editor plugins
-# -- Log4j logging settings
+# -- Log4j2 logging settings
 # -- Other settings
 # -- Experimental, deprecated and "undocumented" settings
 
@@ -563,39 +563,12 @@
 # The list of available editors is in rollerRuntimeConfigDefs.xml
 newweblog.editor=editor-summernote.jsp
 
-
 #-----------------------------------------------------------------------------
-# Log4j logging settings
+# Log4j2 logging settings
 #-----------------------------------------------------------------------------
-
-log4j.rootLogger=ERROR, roller
-
-log4j.appender.roller=org.apache.log4j.DailyRollingFileAppender
-log4j.appender.roller.File=${catalina.base}/logs/roller.log
-log4j.appender.roller.layout=org.apache.log4j.PatternLayout
-log4j.appender.roller.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss,SSS} %C{1}:%M - %m%n
-
-# Roller code. Options are: DEBUG, INFO, WARN, ERROR, FATAL
-log4j.logger.org.apache.roller=INFO
-log4j.logger.net.java.roller=ERROR
-
-# Roller dependent libraries
-log4j.logger.org.apache.struts2=ERROR
-log4j.logger.org.apache.tiles=ERROR
-log4j.logger.com.opensymphony.xwork2=ERROR
-log4j.logger.org.springframework=ERROR
-log4j.logger.org.springframework.security=ERROR
-log4j.logger.org.hibernate=ERROR
-
-# the struts2 file upload stuff has some overly verbose messaging
-log4j.logger.org.apache.struts2.interceptor.FileUploadInterceptor=ERROR
-
-# Velocity talks *way* too much, so set it to log only FATAL problems
-log4j.logger.org.apache.velocity=FATAL
-
-# Roller extras
-log4j.logger.com.ecyrd.jspwiki=ERROR
-log4j.logger.com.danga.MemCached=ERROR
+# Set this property to replace Roller's default log4j2 config with your own.
+# Feel free to use log4j2.xml located in roller.war/WEB-INF/classes as template
+#log4j.configurationFile=resources/log4j2.xml
 
 #-----------------------------------------------------------------------------
 # Other settings
@@ -643,6 +616,7 @@
 
 # EclipseLink JPA properties
 eclipselink.persistence-context.flush-mode=auto
+eclipselink.logging.logger=org.eclipse.persistence.logging.slf4j.SLF4JLogger
 
 # Lucene configurations
 lucene.analyzer.class=org.apache.lucene.analysis.standard.StandardAnalyzer
diff --git a/app/src/main/resources/struts.properties b/app/src/main/resources/struts.properties
index 976224a..fd2435c 100644
--- a/app/src/main/resources/struts.properties
+++ b/app/src/main/resources/struts.properties
@@ -17,6 +17,11 @@
 struts.enable.DynamicMethodInvocation=true
 struts.mapper.action.prefix.enabled=true
 
+# do not include jars for action scanning. This fixes an issue with log4j2 which
+# has several classes matching the convention pattern, some of which have optional dependencies.
+# Struts will cause NoClassDefFoundErrors when it inspects a class with unresolved dependencies via reflection.
+struts.convention.action.includeJars=false
+
 # prevent the damn s:url calls from including undesired query params by default
 struts.url.includeParams=none
 
diff --git a/app/src/test/resources/commons-logging.properties b/app/src/test/resources/commons-logging.properties
deleted file mode 100644
index 31a4df1..0000000
--- a/app/src/test/resources/commons-logging.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
-org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger
\ No newline at end of file
diff --git a/app/src/test/resources/log4j2.xml b/app/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..b2c3181
--- /dev/null
+++ b/app/src/test/resources/log4j2.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+
+<!-- logging config for tests -->
+<Configuration status="warn" name="Apache Roller" >
+    
+    <properties>
+        <property name="logging.dir">${project.build.directory}/logs</property>
+    </properties>
+
+    <Appenders>
+        
+        <RollingFile name="roller"
+                     fileName="${logging.dir}/roller.log" 
+                     filePattern="${logging.dir}/roller-%d{yyyy-MM-dd-HHmmss}.log.gz"
+                     ignoreExceptions="false">
+            <PatternLayout pattern="%-5p %d{yyyy-MM-dd HH:mm:ss} [%t] %C - %m%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy />
+                <SizeBasedTriggeringPolicy size="8 MB"/>
+            </Policies>
+        </RollingFile>
+
+        <RollingFile name="server"
+                     fileName="${logging.dir}/server.log" 
+                     filePattern="${logging.dir}/server-%d{yyyy-MM-dd-HHmmss}.log.gz"
+                     ignoreExceptions="false">
+            <PatternLayout pattern="%-5p %d{yyyy-MM-dd HH:mm:ss} [%t] %C - %m%n"/>
+            <Policies>
+                <SizeBasedTriggeringPolicy size="8 MB"/>
+            </Policies>
+            
+        </RollingFile>
+        
+    </Appenders>
+
+    <Loggers>
+        
+        <!-- roller.log; everything not defined here will end up in server.log -->
+        <Logger name="org.apache.roller"   level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.velocity" level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.springframework" level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.struts2"  level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.openid4java"     level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.tiles"    level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="com.opensymphony"    level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="com.rometools"       level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.webjars"         level="info"  additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        
+        <!-- 
+        <Logger name="org.apache.roller.planet.business.jpa.JPAPropertiesManagerImpl"    level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.roller.weblogger.business.jpa.JPAPropertiesManagerImpl" level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.roller.weblogger.business"                              level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+
+        <Logger name="org.apache.roller.planet.config.PlanetConfig"       level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.roller.weblogger.config.WebloggerConfig" level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+
+        <Logger name="org.apache.roller.weblogger.planet.tasks"     level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.roller.planet.business"            level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        <Logger name="org.apache.roller.weblogger.planet.business"  level="debug" additivity="false"> <AppenderRef ref="roller"/> </Logger>
+        -->
+        
+        <!-- server.log catches everything that hasn't been logged yet-->
+        <Root level="info">
+            <AppenderRef ref="server"/>
+        </Root>
+        
+    </Loggers>
+
+</Configuration>
\ No newline at end of file
diff --git a/app/src/test/resources/roller-custom.properties b/app/src/test/resources/roller-custom.properties
index dd6a580..59fed4f 100644
--- a/app/src/test/resources/roller-custom.properties
+++ b/app/src/test/resources/roller-custom.properties
@@ -42,22 +42,3 @@
 tasks.TestTask.startTime=immediate
 tasks.TestTask.interval=1800
 tasks.TestTask.leaseTime=300
-
-# logging
-log4j.rootLogger=INFO, roller
-log4j.appender.roller.File=${project.build.directory}/roller.log
-log4j.category.org.apache.roller=INFO
-log4j.category.net.java.roller=ERROR
-
-
-log4j.category.org.apache.struts=DEBUG
-#log4j.category.org.apache.roller.planet.business.jpa.JPAPropertiesManagerImpl=DEBUG
-#log4j.category.org.apache.roller.weblogger.business.jpa.JPAPropertiesManagerImpl=DEBUG
-#log4j.category.org.apache.roller.weblogger.business=DEBUG
-
-#log4j.category.org.apache.roller.planet.config.PlanetConfig=DEBUG
-#log4j.category.org.apache.roller.weblogger.config.WebloggerConfig=DEBUG
-
-#log4j.category.org.apache.roller.weblogger.planet.tasks=DEBUG
-#log4j.category.org.apache.roller.planet.business=DEBUG
-#log4j.category.org.apache.roller.weblogger.planet.business=DEBUG
diff --git a/app/src/test/resources/roller-jettyrun.properties b/app/src/test/resources/roller-jettyrun.properties
index 6b4c36e..7130f99 100644
--- a/app/src/test/resources/roller-jettyrun.properties
+++ b/app/src/test/resources/roller-jettyrun.properties
@@ -28,7 +28,6 @@
 search.index.dir          =${project.build.directory}/work/search-index
 uploads.dir               =${project.build.directory}/work/uploadsdir
 mediafiles.storage.dir    =${project.build.directory}/work/mediafiles
-log4j.appender.roller.File=${project.build.directory}/work/roller.log
 
 # don't auto migrate during tests
 uploads.migrate.auto=false
@@ -50,6 +49,3 @@
 cache.weblogpage.enabled=false
 cache.weblogfeed.enabled=false
 cache.planet.enabled=false
-
-# logging - you can set Log4J properties here
-#log4j.logger.org.apache.roller.weblogger.business=DEBUG