Custom logging to gather messages at runtime

java, log4j

Solution

It's absolutely possible - although you're probably going to need to create your own Appender. This is really easy to do, though. Here's a rough-out of an example (need to think out thread-safety...this isn't threadsafe....and I'm not sure I like the statics...but this should be good enough to push you in the right direction):

public class BufferAppender extends org.apache.log4j.AppenderSkeleton {
    private static Map<String, StringBuffer> buffers = new HashMap<String, StringBuffer>();

    @Override
    protected void append(LoggingEvent evt) {
        String toAppend = this.layout.format(evt);
        StringBuffer sb = getBuffer(evt.getLoggerName());
        buffer.append(toAppend);
    }

    public static String getBufferContents(String loggerName) {
            StringBuffer sb = buffers.get(sb);
            if(sb == null) {
               return null;
            } else {
               return sb.toString();
            }
    }

    public static void clearBuffer(String loggerName) {
            createBuffer(loggerName);
    }

    private static StringBuffer getBuffer(String loggerName) {
       StringBuffer sb = buffers.get(loggerName);
       if(sb == null) {
            sb = createBuffer(loggerName);
       }
       return sb;
    }

    private static StringBuffer createBuffer(String loggerName) {
       StringBuffer sb = new StringBuffer();
       buffers.put(loggerName, sb);
       return sb;
    }
}

Problem

Is there a way to create a log4j Logger at runtime that will gather logging messages into a buffer? I currently have a class that logs a number of events. For a remote application that needs to monitor the logged events, I'd like to just swap in a logger that logs to a buffer and then retrieve the buffer, rather than refactor the class. E.g. given something like: ``` Class Foo{ Logger log = ....; public void doSomething(){ log.debug(... .. actual code log.debug(... } } ``` //what I'd like to do from some outside code: ``` String showFooLog(){ Foo f = new Foo(); f.log=new Logger(... f.doSomething(); return f.log.contents(); } ``` Is this possible? Edit: Found a shorter solution, pointed to from Jared's posting( although it's still not threadsafe). Thanks for the help. ``` Logger l = Logger.getLogger( ... ); StringWriter writer = new StringWriter(); WriterAppender appender = new WriterAppender( new HTMLLayout(), writer ); l.addAppender( appender ); ... run code here writer.flush(); l.removeAppender( appender ); return writer.toString() ```

Original source

Related problems