Package com.tnsai.observability.events
Class AgentContext
java.lang.Object
com.tnsai.observability.events.AgentContext
Thread-local container for the current
EventContext.
Framework entry points (e.g. Agent.chat, Tool.execute,
McpClient.request) push an EventContext for the duration
of their work using enter(EventContext) in a try-with-resources
block. Any AgentEventPublisher.publish(...) or
logger.info(...) call inside the block automatically picks up the
context — the former via currentOptional(), the latter via
SLF4J MDC which is kept in sync.
Why thread-local + MDC
Two mechanisms because two consumers:AgentEventpublishers (structured) readcurrentOptional()to attach typed correlation fields.- SLF4J / Logback / Logstash JSON encoders read MDC to enrich
unstructured log lines (third-party library logs, consumer
logger.info(...)). Synced one-way: context → MDC.
Async boundaries
Thread-local is not propagated automatically across thread boundaries. Usewrap(Runnable) / wrap(Callable) when handing work
to ExecutorService, CompletableFuture,
or virtual-thread StructuredTaskScope. The wrapper captures the
caller's context and restores it on the worker thread, then clears.
Nesting
Scopes nest naturally: an outer agent scope can wrap an inner tool scope, which can wrap an inner LLM scope. Eachenter(EventContext) stashes
the previous value and restores it on close. There is no global stack —
each thread has at most one current context, with restoration order
enforced by the try-with-resources structure.- Since:
- 0.5.0 (issue #78)
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classAutoCloseable returned byenter(EventContext)— restores the previous context (or clears entirely if none was active) on close. -
Method Summary
Modifier and TypeMethodDescriptionstatic EventContextcurrent()static Optional<EventContext> static AgentContext.Scopeenter(EventContext ctx) Pushes the given context for the lifetime of the returnedAgentContext.Scope.static RunnableCaptures the current context and returns aRunnablethat runstaskwith that context applied on whatever thread executes it.static <T> Callable<T> Callable variant ofwrap(Runnable).
-
Method Details
-
current
- Returns:
- current context for this thread.
- Throws:
IllegalStateException- if no context is active. PrefercurrentOptional()for callers that may run outside a framework entry point (test utilities, off-thread callbacks).
-
currentOptional
- Returns:
- current context for this thread, empty if no scope is active. Safe to call from any thread.
-
enter
Pushes the given context for the lifetime of the returnedAgentContext.Scope. Restores the previous context (or clears, if none) onAgentContext.Scope.close().Standard usage:
try (var ignored = AgentContext.enter(ctx)) { // body — every event published or log line emitted in this scope // automatically carries `ctx` correlation fields. } -
wrap
Captures the current context and returns aRunnablethat runstaskwith that context applied on whatever thread executes it. Restores the calling-thread state after the task completes (or fails).Use when handing work to an
ExecutororCompletableFuture.supplyAsync(...)so log lines from the worker carry the right correlation IDs. -
wrap
Callable variant ofwrap(Runnable).
-