0
# Diagnostic Contexts
1
2
Mapped Diagnostic Context (MDC) and Nested Diagnostic Context (NDC) for adding contextual information to log messages. Both contexts bridge to SLF4J's MDC mechanism for thread-local diagnostic data.
3
4
## Capabilities
5
6
### Mapped Diagnostic Context (MDC)
7
8
Thread-local key-value storage for contextual information that can be included in log messages. All operations delegate to SLF4J's MDC.
9
10
```java { .api }
11
/**
12
* Put a key-value pair in the MDC
13
* @param key The key
14
* @param value The value as String
15
*/
16
public static void put(String key, String value);
17
18
/**
19
* Put a key-value pair in the MDC (Object converted to String)
20
* @param key The key
21
* @param value The value as Object (converted to String via toString())
22
*/
23
public static void put(String key, Object value);
24
25
/**
26
* Get value by key from MDC
27
* @param key The key to lookup
28
* @return The value or null if not found
29
*/
30
public static Object get(String key);
31
32
/**
33
* Remove key-value pair from MDC
34
* @param key The key to remove
35
*/
36
public static void remove(String key);
37
38
/**
39
* Clear all MDC data for current thread
40
*/
41
public static void clear();
42
43
/**
44
* Get MDC context as Hashtable (deprecated)
45
* @return Copy of MDC context as Hashtable
46
* @deprecated This method may be removed in future versions
47
*/
48
@Deprecated
49
public static Hashtable<String, String> getContext();
50
```
51
52
**Usage Examples:**
53
54
```java
55
import org.apache.log4j.MDC;
56
import org.apache.log4j.Logger;
57
58
Logger logger = Logger.getLogger(MyClass.class);
59
60
// Set context information
61
MDC.put("userId", "12345");
62
MDC.put("sessionId", "abc-def-ghi");
63
MDC.put("requestId", UUID.randomUUID().toString());
64
65
// Log messages will include MDC context (if configured in SLF4J implementation)
66
logger.info("Processing user request");
67
68
// Can put different types (converted to String)
69
MDC.put("timestamp", System.currentTimeMillis());
70
MDC.put("userRole", UserRole.ADMIN);
71
72
// Retrieve values
73
String userId = (String) MDC.get("userId");
74
String sessionId = (String) MDC.get("sessionId");
75
76
// Remove specific key
77
MDC.remove("requestId");
78
79
// Clear all context for thread
80
MDC.clear();
81
82
// Example in web application filter
83
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
84
try {
85
// Set context for request
86
MDC.put("requestId", generateRequestId());
87
MDC.put("remoteAddr", request.getRemoteAddr());
88
89
chain.doFilter(request, response);
90
} finally {
91
// Always clean up
92
MDC.clear();
93
}
94
}
95
```
96
97
### Nested Diagnostic Context (NDC)
98
99
Stack-based diagnostic context for hierarchical information. Implemented using SLF4J's MDC with numbered keys.
100
101
```java { .api }
102
/**
103
* NDC key prefix used for MDC storage
104
*/
105
public static final String PREFIX = "NDC";
106
107
/**
108
* Push a message onto the NDC stack
109
* @param message Message to push
110
*/
111
public static void push(String message);
112
113
/**
114
* Pop the top message from NDC stack
115
* @return The popped message or empty string if stack is empty
116
*/
117
public static String pop();
118
119
/**
120
* Peek at the top message without removing it
121
* @return The top message or empty string if stack is empty
122
*/
123
public static String peek();
124
125
/**
126
* Get current depth of NDC stack
127
* @return Stack depth
128
*/
129
public static int getDepth();
130
131
/**
132
* Clear all NDC data for current thread
133
*/
134
public static void clear();
135
136
/**
137
* Get NDC string (always returns null in this implementation)
138
* @return null
139
*/
140
public static String get();
141
142
/**
143
* Remove all NDC data (same as clear())
144
*/
145
public static void remove();
146
147
/**
148
* Clone NDC stack (always returns null in this implementation)
149
* @return null
150
*/
151
public static Stack<?> cloneStack();
152
153
/**
154
* Inherit NDC stack from another thread (no-op in this implementation)
155
* @param stack Stack to inherit from
156
*/
157
public static void inherit(Stack<?> stack);
158
159
/**
160
* Set maximum NDC depth (no-op in this implementation)
161
* @param maxDepth Maximum depth
162
*/
163
public static void setMaxDepth(int maxDepth);
164
```
165
166
**Usage Examples:**
167
168
```java
169
import org.apache.log4j.NDC;
170
import org.apache.log4j.Logger;
171
172
Logger logger = Logger.getLogger(MyClass.class);
173
174
// Build nested context
175
NDC.push("UserService");
176
logger.info("Starting user operation"); // Context: [UserService]
177
178
NDC.push("validateUser");
179
logger.debug("Validating user credentials"); // Context: [UserService, validateUser]
180
181
NDC.push("checkDatabase");
182
logger.debug("Querying user database"); // Context: [UserService, validateUser, checkDatabase]
183
184
// Check depth
185
int depth = NDC.getDepth(); // 3
186
187
// Peek without removing
188
String current = NDC.peek(); // "checkDatabase"
189
190
// Pop as operations complete
191
String finished = NDC.pop(); // "checkDatabase", depth now 2
192
logger.debug("Database check completed"); // Context: [UserService, validateUser]
193
194
NDC.pop(); // "validateUser", depth now 1
195
logger.info("User validation completed"); // Context: [UserService]
196
197
NDC.pop(); // "UserService", depth now 0
198
logger.info("User operation completed"); // Context: []
199
200
// Clear all context
201
NDC.clear();
202
203
// Example in method call hierarchy
204
public void processOrder(Order order) {
205
NDC.push("processOrder(" + order.getId() + ")");
206
try {
207
logger.info("Processing order");
208
validateOrder(order);
209
saveOrder(order);
210
notifyCustomer(order);
211
} finally {
212
NDC.pop();
213
}
214
}
215
216
private void validateOrder(Order order) {
217
NDC.push("validateOrder");
218
try {
219
logger.debug("Validating order data");
220
// validation logic
221
} finally {
222
NDC.pop();
223
}
224
}
225
```
226
227
### Context Best Practices
228
229
Guidelines for effective use of diagnostic contexts.
230
231
**MDC Best Practices:**
232
233
```java
234
// Use try-finally to ensure cleanup
235
public void handleRequest(HttpServletRequest request) {
236
try {
237
MDC.put("requestId", generateRequestId());
238
MDC.put("userId", getCurrentUserId());
239
240
// Process request
241
processRequest(request);
242
243
} finally {
244
// Always clean up to prevent memory leaks
245
MDC.clear();
246
}
247
}
248
249
// Use meaningful, consistent key names
250
MDC.put("user.id", userId);
251
MDC.put("session.id", sessionId);
252
MDC.put("request.method", request.getMethod());
253
MDC.put("request.uri", request.getRequestURI());
254
```
255
256
**NDC Best Practices:**
257
258
```java
259
// Use try-finally pattern for NDC as well
260
public void complexOperation() {
261
NDC.push("complexOperation");
262
try {
263
logger.info("Starting complex operation");
264
265
subOperation1();
266
subOperation2();
267
268
logger.info("Complex operation completed");
269
} finally {
270
NDC.pop();
271
}
272
}
273
274
// Use descriptive context names
275
NDC.push("OrderService.processPayment");
276
NDC.push("PaymentGateway.authorizeCard");
277
NDC.push("BankAPI.validateAccount");
278
```
279
280
**Combined Usage:**
281
282
```java
283
// MDC for request-wide context, NDC for call hierarchy
284
public void processUserRequest(String userId, String operation) {
285
try {
286
// Set request context with MDC
287
MDC.put("userId", userId);
288
MDC.put("operation", operation);
289
MDC.put("timestamp", Instant.now().toString());
290
291
// Track call hierarchy with NDC
292
NDC.push("processUserRequest");
293
294
logger.info("Processing user request");
295
performOperation(operation);
296
297
} finally {
298
NDC.clear();
299
MDC.clear();
300
}
301
}
302
```