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/08/21 04:26:18 UTC

svn commit: r1375371 - in /logging/log4j/log4j2/trunk/src/site/xdoc/manual: extending.xml logsep.xml

Author: rgoers
Date: Tue Aug 21 02:26:18 2012
New Revision: 1375371

URL: http://svn.apache.org/viewvc?rev=1375371&view=rev
Log:
Add some documentation

Modified:
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/logsep.xml

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=1375371&r1=1375370&r2=1375371&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/extending.xml Tue Aug 21 02:26:18 2012
@@ -24,32 +24,360 @@
 
     <body>
       <section name="Extending Log4j">
+        <p>
+          Log4j 2 provides numerous ways that it can be manipulated and extended. This section includes an
+          overview of the various ways that are directly supported by the Log4j 2 implementation.
+        </p>
           <subsection name="LoggerContextFactory">
-
+            <p>
+              The LoggerContextFactory binds the Log4j API to its implementation. The Log4j LogManager
+              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.
+              Finally, the value of the "LoggerContextFactory" property will be used to locate the
+              LoggerContextFactory. In Log4j 2 this is provided by Log4jContextFactory.
+            </p>
           </subsection>
           <subsection name="ContextSelector">
-
+            <p>
+              ContextSelectors are called by the Log4j LoggerContext factory. They perform the actual work of
+              locating or creating a LoggerContext, which is the anchor for Loggers and their configuration.
+              ContextSelectors are free to implement any mechanism they desire to manage LoggerContexts. The
+              default Log4jContextFactory checks for the presence of a System Property named "Log4jContextSelector".
+              If found, the property is expected to contain the name of the Class that implements the
+              ContextSelector to be used.
+            </p>
+            <p>
+              Log4j provides three ContextSelectors:
+              <dl>
+                <dt>BasicContextSelector</dt>
+                <dd>Uses either a LoggerContext that has been stored in a ThreadLocal or a common LoggerContext.</dd>
+                <dt>ClassLoaderContextSelector</dt>
+                <dd>Associates LoggerContexts with the ClassLoader that created the caller of the getLogger call.</dd>
+                <dt>JNDIContextSelector</dt>
+                <dd>Locates the LoggerContext by querying JNDI.</dd>
+              </dl>
+            </p>
           </subsection>
           <subsection name="ConfigurationFactory">
-
+            <p>
+              Modifying the way in which logging can be configured is usually one of the areas with the most
+              interest. The primary method for doing that is by implementing or extending a ConfigurationFactory.
+              Log4j provides two ways of adding new ConfigurationFactories. The first is by defining the system
+              property named "log4j.configurationFactory" to the name of the class that should be searched first
+              for a configuration. The second method is by defining the ConfigurationFactory as a Plugin.
+            </p>
+            <p>
+              All the ConfigurationFactories are then processed in order. Each factory is called on its
+              getSupportedTypes method to determine the file extensions it supports. If a configuration file
+              is located with one of the specified file extensions then control is passed to that
+              ConfigurationFactory to load the configuration and create the Configuration object.
+            </p>
+            <p>
+              Most Configuration extend the BaseConfiguration class. This class expects that the subclass will
+              process the configuration file and create a hierarchy of Node objects. Each Node is fairly simple
+              in that it consists of the name of the node, the name/value pairs associated with the node, The
+              PluginType of the node and a List of all of its child Nodes. BaseConfiguration will then be
+              passed the Node tree and instantiate the configuration objects from that.
+            </p>
+            <source>
+@Plugin(name = "XMLConfigurationFactory", type = "ConfigurationFactory")
+@Order(5)
+public class XMLConfigurationFactory extends ConfigurationFactory {
+
+    /**
+     * Valid file extensions for XML files.
+     */
+    public static final String[] SUFFIXES = new String[] {".xml", "*"};
+
+    /**
+     * Return the Configuration.
+     * @param source The InputSource.
+     * @return The Configuration.
+     */
+    public Configuration getConfiguration(InputSource source) {
+        return new XMLConfiguration(source, configFile);
+    }
+
+    /**
+     * Returns the file suffixes for XML files.
+     * @return An array of File extensions.
+     */
+    public String[] getSupportedTypes() {
+        return SUFFIXES;
+    }
+}</source>
           </subsection>
           <subsection name="LoggerConfig">
-
+            <p>
+              LoggerConfig objects are where Loggers created by applications tie into the configuration. The Log4j
+              implementation requires that all LoggerConfigs be based on the LoggerConfig class, so applications
+              wishing to make changes must do so by extending the LoggerConfig class. To declare the new
+              LoggerConfig, declare it as a Plugin of type "Core" and providing the name that applications
+              should specify as the element name in the configuration. The LoggerConfig should also define
+              a PluginFactory that will create an instance of the LoggerConfig.
+            </p>
+            <p>
+              The following example shows how the root LoggerConfig simply extends a generic LoggerConfig.
+            </p>
+            <source><![CDATA[
+@Plugin(name = "root", type = "Core", printObject = true)
+public static class RootLogger extends LoggerConfig {
+
+    @PluginFactory
+    public static LoggerConfig createLogger(@PluginAttr("additivity") String additivity,
+                                            @PluginAttr("level") String loggerLevel,
+                                            @PluginElement("appender-ref") AppenderRef[] refs,
+                                            @PluginElement("filters") Filter filter) {
+        List<AppenderRef> appenderRefs = Arrays.asList(refs);
+        Level level;
+        try {
+            level = loggerLevel == null ? Level.ERROR : Level.valueOf(loggerLevel.toUpperCase());
+        } catch (Exception ex) {
+            LOGGER.error("Invalid Log level specified: {}. Defaulting to Error", loggerLevel);
+            level = Level.ERROR;
+        }
+        boolean additive = additivity == null ? true : Boolean.parseBoolean(additivity);
+
+        return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additive);
+    }
+}]]></source>
           </subsection>
           <subsection name="Lookups">
-
+            <p>
+              Lookups are the means in which parameter substitution is performed. During Configuration initialization
+              an "Interpolator" is created that locates all the Lookups and registers them for use when a variable
+              needs to be resolved. The interpolator matches the "prefix" portion of the variable name to a
+              registered Lookup and passes control to it to resolve the variable.
+            </p>
+            <p>
+              A Lookup must be declared using a Plugin annotation with a type of "Lookup". The name specified on
+              the Plugin annotation will be used to match the prefix.  Unlike other Plugins, Lookups do not
+              use a PluginFactory. Instead, they are required to provide a constructor that accepts no arguments.
+              The example below shows a Lookup that will return the value of a System Property.
+            </p>
+            <source>
+@Plugin(name = "sys", type = "Lookup")
+public class SystemPropertiesLookup implements StrLookup {
+
+    /**
+     * Lookup the value for the key.
+     * @param key  the key to be looked up, may be null
+     * @return The value for the key.
+     */
+    public String lookup(String key) {
+        return System.getProperty(key);
+    }
+
+    /**
+     * Lookup the value for the key using the data in the LogEvent.
+     * @param event The current LogEvent.
+     * @param key  the key to be looked up, may be null
+     * @return The value associated with the key.
+     */
+    public String lookup(LogEvent event, String key) {
+        return System.getProperty(key);
+    }
+}</source>
           </subsection>
           <subsection name="Filters">
-
+            <p>
+              As might be expected, Filters are the used to reject or accept log events as they pass through the
+              logging system. A Filter is declared using a Plugin annotation of type "Core" and an elementType of
+              "filter". The name attribute on the Plugin annotation is used to specify the name of the element
+              users should use to enable the Filter. Specifying the printObject attribute with a value of "true"
+              indicates that a call to toString will format the arguments to the filter as the configuration
+              is being processed. The Filter must also specify a PluginFactory method that will be called to
+              create the Filter.
+            </p>
+            <p>
+              The example below shows a Filter used to reject LogEvents based upon their logging level. Notice the
+              typical pattern where all the filter methods resolve to a single filter method.
+            </p>
+            <source>
+@Plugin(name = "ThresholdFilter", type = "Core", elementType = "filter", printObject = true)
+public final class ThresholdFilter extends FilterBase {
+
+    private final Level level;
+
+    private ThresholdFilter(Level level, Result onMatch, Result onMismatch) {
+        super(onMatch, onMismatch);
+        this.level = level;
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
+        return filter(level);
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
+        return filter(level);
+    }
+
+    public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
+        return filter(level);
+    }
+
+    @Override
+    public Result filter(LogEvent event) {
+        return filter(event.getLevel());
+    }
+
+    private Result filter(Level level) {
+        return level.isAtLeastAsSpecificAs(this.level) ? onMatch : onMismatch;
+    }
+
+    @Override
+    public String toString() {
+        return level.toString();
+    }
+
+    /**
+     * Create a ThresholdFilter.
+     * @param loggerLevel The log Level.
+     * @param match The action to take on a match.
+     * @param mismatch The action to take on a mismatch.
+     * @return The created ThresholdFilter.
+     */
+    @PluginFactory
+    public static ThresholdFilter createFilter(@PluginAttr("level") String loggerLevel,
+                                               @PluginAttr("onMatch") String match,
+                                               @PluginAttr("onMismatch") String mismatch) {
+        Level level = loggerLevel == null ? Level.ERROR : Level.toLevel(loggerLevel.toUpperCase());
+        Result onMatch = match == null ? Result.NEUTRAL : Result.valueOf(match.toUpperCase());
+        Result onMismatch = mismatch == null ? Result.DENY : Result.valueOf(mismatch.toUpperCase());
+
+        return new ThresholdFilter(level, onMatch, onMismatch);
+    }
+}</source>
           </subsection>
           <subsection name="Appenders">
-
+            <p>
+              Appenders are passed an event, (usually) invoke a Layout to format the event, and then "publish"
+              the event in whatever manner is desired. Appenders are declared as Plugins with a type of "Core"
+              and an elementType of "appender". The name attribute on the Plugin annotation specifies the name
+              of the element users must provide in their configuration to use the Appender. Appender's should
+              specify printObject as "true" if the toString method renders the values of the attributes passed
+              to the Appender.
+            </p>
+            <p>
+              Appenders must also declare a PluginFactory method that will create the appender. The example
+              below shows an Appender named "Stub" that can be used as an initial template.
+            </p>
+            <p>
+              Most Appenders use Managers. A manager actually "owns" the resources, such as an OutputStream or
+              socket. When a reconfiguration occurs a new Appender will be created. However, if nothing significant
+              in the previous Manager has change the new Appender will simply reference it instead of creating a
+              new one. This insures that events are not lost while a reconfiguration is taking place without
+              requiring that logging pause while the reconfiguration takes place.
+            </p>
+            <source>
+@Plugin(name = "Stub", type = "Core", elementType = "appender", printObject = true)
+public final class StubAppender extends OutputStreamAppender {
+
+    private StubAppender(String name, Layout layout, Filter filter, StubManager manager, boolean handleExceptions) {
+    }
+
+    @PluginFactory
+    public static StubAppender createAppender(@PluginAttr("name") String name,
+                                              @PluginAttr("suppressExceptions") String suppress,
+                                              @PluginElement("layout") Layout layout,
+                                              @PluginElement("filters") Filter filter) {
+
+        boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress);
+
+        if (name == null) {
+            LOGGER.error("No name provided for StubAppender");
+            return null;
+        }
+
+        StubManager manager = StubManager.getStubManager(name);
+        if (manager == null) {
+            return null;
+        }
+        if (layout == null) {
+            layout = PatternLayout.createLayout(null, null, null, null);
+        }
+        return new StubAppender(name, layout, filter, manager, handleExceptions);
+    }
+}</source>
           </subsection>
           <subsection name="Layouts">
-
+            <p>
+              Layouts perform the formatting of events into the printable text that is written by Appenders to
+              some destination. All Layouts must implement the Layout interface. Layouts that format the
+              event into a String should extend AbstractStringLayout, which will take care of converting the
+              String into the required byte array.
+            </p>
+            <p>
+              Every Layout must declare itself as a plugin using the Plugin annotation. The type must be "Core",
+              and the elementType must be "Layout". printObject should be set to true if the plugin's toString
+              method will provide a representation of the object and its parameters. The name of the plugin must
+              match the value users should use to specify it as an element in their Appender configuration.
+              The plugin also must provide a static method annotated as a PluginFactory and with each of the
+              methods parameters annotated with PluginAttr or PluginElement as appropriate.
+            </p>
+            <source>
+@Plugin(name = "SampleLayout", type = "Core", elementType = "layout", printObject = true)
+public class SampleLayout extends AbstractStringLayout {
+
+    protected SampleLayout(boolean locationInfo, boolean properties, boolean complete, Charset charset) {
+    }
+
+    @PluginFactory
+    public static SampleLayout createLayout(@PluginAttr("locationInfo") String locationInfo,
+                                            @PluginAttr("properties") String properties,
+                                            @PluginAttr("complete") String complete,
+                                            @PluginAttr("charset") String charset) {
+        Charset c = Charset.isSupported("UTF-8") ? Charset.forName("UTF-8") : Charset.defaultCharset();
+        if (charset != null) {
+            if (Charset.isSupported(charset)) {
+                c = Charset.forName(charset);
+            } else {
+                LOGGER.error("Charset " + charset + " is not supported for layout, using " + c.displayName());
+            }
+        }
+        boolean info = locationInfo == null ? false : Boolean.valueOf(locationInfo);
+        boolean props = properties == null ? false : Boolean.valueOf(properties);
+        boolean comp = complete == null ? false : Boolean.valueOf(complete);
+        return new SampleLayout(info, props, comp, c);
+    }
+}</source>
           </subsection>
           <subsection name="PatternConverters">
-
+            <p>
+              PatternConverters are used by the PatternLayout to format the log event into a printable String. Each
+              Converter is responsible for a single kind of manipulation, however Converters are free to format
+              the event in complex ways. For example, there are several converters that manipulate Throwables and
+              format them in various ways.
+            </p>
+            <p>
+              A PatternConverter must first declare itself as a Plugin using the standard Plugin annotation but
+              must specify value of "Converter" on the type attribute. Furthermore, the Converter must also
+              specify the ConverterKeys attribute to define the tokens that can be specified in the pattern
+              (preceded by a '%' character) to identify the Converter.
+            </p>
+            <p>
+              Unlike most other Plugins, Converters do not use a PluginFactory. Instead, each Converter is
+              required to provide a static newInstance method that accepts an array of Strings as the only
+              parameter. The String array are the values that are specified within the curly braces that can
+              follow the converter key.
+            </p>
+            <p>
+              The following shows the skeleton of a Converter plugin.
+            </p>
+            <source>
+@Plugin(name = "query", type = "Converter")
+@ConverterKeys({"q", "query"})
+public final class QueryConverter extends LogEventPatternConverter {
+
+    public QueryConverter(String[] options) {
+    }
+
+    public static QueryConverter newInstance(final String[] options) {
+      return new QueryConverter(options);
+    }
+}</source>
           </subsection>
           <subsection name="Custom Plugins">
 

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/logsep.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/logsep.xml?rev=1375371&r1=1375370&r2=1375371&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/logsep.xml (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/logsep.xml Tue Aug 21 02:26:18 2012
@@ -23,6 +23,61 @@
     </properties>
 
     <body>
-      Log4J2
+      <section name="Logging Separation">
+        <p>
+          There are many well known use cases where applications may share an environment with other applications
+          and each has a need to have its own, separate logging environment. This purpose of this section is to
+          discuss some of these cases and ways to accomplish this.
+        </p>
+        <a name="Use Cases"/>
+        <subsection name="Use Cases">
+          <p>
+            This section describes some of the use cases where Log4j could be used and what its desired behavior
+            might be.
+          </p>
+          <h4>Standalone Application</h4>
+            <p>
+              Standalone applications are usually relatively simple. They typically have one bundled executable
+              that requires only a single logging configuration.
+            </p>
+          <h4>Web Applications</h4>
+            <p>
+              A typical web application will be packaged as a WAR file and will include all of its dependencies in
+              WEB-INF/lib and will have its configuration file located in the class path or in a location
+              configured in the web.xml.
+            </p>
+          <h4>Java EE Applications</h4>
+            <p>
+              A Java EE application will consist of one or more WAR files and possible some EJBs, typically all
+              packaged in an EAR file. Usually, it is desirable to have a single configuration that applies to
+              all the components in the EAR. The logging classes will generally be placed in a location shared
+              across all the components and the configuration needs to also be shareable.
+            </p>
+          <h4>"Shared" Web Applications and REST Service Containers</h4>
+            <p>
+              In this scenario there are multiple WAR files deployed into a single container. Each of the applications
+              should use the same logging configuration and share the same logging implementation across each of the
+              web applications. When writing to files and streams each of the applications should share them to avoid
+              the issues that can occur when multiple components try to write to the same file(s) through different
+              File objects, channels, etc.
+            </p>
+        </subsection>
+        <a name="Approaches"/>
+        <subsection name="Approaches">
+          <h4>The Simple Approach</h4>
+            <p>
+              The simplest approach for separating logging within applications is to package each application with
+              its own copy of Log4j and to use the BasicContextSelector. While this works for standalone applications
+              and may work for web applications and possibly Java EE applications, it does not work at all in the
+              last case.  However, when this approach does work it should be used as it is ultimately the simplest
+              and most straightforward way of implementing logging.
+            </p>
+
+          <h4>Using Context Selectors</h4>
+            <p>
+
+            </p>
+        </subsection>
+      </section>
     </body>
 </document>