Elias,
How are your changes compatible with log4j 1.3 where layouts write directly to the output stream without intermediary String objects?
At 07:35 PM 9/17/2004, Elias Ross wrote:
I had a created a way to avoid a deadlock condition when Appender is holding on to a lock and rendering an object. In some situations, attempting to log during a toString() causes this. Refer to to Bugzilla bug:
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24159
To understand why this is an issue, here are three statements: 1 Logger.debug(this); 2 Logger.debug(this.toString()); 3 if (Logger.isDebugEnabled()) Logger.debug(this.toString());
1 - Does not call Object.toString until the last minute. This is good because if debug is disabled, creates no overhead. Additionally, if the Logger's threshold is DEBUG and no appender wants the event, then creates no overload 2 - Creates overhead 3 - Creates no overhead if the logger threshold is above DEBUG
It is possible to call Format without locking the appender.
My proposed changes work (and probably would improve concurrency because locking happens less often and during a Format) but I can understand wanting to preserve compatibility so changing AppenderSkeleton might be inappropriate. How about creating a AppenderSupport or AppenderBase?
It's also better design (IMHO) to factor canAppend into its own method.
Here are the overview changes:
* Add "protected boolean canAppend()" method. Subclasses override as appropriate. * Call canAppend before formatting (holding lock on "this") * Format the message (no need to lock yet...) * Synchronize on "this", check canAppend again. Log4J might just ignore this step and try to log anyway. If there's an Exception (like the writer was closed) then it's no big deal, Log4J just catches it and move on. * Call writer.write(String)
This is the subAppend from WriterAppender that does not lock:
protected void subAppend(LoggingEvent event) { Layout l = this.layout; if (l == null) { errorHandler.error( "No layout set for the appender named [" + name + "]."); return; } String fe = l.format(event); String s[] = null; if (l.ignoresThrowable()) { s = event.getThrowableStrRep(); }
// Could be moved to its own synchronized method synchronized (this) { if (!canAppend(event)) return; this.qw.write(fe); if (s != null) { int len = s.length; for (int i = 0; i < len; i++) { this.qw.write(s[i]); this.qw.write(Layout.LINE_SEP); } } if (this.immediateFlush) { this.qw.flush(); } } }
-- Ceki G�lc�
For log4j documentation consider "The complete log4j manual"
ISBN: 2970036908 http://www.qos.ch/shop/products/clm_t.jsp
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
