14 messages in org.apache.logging.log4j-userRe: Fw: ThreadLocalAppender for log4j...
FromSent OnAttachments
Ramakrishna MenonMar 1, 2004 5:25 pm 
Ceki GülcüMar 2, 2004 2:18 am 
Ramakrishna MenonMar 2, 2004 7:26 am 
Ceki GülcüMar 2, 2004 8:13 am 
Paul SmithMar 2, 2004 11:56 am 
Ramakrishna MenonMar 2, 2004 12:12 pm 
Paul SmithMar 2, 2004 1:22 pm 
Ramakrishna MenonMar 2, 2004 3:33 pm 
Paul SmithMar 2, 2004 3:42 pm 
Ramakrishna MenonMar 2, 2004 4:36 pm 
Ramakrishna MenonJun 23, 2004 9:11 am 
Ramakrishna MenonJun 25, 2004 9:44 am 
Paul SmithJun 27, 2004 2:53 pm 
Ramakrishna MenonJun 28, 2004 8:39 am 
Actions with this message:
Paste this link in email or IM:
Paste this link in email or IM:
Atom feed for this thread
Paste this URL into your reader:
Subject:Re: Fw: ThreadLocalAppender for log4j?resendingActions...
From:Ramakrishna Menon (rama@oracle.com)
Date:Jun 23, 2004 9:11:42 am
List:org.apache.logging.log4j-user

Hi Paul I was supposed to work on this thread and get back to this list but was caught up in other priorities at work. I am now trying to redo some of the investigations I did earlier and also look at adapting your solution. Thought I would summarize what I am thinking of doing (my understanding of log4j is fairly limited - I just know how to get a simple logger up and running with a simple config file:-))

To recall the original issue, it was to log a message on the rendered url. Now in our application we are using log4j to log messages already. I want to intercept these messages and render them in a url based on a flag that is set on the url (or in the session.) Important thing is that a url should get messages only from the request (or thread) that was handled while its rendering.)

Now what I am thinking of doing is to 1. create a class which is an appender that intercepts the messsages and writes it to a StringWriter with which it is initialized. 2. at the beginning of the routine that handles a request, I create a new appender and initialize it with the stringwriter. It appends to the stringwriter any messages that it gets.

3. at the end of the routine request handling routine, I get the stringwriter from the appender and destroy it in a finally clause.

4. In the logging properties file I would add this appender as well ( I am not sure if this is necessary since I create this appender manually ?)

Does that sound right/sane/insane?

Any other comments/thoughts. btw, I remember thinking about using ThreadLocal but dont see it relevant here now - not sure I am missing something I thought earlier :)

Best Regards, Menon:) ------------------------------------------------------------- Ramakrishna M. Menon (A Rafi Fan - http://www.mohdrafi.com ) MBA, Berkeley Oracle Corp.-> (650) 506-2343 http://websites.oraclecorp.com/websites/pub/oracleperformance/ -------------------------------------------------------------

Ok, to get some context to what we did, our App had a MessageListener interface that was used a lot as a Listener callback to pass Informational messages to our GUI (I've put notes in []):

public interface MessageListener extends EventListener { /** * This listener receives a notification */ public void receiveMessage(MessageEvent message); }

[MessageEvent is a trivial class, MessageType=ERROR|INFO|WARN etc, plus a String message, I won't paste it here]

//-----

[Now we needed to adapt this interface to an Appender, here's the appender with the Thread specific filter. Note: convertLog4JToMessageEvent just converts LoggingEvent to MessageEvent]

//----- .... public static final Appender createLog4JAppenderAdpater(MessageListener listener) { return Log4jAppender.create(listener); }

private static final class Log4jAppender extends AppenderSkeleton { private MessageListener listener;

private Log4jAppender(){} public static Log4jAppender create(MessageListener listener) { Log4jAppender appender = new Log4jAppender();

appender.listener = listener;

final Thread threadThatCreatedTheAppender = Thread.currentThread();

appender.addFilter(new Filter(){ public int decide(LoggingEvent event) { if (Thread.currentThread() == threadThatCreatedTheAppender) { return Filter.ACCEPT; } return Filter.DENY; } }); return appender; }

protected void append(LoggingEvent event) { listener.receiveMessage(convertLog4JToMessageEvent(event)); }

public void close() { listener = null; }

public boolean requiresLayout() { return false; } }

// -------------

[Now, at the point of code where you can use this:]

.... Logger loggerWeAreInterestedIn = Logger.getLogger(ClassWayDownHierachy.class);

Appender appender = MessageListenerUtils.createLog4JAppenderAdpater(messageListener);

loggerWeAreInterestedIn.addAppender(appender);

try{ someObject.doSomeMethod(); }finally{ loggerWeAreInterestedIn.removeAppender(appender); }

It's very important to remove the appender in the finally block otherwise you will be adding lots of appenders over time and will leak memory. There is probably a performance hit in doing all this, but sometimes that's better than the alternatives. It's not clean, but it does work. You might want to do something different than adapt the LoggingEvent to another class, but hopefully you can see the pattern.

Hope this helps someone, or is food for further discussion.

regards,