RFR: 8145934: Make ttyLocker equivalent for Unified Logging framework

John Rose john.r.rose at oracle.com
Wed Feb 10 22:43:58 UTC 2016


Thanks for taking this on.

To be an adequate substitute for ttyLocker it needs to
support block structure via the RAII pattern.  Otherwise
the use cases are verbose enough to be a burden on
programmers.

This is easy, I think:  Give LogMessage a constructor
which takes a reference to the corresponding LogHandle.
Have the LogMessage destructor call log.write(*this).

(BTW, as written it allows accidentally dropped writes,
which is bad:  We'll never find all those bugs.  That's
the burden of a rough-edged API, especially when it is
turned off most of the time.)

If necessary or for flexibility, allow the LogMessage
constructor an optional boolean to say "don't write
automatically".  Also, allow a "reset" method to
cancel any buffered writing.  So the default is to
perform the write at the end of the block (if there
is anything to write), but it can be turned off
explicitly.

Giving the LogMessage a clear linkage to a LogHandle
allows the LogMessage to be a simple delegate for
the LogHandle itself.  This allows the user to ignore
the LogHandle and work with the LogMessage as
if it were the LogHandle.  That seems preferable
to requiring split attention to both objects.

Given this simplification, the name LogMessage
could be changed to BufferedLogHandle, LogBuffer,
ScopedLog, etc., to emphasize that the thing is
really a channel to some log, but with an extra
bit of buffering to control.

To amend your example use case:

    // example buffered log messages (proposed)
    LogHandle(logging) log;
    if (log.is_debug()) {
      ResourceMark rm;
      LogMessage msg;
      msg.debug("debug message");
      msg.trace("additional trace information");
      log.write(msg);
    }

Either this:

    // example buffered log messages (amended #1)
    LogHandle(logging) log;
    if (log.is_debug()) {
      ResourceMark rm;
      LogBuffer buf(log);
      buf.debug("debug message");
      buf.trace("additional trace information");
    }

Or this:

    // example buffered log messages (amended #2)
    { LogBuffer(logging) log;
      if (log.is_debug()) {
        ResourceMark rm;
        log.debug("debug message");
        log.trace("additional trace information");
      }
    }

The second is probably preferable, since it encourages the
logging logic to be modularized into a single block, and
because it reduces the changes for error that might occur
from having two similar names (log/msg or log/buf).

The second usage requires the LogBuffer constructor
to be lazy:  It must delay internal memory allocation
until the first output operation.

— John


More information about the hotspot-dev mailing list