62

I am new in log4j. Can anyone explain how to create my own Appender? i.e. how to implement the classes and interfaces and how to override it?

Marco Altieri
  • 3,726
  • 2
  • 33
  • 47
unknown
  • 843
  • 2
  • 10
  • 14
  • 4
    you need to implement the [appender interface](http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Appender.html). but you should probably subclass one of the existing appenders and override the methods, e.g. doAppend(LoggingEvent), to suit your needs. – happymeal May 20 '11 at 13:50
  • 1
    what if the existing appender is final? – Gaurav Feb 15 '19 at 11:35

4 Answers4

80

Update: the provided solution is valid for Log4J 1.x . If you're looking for 2.x versions, take a look at this article: How to create a custom appender in log4j2

You should extend AppenderSkeleton class, that (quoting javadoc) "provides the code for common functionality, such as support for threshold filtering and support for general filters."

If you read the code of AppenderSkeleton, you'll see that it handles almost all, leaving to you just:

  1. protected void append(LoggingEvent event)
  2. public void close()
  3. public boolean requiresLayout()

The core method is append. Remember that you don't need to implement the filtering logic in it because it is already implemented in doAppend that in turn calls append. Here I made a (quite useless) class that stores the log entries in an ArrayList, just as a demo.

public /*static*/ class MyAppender extends AppenderSkeleton {
    ArrayList<LoggingEvent> eventsList = new ArrayList();

    @Override
    protected void append(LoggingEvent event) {
        eventsList.add(event);
    }

    public void close() {
    }

    public boolean requiresLayout() {
        return false;
    }

}

Ok, let's test it:

public static void main (String [] args) {

    Logger l = Logger.getLogger("test");

    MyAppender app = new MyAppender();

    l.addAppender(app);

    l.warn("first");
    l.warn("second");
    l.warn("third");

    l.trace("fourth shouldn't be printed");

    for (LoggingEvent le: app.eventsList) {
        System.out.println("***" + le.getMessage());
    }
} 

You should have "first", "second", "third" printed; the fourth message shouldn't be printed since the log level of root logger is debug while the event level is trace. This proves that AbstractSkeleton implements "level management" correctly for us. So that's definitely seems the way to go... now the question: why do you need a custom appender while there are many built in that log to almost any destination? (btw a good place to start with log4j: http://logging.apache.org/log4j/1.2/manual.html)

AgostinoX
  • 7,477
  • 20
  • 77
  • 137
  • i used the above class,no Error,.. how can i identify new Appender will created?How can i use it? – unknown May 24 '11 at 06:49
  • 3
    From http://logging.apache.org/log4j/1.2/manual.html,"A log request of level p in a logger with (either assigned or inherited, wichever is appropriate) level q, is enabled if p>=q". The log request is of level "trace", while the logger has level set to "debug" which is higher than trace, so won't be logged. Remember that logger isn't assigned a level, so it inherits the level of the root logger. To have the logger log also trace level requests(max verbosity!) you can set either programmatically(l.setLevel(Level.TRACE);) or(better) via property files the level of "logger" or of the root logger. – AgostinoX May 24 '11 at 09:28
  • i created a web service,now i want to cal the web service by using this Appender.how can i cal? – unknown May 25 '11 at 07:55
  • Do you mean how to use this Appender from within the web server? – AgostinoX May 25 '11 at 10:26
  • 1
    I don't know your specific web server. Have you tried the suggestions in "Default Initialization under Tomcat" that comes in http://logging.apache.org/log4j/1.2/manual.html ? – AgostinoX May 25 '11 at 11:57
  • ok, When server is started ,the log files print the output statement..how can i print the that log statement in my own file? – unknown May 25 '11 at 12:01
  • 1
    That's not what you asked in your initial question. If you have create your own Appender subclass, you should provide code for writing to disk. Probably you didn't need a custom Appender class, you only need a FileAppender, that logs on disk out of the box. You just provide the file name. – AgostinoX May 25 '11 at 12:14
  • 1
    @Elakkiya: you're welcome. Have you solved your problem with log4j? Have you extend AppenderSkeleton or used some provided Appender? – AgostinoX Jun 04 '11 at 08:50
  • My problem is here [link](http://stackoverflow.com/questions/6124148/log4jappender-to-print-the-log-statements) – unknown Jun 04 '11 at 11:37
  • Hi do you know how to do this in the newer versions? I am asking since this doesnt work for me now. I get an error that logger doesnt have a function "addAppender". – Tomer May 07 '17 at 15:24
  • How do you do this in log4j2 please answer – UFO_Rider Jan 27 '22 at 17:58
  • I've added a link to the solution for versions 2.x – AgostinoX Jan 29 '22 at 08:46
9

If you would like to do some manipulations or decisions you can do it like this:

@Override
protected void append(LoggingEvent event) {
        String message = null;
        if(event.locationInformationExists()){
            StringBuilder formatedMessage = new StringBuilder();
            formatedMessage.append(event.getLocationInformation().getClassName());
            formatedMessage.append(".");
            formatedMessage.append(event.getLocationInformation().getMethodName());
            formatedMessage.append(":");
            formatedMessage.append(event.getLocationInformation().getLineNumber());
            formatedMessage.append(" - ");
            formatedMessage.append(event.getMessage().toString());
            message = formatedMessage.toString();
        }else{
            message = event.getMessage().toString();
        }

        switch(event.getLevel().toInt()){
        case Level.INFO_INT:
            //your decision
            break;
        case Level.DEBUG_INT: 
            //your decision
            break;
        case Level.ERROR_INT:
            //your decision
            break;
        case Level.WARN_INT:
            //your decision
            break;
        case Level.TRACE_INT:
            //your decision
            break;
        default:
            //your decision
            break;
        }
}
Lior
  • 247
  • 2
  • 6
5

I would like to expend @AgostinoX answer to support pro file configuration and the ability to start and stop the logging capture :

public class StringBufferAppender extends org.apache.log4j.AppenderSkeleton {

    StringBuffer logs = new StringBuffer();
    AtomicBoolean captureMode = new AtomicBoolean(false);

    public void close() {
        // TODO Auto-generated method stub

    }

    public boolean requiresLayout() {
        // TODO Auto-generated method stub
        return false;
    }


    @Override
    protected void append(LoggingEvent event) {
        if(captureMode.get())
            logs.append(event.getMessage());
    }

    public void start()
    {
        //System.out.println("[StringBufferAppender|start] - Start capturing logs");
        StringBuffer logs = new StringBuffer();
        captureMode.set(true);
    }

    public StringBuffer stop()
    {
        //System.out.println("[StringBufferAppender|start] - Stop capturing logs");
        captureMode.set(false);
        StringBuffer data = new StringBuffer(logs);
        logs = null;
        return data;
    }


}

Now all you have to do is to define in in the log4j.property file

log4j.rootLogger=...., myAppender  # here you adding your appendr name
log4j.appender.myAppender=com.roi.log.StringBufferAppender # pointing it to the implementation

than when ever you want to enable it during runtume:

Logger logger = Logger.getRootLogger();
        StringBufferAppender appender = (StringBufferAppender)logger.getAppender("myAppender");
        appender.start();

and while want to stop it:

StringBuffer sb = appender.stop();
USer22999299
  • 5,284
  • 9
  • 46
  • 78
2

To create a own Appender you just implement the Appender Interface and just override it. And also study this link start log

Aleksandr Kravets
  • 5,750
  • 7
  • 53
  • 72
Aabi
  • 31
  • 2