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]



Reply via email to