Class LogContext

java.lang.Object
org.apache.juneau.commons.logging.LogContext

public final class LogContext extends Object
A thread-confined, MDC-style key/value context whose entries are auto-attached to every LogRecord emitted by a RichLogger on the same thread while a scope is open.

There is exactly one context per thread, shared across every RichLogger name — attachment happens in the single central interception point (RichLogger.log(java.util.logging.LogRecord)), not per logger instance. The "on RichLogger" framing is about API home (RichLogger.context()), not about per-instance scoping.

Usage:

try (LogContext.Scope c = RichLogger.context().with("requestId", id)) { // Every record logged in this scope automatically carries requestId. logger.info("processing"); }

Nesting semantics:

Classic MDC save/restore: with(String, Object) records the key's previous value (or "absent") before overwriting, and LogContext.Scope.close() restores exactly that prior state — never a blanket clear. Nested scopes on the same key are safe: closing the inner scope restores the outer value, not the empty state. with(Map) restores all entries in one LogContext.Scope.close().

Null policy:

with(String, Object) rejects a null key. A null value means "remove this key for the scope's duration" — a null is never stored, so snapshot() (an immutable copy) never blows up on a null key or value.

Thread confinement (v1):

This context is thread-confined only. It is not inherited by child threads, not propagated across executor or CompletableFuture boundaries, and is not SLF4J MDC and is not restored by MdcAsyncListener. Apps that rely on SLF4J MDC on an async-completion thread keep it; apps that rely on LogContext do not (except the REST debug-pipeline completion record, which carries it explicitly).

Scope discipline:

A LogContext.Scope must be closed on the same thread that opened it (use try-with-resources). A forgotten LogContext.Scope.close() leaves the entry live on that thread and is visible on the next get(String) on the same thread — the leak is the caller's, not the framework's.

See Also:
  • Method Details

    • with

      public LogContext.Scope with(String key, Object value)
      Opens a scope that sets a single entry.
      Parameters:
      key - The entry key. Must not be null.
      value - The entry value. A null value removes the key for the scope's duration.
      Returns:
      A scope that restores the prior state of this key on LogContext.Scope.close(). Never null.
    • with

      public LogContext.Scope with(Map<String,Object> entries)
      Opens a scope that sets a batch of entries atomically.

      All entries are restored to their prior state in one LogContext.Scope.close() (not N chained scopes), so a batch caller does not need nested try-with-resources for multiple keys set together.

      Parameters:
      entries - The entries to set. Must not be null and must not contain a null key. A null value removes that key for the scope's duration.
      Returns:
      A scope that restores the prior state of all supplied keys on LogContext.Scope.close(). Never null.
    • get

      public Object get(String key)
      Returns the current value for the specified key on this thread.
      Parameters:
      key - The entry key.
      Returns:
      The value, or null if not set on this thread.
    • snapshot

      Returns an immutable snapshot of this thread's context at this instant.
      Returns:
      An immutable copy of the current entries, or the shared empty Map.of() singleton when empty.