Author: rgoers
Date: Sun Nov 27 07:22:46 2011
New Revision: 1206675

URL: http://svn.apache.org/viewvc?rev=1206675&view=rev
Log:
Finish first draft of configuration documentation.

Added:
    
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppender2Test.java
      - copied, changed from r1204693, 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppenderTest.java
    
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing2.json
      - copied, changed from r1204693, 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing.json
Modified:
    
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java
    
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
    
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/lookup/MapLookup.java
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/site.xml
    
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/xdoc/manual/configuration.xml

Modified: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java?rev=1206675&r1=1206674&r2=1206675&view=diff
==============================================================================
--- 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java
 (original)
+++ 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java
 Sun Nov 27 07:22:46 2011
@@ -148,10 +148,15 @@ public class JSONConfiguration extends B
                 if (n.isArray()) {
                     logger.debug("Processing node for array " + 
entry.getKey());
                     for (int i=0; i < n.size(); ++i) {
-                        PluginType entryType = 
getPluginManager().getPluginType(entry.getKey());
+                        String pluginType = getType(n.get(i), entry.getKey());
+                        PluginType entryType = 
getPluginManager().getPluginType(pluginType);
                         Node item = new Node(node, entry.getKey(), entryType);
                         processAttributes(item, n.get(i));
-                        logger.debug("Processing " + entry.getKey() + "[" + i 
+ "]");
+                        if (pluginType.equals(entry.getKey())) {
+                            logger.debug("Processing " + entry.getKey() + "[" 
+ i + "]");
+                        } else {
+                            logger.debug("Processing " + pluginType + " " + 
entry.getKey() + "[" + i + "]");
+                        }
                         Iterator<Map.Entry<String, JsonNode>> itemIter = 
n.get(i).getFields();
                         List<Node> itemChildren = item.getChildren();
                         while (itemIter.hasNext()) {
@@ -167,8 +172,6 @@ public class JSONConfiguration extends B
                     logger.debug("Processing node for object " + 
entry.getKey());
                     children.add(constructNode(entry.getKey(), node, n));
                 }
-
-
             }
         }
 
@@ -184,14 +187,30 @@ public class JSONConfiguration extends B
         return node;
     }
 
+    private String getType(JsonNode node, String name) {
+        Iterator<Map.Entry<String, JsonNode>> iter = node.getFields();
+        while (iter.hasNext()) {
+            Map.Entry<String, JsonNode> entry = iter.next();
+            if (entry.getKey().equalsIgnoreCase("type")) {
+                JsonNode n = entry.getValue();
+                if (n.isValueNode()) {
+                    return n.asText();
+                }
+            }
+        }
+        return name;
+    }
+
     private void processAttributes(Node parent, JsonNode node) {
         Map<String, String> attrs = parent.getAttributes();
         Iterator<Map.Entry<String, JsonNode>> iter = node.getFields();
         while (iter.hasNext()) {
             Map.Entry<String, JsonNode> entry = iter.next();
-            JsonNode n = entry.getValue();
-            if (n.isValueNode()) {
-                attrs.put(entry.getKey(), n.asText());
+            if (!entry.getKey().equalsIgnoreCase("type")) {
+                JsonNode n = entry.getValue();
+                if (n.isValueNode()) {
+                    attrs.put(entry.getKey(), n.asText());
+                }
             }
         }
     }

Modified: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java?rev=1206675&r1=1206674&r2=1206675&view=diff
==============================================================================
--- 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
 (original)
+++ 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
 Sun Nov 27 07:22:46 2011
@@ -62,6 +62,8 @@ public class XMLConfiguration extends Ba
 
     private boolean strict = false;
 
+    private String schema = null;
+
     private static final String[] verboseClasses = new String[] { 
ResolverUtil.class.getName() };
 
     private Validator validator;
@@ -95,6 +97,8 @@ public class XMLConfiguration extends Ba
                     setName(entry.getValue());
                 } else if ("strict".equalsIgnoreCase(entry.getKey())) {
                     strict = Boolean.parseBoolean(entry.getValue());
+                } else if ("schema".equalsIgnoreCase(entry.getKey())) {
+                    schema = entry.getValue();
                 } else if ("monitorInterval".equalsIgnoreCase(entry.getKey())) 
{
                     int interval = Integer.parseInt(entry.getValue());
                     if (interval > 0 && configFile != null) {
@@ -129,24 +133,31 @@ public class XMLConfiguration extends Ba
         } catch (ParserConfigurationException pex) {
             logger.error("Error parsing " + source.getSystemId(), pex);
         }
-        if (strict && buffer != null) {
-            InputStream is = 
getClass().getClassLoader().getResourceAsStream(LOG4J_XSD);
-            Source src = new StreamSource(is, LOG4J_XSD);
-            SchemaFactory factory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-            Schema schema = null;
+        if (strict && schema != null && buffer != null) {
+            InputStream is = null;
             try {
-                schema = factory.newSchema(src);
-            } catch (SAXException ex) {
-                logger.error("Error parsing Log4j schema", ex);
-            }
-            if (schema != null) {
-                validator = schema.newValidator();
+                is = getClass().getClassLoader().getResourceAsStream(schema);
+            } catch (Exception ex) {
+                logger.error("Unable to access schema " + schema);
+            }
+            if (is != null) {
+                Source src = new StreamSource(is, LOG4J_XSD);
+                SchemaFactory factory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+                Schema schema = null;
                 try {
-                    validator.validate(new StreamSource(new 
ByteArrayInputStream(buffer)));
-                } catch (IOException ioe) {
-                    logger.error("Error reading configuration for validation", 
ioe);
+                    schema = factory.newSchema(src);
                 } catch (SAXException ex) {
-                    logger.error("Error validating configuration", ex);
+                    logger.error("Error parsing Log4j schema", ex);
+                }
+                if (schema != null) {
+                    validator = schema.newValidator();
+                    try {
+                        validator.validate(new StreamSource(new 
ByteArrayInputStream(buffer)));
+                    } catch (IOException ioe) {
+                        logger.error("Error reading configuration for 
validation", ioe);
+                    } catch (SAXException ex) {
+                        logger.error("Error validating configuration", ex);
+                    }
                 }
             }
         }

Modified: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/lookup/MapLookup.java
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/lookup/MapLookup.java?rev=1206675&r1=1206674&r2=1206675&view=diff
==============================================================================
--- 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/lookup/MapLookup.java
 (original)
+++ 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/lookup/MapLookup.java
 Sun Nov 27 07:22:46 2011
@@ -17,12 +17,15 @@
 package org.apache.logging.log4j.core.lookup;
 
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.message.MapMessage;
 
 import java.util.Map;
 
 /**
  * The basis for a lookup based on a Map.
  */
+@Plugin(name="map",type="Lookup")
 public class MapLookup<V> implements StrLookup<V> {
     /**
      * Map keys are variable names and value.
@@ -30,7 +33,7 @@ public class MapLookup<V> implements Str
     private final Map<String, V> map;
 
     /**
-     * Creates a new instance backed by a Map.
+     * Creates a new instance backed by a Map. Used by the default lookup.
      *
      * @param map the map of keys to values, may be null
      */
@@ -39,6 +42,13 @@ public class MapLookup<V> implements Str
     }
 
     /**
+     * Constructor when used directly as a plugin.
+     */
+    public MapLookup() {
+        this.map = null;
+    }
+
+    /**
      * Looks up a String key to a String value using the map.
      * <p/>
      * If the map is null, then null is returned.
@@ -59,6 +69,18 @@ public class MapLookup<V> implements Str
     }
 
     public String lookup(LogEvent event, String key) {
-        return lookup(key);
+        if (map == null && !(event.getMessage() instanceof MapMessage)) {
+            return null;
+        }
+        if (map != null && map.containsKey(key)) {
+            Object obj = map.get(key);
+            if (obj != null) {
+                return obj.toString();
+            }
+        }
+        if (event.getMessage() instanceof MapMessage) {
+            return ((MapMessage) event.getMessage()).get(key);
+        }
+        return null;
     }
 }

Copied: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppender2Test.java
 (from r1204693, 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppenderTest.java)
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppender2Test.java?p2=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppender2Test.java&p1=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppenderTest.java&r1=1204693&r2=1206675&rev=1206675&view=diff
==============================================================================
--- 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppenderTest.java
 (original)
+++ 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/appender/routing/JSONRoutingAppender2Test.java
 Sun Nov 27 07:22:46 2011
@@ -40,8 +40,8 @@ import static org.junit.Assert.assertTru
 /**
  *
  */
-public class JSONRoutingAppenderTest {
-    private static final String CONFIG = "log4j-routing.json";
+public class JSONRoutingAppender2Test {
+    private static final String CONFIG = "log4j-routing2.json";
     private static Configuration config;
     private static ListAppender app;
     private static LoggerContext ctx;

Copied: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing2.json
 (from r1204693, 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing.json)
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing2.json?p2=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing2.json&p1=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing.json&r1=1204693&r2=1206675&rev=1206675&view=diff
==============================================================================
--- 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing.json
 (original)
+++ 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-routing2.json
 Sun Nov 27 07:22:46 2011
@@ -4,31 +4,32 @@
       },
     "ThresholdFilter": { "level": "debug" },
     "appenders": {
-      "Console": { "name": "STDOUT",
-        "PatternLayout": { "pattern": "%m%n" }
-      },
-      "List": { "name": "List",
-        "ThresholdFilter": { "level": "debug" }
-      },
-      "Routing": { "name": "Routing",
-        "Routes": { "pattern": "$${sd:type}",
-          "Route": [
-            {
-              "RollingFile": {
-                "name": "Rolling-${sd:type}", "fileName": "${filename}",
-                "filePattern": "target/rolling1/test1-${sd:type}.%i.log.gz",
-                "PatternLayout": {"pattern": "%d %p %C{1.} [%t] %m%n"},
-                "SizeBasedTriggeringPolicy": { "size": "500" }
-              }
-            },
-            { "appender-ref": "STDOUT", "key": "Audit"},
-            { "appender-ref": "List", "key": "Service"}
-          ]
+      "appender": [
+         { "type": "Console", "name": "STDOUT", "PatternLayout": { "pattern": 
"%m%n" }},
+         { "type": "List", "name": "List", "ThresholdFilter": { "level": 
"debug" }},
+         { "type": "Routing",  "name": "Routing",
+          "Routes": { "pattern": "$${sd:type}",
+            "Route": [
+              {
+                "RollingFile": {
+                  "name": "Rolling-${sd:type}", "fileName": "${filename}",
+                  "filePattern": "target/rolling1/test1-${sd:type}.%i.log.gz",
+                  "PatternLayout": {"pattern": "%d %p %C{1.} [%t] %m%n"},
+                  "SizeBasedTriggeringPolicy": { "size": "500" }
+                }
+              },
+              { "appender-ref": "STDOUT", "key": "Audit"},
+              { "appender-ref": "List", "key": "Service"}
+            ]
+          }
         }
-      }
+      ]
     },
     "loggers": {
-      "logger": { "name": "EventLogger", "level": "info", "additivity": 
"false", "appender-ref": { "ref": "Routing" }},
+      "logger": [
+        { "name": "EventLogger", "level": "info", "additivity": "false", 
"appender-ref": { "ref": "Routing" }},
+        { "name": "com.foo.bar", "level": "error", "additivity": "false", 
"appender-ref": { "ref": "Console" }}
+      ],
       "root": { "level": "error", "appender-ref": { "ref": "STDOUT" }}
     }
   }

Modified: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/site.xml
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/site.xml?rev=1206675&r1=1206674&r2=1206675&view=diff
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/site.xml 
(original)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/site.xml Sun 
Nov 27 07:22:46 2011
@@ -45,7 +45,7 @@
       <item name="Architecture" href="/manual/architecture.html"/>
       <item name="Configuration" href="/manual/configuration.html" 
collapse="true">
         <item name="Automatic Configuration" 
href="/manual/configuration.html#AutomaticConfiguration"/>
-        <item name="Additivity" href="/manual/configuration.html#Additvity"/>
+        <item name="Additivity" href="/manual/configuration.html#Additivity"/>
         <item name="Automatic Reconfiguration" 
href="/manual/configuration.html#AutomaticReconfiguration"/>
         <item name="Configuration Syntax" 
href="/manual/configuration.html#ConfigurationSyntax"/>
         <item name="Property Substitution" 
href="/manual/configuration.html#PropertySubstitution"/>

Modified: 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/xdoc/manual/configuration.xml
URL: 
http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/xdoc/manual/configuration.xml?rev=1206675&r1=1206674&r2=1206675&view=diff
==============================================================================
--- 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/xdoc/manual/configuration.xml
 (original)
+++ 
logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/src/site/xdoc/manual/configuration.xml
 Sun Nov 27 07:22:46 2011
@@ -40,6 +40,8 @@
               components to the default configuration.</li>
             <li>Programmatically, by calling methods on the internal Logger 
class.</li>
           </ol>
+        </p>
+        <p>
           This page focuses primarily on configuring Log4j through a 
configuration file. Information on
           programmatically configuring Log4j can be found at <a 
href="../extending.html">Extending Log4j 2</a>.
         </p>
@@ -246,16 +248,498 @@
             When configured from a File, Log4j has the ability to 
automatically detect changes to the configuration
             file and reconfigure itself. If the monitorInterval attribute is 
specified on the configuration element
             and is set to a non-zero value then the file will be checked the 
next time a log event is evaluated
-            and/or logged and the monitorInterval has elapsed since the last 
check.
+            and/or logged and the monitorInterval has elapsed since the last 
check. The example below shows how
+            to configure the attribute so that the configuration file will be 
checked for changes only after at
+            least 30 seconds have elapsed.  The minimum, and default, interval 
is 30 seconds.
           </p>
+          <source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<configuration monitorInterval="30">
+...
+</configuration>]]></source>
         </subsection>
         <a name="ConfigurationSyntax"/>
         <subsection name="Configuration Syntax">
+          <p>
+            As the previous examples have shown as well as those to follow, 
Log4j allows you to easily
+            redefine logging behavior without needing to modify your 
application. It is possible to
+            disable logging for certain parts of the application, log only 
when specific criteria are met such
+            as the action being performed for a specific user, route output to 
Flume or a log reporting system,
+            etc. Being able to do this requires understanding the syntax of 
the configuration files.
+          </p>
+          <h4>Configuration with XML</h4>
+          <p>
+            The configuration element in the XML file accetps several 
attributes:
+            <table>
+              <tr>
+                <th>Attribute Name</th>
+                <th>Description</th>
+              </tr>
+              <tr>
+                <td>monitorInterval</td>
+                <td>The minimum amount of time, in seconds, that must elapse 
before the file configuration
+                  is checked for changes.</td>
+              </tr>
+              <tr>
+                <td>name</td>
+                <td>The name of the configuration.</td>
+              </tr>
+              <tr>
+                <td>packages</td>
+                <td>A comma separated list of package names to search for 
plugins. Plugins are only loaded
+                  once per classloader so changing this value may not have any 
effect upon reconfiguration.</td>
+              </tr>
+              <tr>
+                <td>schema</td>
+                <td>Identifies the location for the classloader to located the 
XML Schema to use to validate
+                  the configuration. Only valid when strict is set to true. If 
not set no schema validation
+                  will take place.</td>
+              </tr>
+              <tr>
+                <td>status</td>
+                <td>The level of internal Log4j events that should be logged 
to the console.</td>
+              </tr>
+              <tr>
+                <td>strict</td>
+                <td>Enables the use of the strict XML format. Not supported in 
JSON configurations.</td>
+              </tr>
+              <tr>
+                <td>verbose</td>
+                <td>Enables diagnostic information while loading plugins.</td>
+              </tr>
+            </table>
+          </p>
+          <p>
+            Log4j can be configured using two XML flavors; concise and strict. 
The concise format makes
+            configuration very easy as the element names match the components 
they represent however it
+            cannot be validated with an XML schema. For example, the 
ConsoleAppender is configured by
+            declaring an XML element named Console under its parent appenders 
element. However, element
+            and attribute names are are not case sensitive. In addition, 
attributes can either be specified
+            as an XML attribute or as an XML element that has no attributes 
and has a text value. So
+          </p>
+          <source><![CDATA[<patternLayout pattern="%m%n"/>]]></source>
+          <p>and</p>
+          <source><![CDATA[<PatternLayout>
+  <pattern>%m%n</pattern>
+</PatternLayout>]]></source>
+          <p>
+            are equivalent.
+          </p>
+          <p>
+            The file below represents the structure of an XML configuration, 
but note
+            that the elements in italics below represent the concise element 
names that would appear in their place.
+          </p>
+
+          <source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>;
+<configuration>
+  <properties>
+    <property name="name1">value</property>
+    <property name="name2" value="value2"/>
+  </properties>
+  <]]><i>filter</i>  ... <![CDATA[/>
+  <appenders>
+    <]]><i>appender</i> ... <![CDATA[>
+      <]]><i>filter</i>  ... <![CDATA[/>
+    </]]><i>appender</i><![CDATA[>
+    ...
+  </appenders>
+  <loggers>
+    <logger name="name1">
+      <]]><i>filter</i>  ... <![CDATA[/>
+    </logger>
+    ...
+    <root level="level">
+      <appender-ref ref="name"/>
+    </root>
+  </loggers>
+</configuration>]]></source>
+          <p>
+            See the many examples on this page for sample appender, filter and 
logger declarations.
+          </p>
+            <h5>Strict XML</h5>
+          <p>
+            In addition to the concise XML format above, Log4j allows 
configurations to be specified in a
+            more "normal" XML manner that can be validated using an XML 
Schema. This is accomplished by
+            replacing the friendly element names above with their object type 
as shown below. For example,
+            instead of the ConsoleAppender being configuerd using an element 
named Console it is instead
+            configured as an appender element with a type attribute containing 
"Console".
+          </p>
+          <source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>;
+<configuration>
+  <properties>
+    <property name="name1">value</property>
+    <property name="name2" value="value2"/>
+  </properties>
+  <filter type="type" ... />
+  <appenders>
+    <appender type="type" name="name">
+      <filter type="type" ... />
+    </appender>
+    ...
+  </appenders>
+  <loggers>
+    <logger name="name1">
+      <filter type="type" ... />
+    </logger>
+    ...
+    <root level="level">
+      <appender-ref ref="name"/>
+    </root>
+  </loggers>
+</configuration>]]></source>
+          <p>
+            Below is a sample configuration using the strict format.
+          </p>
+          <source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<configuration status="debug" strict="true" name="XMLConfigTest" 
packages="org.apache.logging.log4j.test">
+  <properties>
+    <property name="filename">target/test.log</property>
+  </properties>
+  <filter type="ThresholdFilter" level="trace"/>
+
+  <appenders>
+    <appender type="Console" name="STDOUT">
+      <layout type="PatternLayout" pattern="%m MDC%X%n"/>
+      <filters>
+        <filter type="MarkerFilter" marker="FLOW" onMatch="DENY" 
onMismatch="NEUTRAL"/>
+        <filter type="MarkerFilter" marker="EXCEPTION" onMatch="DENY" 
onMismatch="ACCEPT"/>
+      </filters>
+    </appender>
+    <appender type="Console" name="FLOW">
+      <layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/>
+      <filters>
+        <filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" 
onMismatch="NEUTRAL"/>
+        <filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" 
onMismatch="DENY"/>
+      </filters>
+    </appender>
+    <appender type="File" name="File" fileName="${filename}">
+      <layout type="PatternLayout">
+        <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+      </layout>
+    </appender>
+    <appender type="List" name="List">
+    </appender>
+  </appenders>
+
+  <loggers>
+    <logger name="org.apache.logging.log4j.test1" level="debug" 
additivity="false">
+      <filter type="ThreadContextMapFilter">
+        <KeyValuePair key="test" value="123"/>
+      </filter>
+      <appender-ref ref="STDOUT"/>
+    </logger>>
+
+    <logger name="org.apache.logging.log4j.test2" level="debug" 
additivity="false">
+      <appender-ref ref="File"/>
+    </logger>>
+
+    <root level="trace">
+      <appender-ref ref="List"/>
+    </root>
+  </loggers>
+
+</configuration>]]></source>
+          <h4>Configuration with JSON</h4>
+          <p>
+            In addition to XML, Log4j can be configured using JSON. The JSON 
format is very similar to the
+            concise XML format. Each key represents the name of a plugin and 
the key/value pairs associated
+            with it are its attributes. Where a key contains more than a 
simple value it itself will be a
+            subordinate plugin. In the example below, ThresholdFilter, 
Console, and PatternLayout are all
+            plugins while the Console plugin will be assigned a value of 
STDOUT for its name attribute and the
+            ThresholdFilter will be assigned a level of debug.
+          </p>
+          <source>{ "configuration": { "status": "error", "name": 
"RoutingTest", "packages": "org.apache.logging.log4j.test",
+      "properties": {
+        "property": { "name": "filename", "value" : 
"target/rolling1/rollingtest-$${sd:type}.log" }
+      },
+    "ThresholdFilter": { "level": "debug" },
+    "appenders": {
+      "Console": { "name": "STDOUT",
+        "PatternLayout": { "pattern": "%m%n" }
+      },
+      "List": { "name": "List",
+        "ThresholdFilter": { "level": "debug" }
+      },
+      "Routing": { "name": "Routing",
+        "Routes": { "pattern": "$${sd:type}",
+          "Route": [
+            {
+              "RollingFile": {
+                "name": "Rolling-${sd:type}", "fileName": "${filename}",
+                "filePattern": "target/rolling1/test1-${sd:type}.%i.log.gz",
+                "PatternLayout": {"pattern": "%d %p %C{1.} [%t] %m%n"},
+                "SizeBasedTriggeringPolicy": { "size": "500" }
+              }
+            },
+            { "appender-ref": "STDOUT", "key": "Audit"},
+            { "appender-ref": "List", "key": "Service"}
+          ]
+        }
+      }
+    },
+    "loggers": {
+      "logger": { "name": "EventLogger", "level": "info", "additivity": 
"false", "appender-ref": { "ref": "Routing" }},
+      "root": { "level": "error", "appender-ref": { "ref": "STDOUT" }}
+    }
+  }
+}</source>
+           <p>
+            Note that in the RoutingAppender the Route element has been 
declared as an array. This is
+            valid because each array element will be a Route component. This 
won't work for elements such as
+            appenders and filters, where each element has a different name in 
the concise format. Appenders and
+            filters can be defined as array elements if each appender or 
filter declares an attribute named "type"
+            that contains the type of the appender. The following example 
illustrates this as well as how to
+            declare multiple loggers as an array.
+          </p>
+           <source>{ "configuration": { "status": "debug", "name": 
"RoutingTest", "packages": "org.apache.logging.log4j.test",
+      "properties": {
+        "property": { "name": "filename", "value" : 
"target/rolling1/rollingtest-$${sd:type}.log" }
+      },
+    "ThresholdFilter": { "level": "debug" },
+    "appenders": {
+      "appender": [
+         { "type": "Console", "name": "STDOUT", "PatternLayout": { "pattern": 
"%m%n" }},
+         { "type": "List", "name": "List", "ThresholdFilter": { "level": 
"debug" }},
+         { "type": "Routing",  "name": "Routing",
+          "Routes": { "pattern": "$${sd:type}",
+            "Route": [
+              {
+                "RollingFile": {
+                  "name": "Rolling-${sd:type}", "fileName": "${filename}",
+                  "filePattern": "target/rolling1/test1-${sd:type}.%i.log.gz",
+                  "PatternLayout": {"pattern": "%d %p %C{1.} [%t] %m%n"},
+                  "SizeBasedTriggeringPolicy": { "size": "500" }
+                }
+              },
+              { "appender-ref": "STDOUT", "key": "Audit"},
+              { "appender-ref": "List", "key": "Service"}
+            ]
+          }
+        }
+      ]
+    },
+    "loggers": {
+      "logger": [
+        { "name": "EventLogger", "level": "info", "additivity": "false", 
"appender-ref": { "ref": "Routing" }},
+        { "name": "com.foo.bar", "level": "error", "additivity": "false", 
"appender-ref": { "ref": "Console" }}
+      ],
+      "root": { "level": "error", "appender-ref": { "ref": "STDOUT" }}
+    }
+  }
+}</source>
+          <h4>Configuring loggers</h4>
+          <p>
+            An understanding of how loggers work in Log4j is critical before 
trying to configure them.
+            Please reference the Log4j <a 
href="../architecture.html">architecture</a> if more information is
+            required. Trying to configure Log4j without understanding those 
concepts will lead to frustration.
+          </p>
+          <p>
+            A LoggerConfig is configured using the <code>logger</code> 
element. The <code>logger</code> eleemnt
+            must have a name attribute specified, will usually have a level 
attribute specified and may
+            also have an additivity attribute specified.  The level may be 
configured with one of TRACE,
+            DEBUG, INFO, WARN, ERROR, ALL or OFF. If no level is specified it 
will default to ERROR. The
+            additivity attribute may be assigned a value of true or false. If 
the attribute is omitted
+            the default value of false will be used.
+          </p>
+          <p>
+            The LoggerConfig may also be configured with one or more 
appender-ref elements. Each appender
+            referenced will become associated with the specified LoggerConfig. 
If multiple appenders
+            are configured on the LoggerConfig each of them be called when 
processing logging events.
+          </p>
+          <p>
+            Every configuration must have a root logger. If one is not 
configured the default root LoggerConfig,
+            which has a level of ERROR but with no appenders attached, will be 
used. The main differences
+            between the root logger and other loggers are
+            <ol>
+              <li>The root logger does not have a name attribute.</li>
+              <li>The root logger does not support the additivity attribute 
since it has no parent.</li>
+            </ol>
+          </p>
+          <h4>Configuring Appenders</h4>
+          <p>
+            An appender is configured either using the specific appender 
plugin's name or with an appender
+            element and the type attibute containing the appender plugin's 
name. In addition each appender
+            must have a name attribute specified with a value that is unique 
within the set of appenders.
+            The name will be used by loggers to reference the appender as 
described in the previous section.
+          </p>
+          <p>
+            Most appenders also support a layout to be configured (which again 
may be specified either
+            using the specific Layout plugin's name as the eleemnt or with 
"layout" as the element name
+            along with a type attribute that contains the layout plugin's 
name. The various appenders
+            will contain other attributes or elements that are required for 
them to function properly.
+          </p>
+          <h4>Configuring Filters</h4>
+          <p>
+            Log4j allows a filter to be specified in any of 3 places:
+            <ol>
+              <li>At the same level as the appenders, loggers and properties 
elements. These filters can accept
+              or reject events before they have been passed to a 
LoggerConfig.</li>
+              <li>In a logger element. These filters can accept or reject 
events for specific loggers.</li>
+              <li>In an appender element. These filters can prevent or cause 
events to be processed by
+                the appender.</li>
+            </ol>
+          </p>
+          <p>
+            Although only a single <code>filter</code> element can be 
configured, that element may be the
+            <code>filters</code> element which represents the CompositeFilter. 
The <code>filters</code> element
+            allows any number of <code>filter</code> elements to be configured 
within it. The following example
+            shows how multiple filters can be configured on the 
ConsoleAppender.
+          </p>
+          <source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<configuration status="debug" name="XMLConfigTest" 
packages="org.apache.logging.log4j.test">
+  <properties>
+    <property name="filename">target/test.log</property>
+  </properties>
+  <ThresholdFilter level="trace"/>
+
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m MDC%X%n"/>
+      <filters>
+        <MarkerFilter marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
+        <MarkerFilter marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
+      </filters>
+    </Console>
+    <Console name="FLOW">
+      <PatternLayout pattern="%C{1}.%M %m %ex%n"/>
+      <filters>
+        <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
+        <MarkerFilter marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
+      </filters>
+    </Console>
+    <File name="File" fileName="${filename}">
+      <PatternLayout>
+        <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+      </PatternLayout>
+    </File>
+    <List name="List">
+    </List>
+  </appenders>
 
+  <loggers>
+    <logger name="org.apache.logging.log4j.test1" level="debug" 
additivity="false">
+      <ThreadContextMapFilter>
+        <KeyValuePair key="test" value="123"/>
+      </ThreadContextMapFilter>
+      <appender-ref ref="STDOUT"/>
+    </logger>>
+
+    <logger name="org.apache.logging.log4j.test2" level="debug" 
additivity="false">
+      <appender-ref ref="File"/>
+    </logger>>
+
+    <root level="trace">
+      <appender-ref ref="List"/>
+    </root>
+  </loggers>
+
+</configuration>]]></source>
         </subsection>
         <a name="PropertySubstitution"/>
         <subsection name="Property Substitution">
+          <p>
+            Log4j 2 supports the ability to specify tokens in the 
configuration as references to properties defined
+            elsewhere. Some of these properties will be resolved when the 
configuration file is interpreted while
+            others may be passed to components where they will be evaluated at 
runtime. To accomplish this, Log4j
+            uses variations Apache Commons Lang's
+            <a 
href="../log4j2-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor">StrSubstitutor</a>
+            and <a 
href="../log4j2-core/apidocs/org/apache/logging/log4j/core/lookup/StrLookup">StrLookup</a>
+            classes. In a manner similar to Ant or Maven, this allows 
variables declared as <code>${name}</code>
+            to be resolved using properties declared in the configuration 
itself. For example, the following example
+            shows the filename for the rolling file appender being declared as 
a property.
+          </p>
+<source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<configuration status="debug" name="RoutingTest" 
packages="org.apache.logging.log4j.test">
+  <properties>
+    <property 
name="filename">target/rolling1/rollingtest-$${sd:type}.log</property>
+  </properties>
+  <ThresholdFilter level="debug"/>
+
+  <appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m%n"/>
+    </Console>
+    <List name="List">
+      <ThresholdFilter level="debug"/>
+    </List>
+    <Routing name="Routing">
+      <Routes pattern="$${sd:type}">
+        <Route>
+          <RollingFile name="Rolling-${sd:type}" fileName="${filename}"
+                       
filePattern="target/rolling1/test1-${sd:type}.%i.log.gz">
+            <PatternLayout>
+              <pattern>%d %p %C{1.} [%t] %m%n</pattern>
+            </PatternLayout>
+            <SizeBasedTriggeringPolicy size="500" />
+          </RollingFile>
+        </Route>
+        <Route appender-ref="STDOUT" key="Audit"/>
+        <Route appender-ref="List" key="Service"/>
+      </Routes>
+    </Routing>
+  </appenders>
 
+  <loggers>
+    <logger name="EventLogger" level="info" additivity="false">
+      <appender-ref ref="Routing"/>
+    </logger>
+
+    <root level="error">
+      <appender-ref ref="STDOUT"/>
+    </root>
+  </loggers>
+
+</configuration>]]></source>
+          <p>
+            While this is useful, there are many more places properties can 
originate from. To accommodate this,
+            Log4j also supports the syntax <code>${prefix:name}</code> where 
the prefix identifies tells Log4j
+            that variable name should be evaluated in a specific context. The 
contexts that are built in to Logj4
+            are:
+            <table>
+              <tr>
+                <th>Prefix</th>
+                <th>Context</th>
+              </tr>
+              <tr>
+                <td>ctx</td>
+                <td>Thread Context Map (MDC)</td>
+              </tr>
+              <tr>
+                <td>env</td>
+                <td>System environment variables</td>
+              </tr>
+              <tr>
+                <td>map</td>
+                <td>A value from a MapMessage</td>
+              </tr>
+              <tr>
+                <td>sd</td>
+                <td>A value from a StructuredDataMessage. The key "id" will 
return the name of the StructuredDataId
+                  without the enterprise number. The key "type" will return 
the message type. Other keys will
+                  retrieve individual elements from the Map.</td>
+              </tr>
+              <tr>
+                <td>sys</td>
+                <td>System properties</td>
+              </tr>
+            </table>
+          </p>
+          <p>
+            An interesting feature of StrLookup processing is that when a 
variable reference is declared with
+            multiple leading '$' characters each time the variable is resolved 
the leading '$' is simply removed.
+            In the previous example the "Routes" element is capable of 
resolving the variable at runtime. To allow
+            this the prefix value is specified as a variable with two leading 
'$' characters. When the configuration
+            file is first processed the first variable is simply removed. 
Thus, when the Routes element is evaluated
+            at runtime it is the variable declaration "${sd:type}" which 
causes the event to be inspected for a
+            StructuredDataMessage and if one is present the value of its type 
attribute to be used as the routing key.
+            Not all elements support resolving variables at runtime. 
Components that do will specifically call that
+            out in their documentation.
+          </p>
+          <p>
+            <i>As a footnote, it is worth pointing out that the variables in 
the RollingFile appender declaration
+            will also not be evaluated when the configuration is processed. 
This is simply because the resolution
+            of the whole RollingFile element is deferred until a match occurs.
+            See <a 
href="../appenders.html#RoutingAppender">RoutingAppender</a> for more 
information.</i>
+          </p>
         </subsection>
         <a name="StatusMessages"/>
         <subsection name="Status Messages">
@@ -378,9 +862,19 @@
           </p>
         </subsection>
         <a name="UnitTestingInMaven"/>
-        <subsection name="Unit Testing in Maven">
-
-
+        <subsection name="Testing in Maven">
+        <p>
+          Maven can run unit and functional tests during the build cycle. By 
default, any files placed in
+          <code>src/test/resources</code> are automatically copied to 
target/test-classes and are included
+          in the classpath during execution of any tests. As such, placing a 
log4j-test.xml into this directory
+          will cause it to be used instead of a log4j.xml or log4j.json that 
might be present.  Thus a different
+          log configuration can be used during testing than what is used in 
production.
+        </p>
+        <p>
+          A second approach, which is extensively used by Log4j 2, is to set 
the log4j.configurationFile property
+          in the method annotated with @BeforeClass in the junit test class. 
This will allow an arbitrarily
+          named file to be used during the test.
+        </p>
         </subsection>
       </section>
     </body>


Reply via email to