Saturday, September 10, 2016

NullAppender implementation for log4j2

The NullAppender, which exists in the log4j1, is not provided by the log4j2. In the log4j2 the NullAppender can be implemented as a plugin (see log4j2 manual).
The log4j1 documentation for the NullAppender states, that this is an appender, which merely exists, but never outputs a message to any device. This description was used for NullAppender plugin implementation presented in this post.

NullAppender plugin implementation example


The plugin example is implemented by the class NullAppenderDemo, which is provided with the Plugin annotation:
 @Plugin(name = "NullAppender", category = "Core", elementType = "appender", printObject = true)  
 public class NullAppenderDemo extends AbstractAppender {  
    ...
The attribute name of the Plugin annotation specifies the name of the element, which should be put into log4j2 configuration in order to use the appender. It may be same to the class name or be different (like in the example). The rest of the attributes are assigned just with the predefined default values.

According to the name, specified in the Plugin annotation, setting the appender in the configuration is like this:
 <Appenders>  
   <NullAppender name="null">  
   .... other appenders  
 </Appenders> 
The term name, used in the configuration, is confusing. It is not the same name from the Plugin annotation. This is the name to be used for binding the appender to a Logger:
 <Loggers>  
     ...  
     <logger name="someLogger" additivity="false">  
          <appenderRef ref="null" />  
     </logger>  
     ...  
 </Loggers>
The NullAppenderDemo contains a factory method, which is called by log4j2 for creating an appender instance. The factory method:
1. Should be a public static method.
2. It may have any signature; the signature depends on the appender implementation.
3. It must be provided with the PluginFactory annotation.
4. Each argument of the factory method should be described with the PluginAttribute or PluginElement annotation. The PluginAttribute annotation is for a primitive types, the PluginElement - for complex types.
This is an example of the factory method:
 @PluginFactory  
 public static NullAppenderDemo createAppender(  
       @PluginAttribute("name") String name,  
       @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,  
       @PluginElement("Layout") Layout<? extends Serializable> layout,  
       @PluginElement("Filters") Filter filter) {  
The full implementation of the NullAppenderDemo plugin:
 package com.alasch1.logging.plugins;  
 import java.io.Serializable;  
 import org.apache.logging.log4j.core.Filter;  
 import org.apache.logging.log4j.core.Layout;  
 import org.apache.logging.log4j.core.LogEvent;  
 import org.apache.logging.log4j.core.appender.AbstractAppender;  
 import org.apache.logging.log4j.core.config.plugins.Plugin;  
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;  
 import org.apache.logging.log4j.core.config.plugins.PluginElement;  
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;  
 import org.apache.logging.log4j.core.layout.PatternLayout;  
 @Plugin(name = "NullAppenderDemo", category = "Core", elementType = "appender", printObject = true)  
 public classNullAppenderDemo extends AbstractAppender {  
      private static final long serialVersionUID = 1L;  
      protected NullAppenderDemo(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions) {  
           super(name, filter, layout, ignoreExceptions);  
      }  
      @Override  
      public void append(LogEvent event) { 
          // Nothing is done here !!! 
      }  
      @PluginFactory  
      public static NullAppender createAppender(  
           @PluginAttribute("name") String name,  
           @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,  
           @PluginElement("Layout") Layout<? extends Serializable> layout,  
           @PluginElement("Filters") Filter filter) {  
           if (name == null) {  
               LOGGER.error("No name provided for NullAppender");  
               return null;  
           }  
           return new NullAppenderDemo(name, filter, layout, ignoreExceptions);  
      }  
 }  

The log4j2 configuration with NullAppender


The configuration has the attribute package, which specifies to log4j2, where the plugin implementation is defined:
 <?xml version="1.0" encoding="UTF-8"?>  
 <Configuration packages="com.alasch1.logging.plugins">  
The configuration defines two appenders, named console and null.
The root logger has a binding to the console appender, which configures, that any message is to be output to the console. The additional logger, named com.alasch1.logging.examples.nullAppenderPackage, has a binding to the null appender. This configures, that no logging from the classes in this package will be done.
The full configuration source:
 <?xml version="1.0" encoding="UTF-8"?>  
 <Configuration packages="com.alasch1.logging.plugins">  
      <Appenders>  
           <NullAppender name="null">  
           </NullAppender>  
           <Console name="console">  
                <PatternLayout>  
                     <pattern>  
                          %d %level{length=2} (%c{1.}.%M:%L) - %m%n  
                     </pattern>  
                </PatternLayout>  
           </Console>  
      </Appenders>  
      <Loggers>  
           <root level="info">  
                <appenderRef ref="console" />  
           </root>  
           <logger name="com.alasch1.logging.examples.nullAppenderPackage" additivity="false">  
                <appenderRef ref="null" />  
           </logger>  
       </Loggers>  
 </Configuration>  
According to the above configuration, the following message will be not logged:
package com.alasch1.logging.examples.nullAppenderPackage;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public class Class4NullLogging {
 private static Logger LOG = LogManager.getLogger(Class4NullLogging.class); 
 public static void logMessage(String msg) {
  LOG.error("NullAppender is not configured : {} ", msg);
 }
}

The alternative to NullAppender


Implementation of NullAppender was not a big deal, but actually it was not necessary at all. Preventing of logging for a specific package may be done just with log level 'off'. All what is needed to get the same effect, as it was with the NullAppender, is to configure the logger like this:
 <Loggers>  
     ...  
     <logger name="someLogger" level="off">  
     </logger>  
     ...  
 </Loggers>
Full sources on Git.

No comments :

About the author

My Photo
I trust only simple code and believe that code should be handsome. This is not a matter of technology, but professional approach, consolidated after years of software development. I enjoy to cause things working and feel very happy, when I manage to solve a problem.
Back to Top