Skip to content

Commit 1f624eb

Browse files
committed
clarify MDC context propagation
1 parent cc51a55 commit 1f624eb

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

docs/adrs/006-logging-strategy.md

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ The SDK uses SLF4J API for all logging statements.
5050
Throughout this document, the term 'request' refers to a single SDK operation that calls an AI service (e.g., `OrchestrationClient.chatCompletion()`, `OpenAiClient.embed()`), distinct from HTTP requests to the user's application.
5151
5252
* **Exception logging.**
53-
When logging exceptions, use standard logging methods (e.g., `log.error("Operation failed", exception)`) rather than serializing exception objects.
53+
When logging exceptions, use standard logging methods (e.g., `log.debug("Connection lost.", exception)`) rather than serializing exception objects.
5454
Exception objects may contain custom fields with sensitive data that could be exposed through JSON serialization or custom `toString()` implementations.
5555
5656
* **Logging framework**
@@ -156,24 +156,33 @@ The SDK uses SLF4J API for all logging statements.
156156

157157
* **Safe consumption.**
158158
Since MDC uses `ThreadLocal` storage, any new thread (created implicitly or explicitly) will not have access to the parent thread's MDC context.
159-
Always audit for possible thread switches that may lead to corrupted logs due to invalid MDC.
160-
Below is an example contrasting safe usage (logging in the calling thread) with unsafe usage (logging in callbacks):
159+
Always audit for thread switches through async operations, resilience patterns etc., as these may lead to corrupted logs due to invalid MDC.
161160

162161
```java
163162
// Thread A
164163
RequestLogContext.setCallId("abc123");
165164
log.debug("[callId={}] Starting request", RequestLogContext.get(MdcKeys.CALL_ID));
166165

167-
// Bad: Logging within callbacks executed in other threads
166+
// Problem: Async callback runs in Thread B without original MDC context
168167
client.executeAsync(() -> {
169-
// Thread B: RequestLogContext.get(MdcKeys.CALL_ID) is null
168+
// Thread B: RequestLogContext.get(MdcKeys.CALL_ID) returns null
170169
log.debug("[callId={}] Processing", RequestLogContext.get(MdcKeys.CALL_ID));
171170
});
172-
173-
// Good: Thread A's context has been restored
174-
log.debug("[callId={}] Completed request", RequestLogContext.get(MdcKeys.CALL_ID));
175171
```
176172

173+
To maintain logging context across thread boundaries, manually propagate the MDC context:
174+
175+
```java
176+
// Capture parent thread's MDC context
177+
Map<String, String> context = MDC.getCopyOfContextMap();
178+
179+
client.executeAsync(() -> {
180+
// Restore the captured context in new thread
181+
MDC.setContextMap(context);
182+
// Thread B: RequestLogContext.get(MdcKeys.CALL_ID) returns abc123
183+
log.debug("[callId={}] Processing", RequestLogContext.get(MdcKeys.CALL_ID));
184+
});
185+
```
177186
---
178187

179188
### 4. Logging Boundaries and Generation

0 commit comments

Comments
 (0)