or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

appenders.mdbuilders.mdconfiguration.mdcontext.mdindex.mdlayouts.mdlogging.mdspi.md

context.mddocs/

0

# Thread Context

1

2

Thread context provides thread-local diagnostic information storage through MDC (Mapped Diagnostic Context) and NDC (Nested Diagnostic Context). This enables context-aware logging across application threads.

3

4

## Mapped Diagnostic Context (MDC)

5

6

### MDC Class

7

8

```java { .api }

9

public final class MDC {

10

// Context management

11

public static void put(String key, String value);

12

public static Object get(String key);

13

public static String get(String key, String defaultValue);

14

public static void remove(String key);

15

public static void clear();

16

17

// Context retrieval

18

public static Hashtable<String, Object> getContext();

19

public static Map<String, String> getCopyOfContextMap();

20

public static void setContextMap(Map<String, String> contextMap);

21

22

// Utility methods

23

public static Set<String> getKeys();

24

public static boolean isEmpty();

25

}

26

```

27

28

**Parameters:**

29

- `key` - String key for the context value

30

- `value` - String value to store

31

- `defaultValue` - String default value if key not found

32

- `contextMap` - Map of context key-value pairs

33

34

**Returns:**

35

- `Object` or `String` value for the specified key

36

- `Hashtable<String, Object>` current context

37

- `Map<String, String>` copy of context map

38

- `Set<String>` set of all keys

39

- `boolean` indicating if context is empty

40

41

## Nested Diagnostic Context (NDC)

42

43

### NDC Class

44

45

```java { .api }

46

public final class NDC {

47

// Stack operations

48

public static void push(String message);

49

public static String pop();

50

public static String peek();

51

public static void clear();

52

public static void remove();

53

54

// Stack information

55

public static int getDepth();

56

public static Stack cloneStack();

57

public static void inherit(Stack stack);

58

59

// Formatting

60

public static String get();

61

}

62

```

63

64

**Parameters:**

65

- `message` - String message to push onto the stack

66

- `stack` - Stack to inherit from another thread

67

68

**Returns:**

69

- `String` popped or peeked message

70

- `int` current stack depth

71

- `Stack` cloned copy of current stack

72

- `String` formatted NDC string

73

74

## MDC Usage Patterns

75

76

### Basic MDC Operations

77

```java

78

import org.apache.log4j.MDC;

79

import org.apache.log4j.Logger;

80

81

public class MDCExample {

82

private static final Logger logger = Logger.getLogger(MDCExample.class);

83

84

public void processUserRequest(String userId, String sessionId) {

85

// Set context information

86

MDC.put("userId", userId);

87

MDC.put("sessionId", sessionId);

88

MDC.put("operation", "processRequest");

89

90

try {

91

logger.info("Starting user request processing");

92

93

// Business logic

94

processBusinessLogic();

95

96

logger.info("User request completed successfully");

97

} catch (Exception e) {

98

logger.error("User request failed", e);

99

} finally {

100

// Clean up context

101

MDC.clear();

102

}

103

}

104

105

private void processBusinessLogic() {

106

// This method can access MDC context

107

String userId = (String) MDC.get("userId");

108

logger.debug("Processing business logic for user: " + userId);

109

110

// Add more context

111

MDC.put("step", "validation");

112

validateUserData();

113

114

MDC.put("step", "processing");

115

performProcessing();

116

117

MDC.remove("step");

118

}

119

120

private void validateUserData() {

121

logger.debug("Validating user data");

122

}

123

124

private void performProcessing() {

125

logger.debug("Performing main processing");

126

}

127

}

128

```

129

130

### Web Application MDC Filter

131

```java

132

import org.apache.log4j.MDC;

133

import javax.servlet.*;

134

import javax.servlet.http.HttpServletRequest;

135

import java.io.IOException;

136

import java.util.UUID;

137

138

public class MDCFilter implements Filter {

139

140

@Override

141

public void doFilter(ServletRequest request, ServletResponse response,

142

FilterChain chain) throws IOException, ServletException {

143

144

HttpServletRequest httpRequest = (HttpServletRequest) request;

145

146

try {

147

// Set request-specific context

148

MDC.put("requestId", UUID.randomUUID().toString());

149

MDC.put("remoteAddr", request.getRemoteAddr());

150

MDC.put("requestURI", httpRequest.getRequestURI());

151

MDC.put("method", httpRequest.getMethod());

152

153

// Add user context if available

154

String userId = httpRequest.getRemoteUser();

155

if (userId != null) {

156

MDC.put("userId", userId);

157

}

158

159

// Continue filter chain

160

chain.doFilter(request, response);

161

162

} finally {

163

// Always clean up MDC

164

MDC.clear();

165

}

166

}

167

168

@Override

169

public void init(FilterConfig filterConfig) throws ServletException {

170

// Filter initialization

171

}

172

173

@Override

174

public void destroy() {

175

// Filter cleanup

176

}

177

}

178

```

179

180

### MDC Context Map Operations

181

```java

182

import org.apache.log4j.MDC;

183

import java.util.Map;

184

import java.util.HashMap;

185

186

public class MDCContextExample {

187

188

public void demonstrateContextOperations() {

189

// Set individual values

190

MDC.put("user", "john");

191

MDC.put("session", "abc123");

192

MDC.put("operation", "login");

193

194

// Get context copy

195

Map<String, String> contextCopy = MDC.getCopyOfContextMap();

196

System.out.println("Current context: " + contextCopy);

197

198

// Check if context is empty

199

boolean isEmpty = MDC.isEmpty();

200

System.out.println("Context empty: " + isEmpty);

201

202

// Get all keys

203

Set<String> keys = MDC.getKeys();

204

System.out.println("Context keys: " + keys);

205

206

// Create new context map

207

Map<String, String> newContext = new HashMap<>();

208

newContext.put("service", "authentication");

209

newContext.put("version", "1.0");

210

211

// Replace entire context

212

MDC.setContextMap(newContext);

213

214

// Verify change

215

System.out.println("New context: " + MDC.getCopyOfContextMap());

216

217

// Clear all

218

MDC.clear();

219

}

220

}

221

```

222

223

## NDC Usage Patterns

224

225

### Basic NDC Operations

226

```java

227

import org.apache.log4j.NDC;

228

import org.apache.log4j.Logger;

229

230

public class NDCExample {

231

private static final Logger logger = Logger.getLogger(NDCExample.class);

232

233

public void processOrder(String orderId) {

234

NDC.push("OrderService");

235

NDC.push("orderId=" + orderId);

236

237

try {

238

logger.info("Starting order processing");

239

240

validateOrder();

241

processPayment();

242

fulfillOrder();

243

244

logger.info("Order processing completed");

245

} catch (Exception e) {

246

logger.error("Order processing failed", e);

247

} finally {

248

// Pop all contexts for this operation

249

NDC.pop(); // Remove orderId

250

NDC.pop(); // Remove OrderService

251

}

252

}

253

254

private void validateOrder() {

255

NDC.push("validation");

256

try {

257

logger.debug("Validating order details");

258

// Validation logic

259

} finally {

260

NDC.pop();

261

}

262

}

263

264

private void processPayment() {

265

NDC.push("payment");

266

try {

267

logger.debug("Processing payment");

268

// Payment logic

269

} finally {

270

NDC.pop();

271

}

272

}

273

274

private void fulfillOrder() {

275

NDC.push("fulfillment");

276

try {

277

logger.debug("Fulfilling order");

278

// Fulfillment logic

279

} finally {

280

NDC.pop();

281

}

282

}

283

}

284

```

285

286

### NDC Stack Management

287

```java

288

import org.apache.log4j.NDC;

289

import org.apache.log4j.Logger;

290

import java.util.Stack;

291

292

public class NDCStackExample {

293

private static final Logger logger = Logger.getLogger(NDCStackExample.class);

294

295

public void demonstrateStackOperations() {

296

// Build up context stack

297

NDC.push("Application");

298

NDC.push("UserService");

299

NDC.push("createUser");

300

301

// Check stack depth

302

int depth = NDC.getDepth();

303

logger.info("Current NDC depth: " + depth);

304

305

// Peek at top without removing

306

String top = NDC.peek();

307

logger.info("Top of stack: " + top);

308

309

// Get full NDC string

310

String fullContext = NDC.get();

311

logger.info("Full NDC context: " + fullContext);

312

313

// Clone stack for another thread

314

Stack<String> stackCopy = NDC.cloneStack();

315

316

// Pop one level

317

String popped = NDC.pop();

318

logger.info("Popped: " + popped);

319

logger.info("Remaining context: " + NDC.get());

320

321

// Clear all

322

NDC.clear();

323

logger.info("After clear, depth: " + NDC.getDepth());

324

325

// Restore from clone

326

NDC.inherit(stackCopy);

327

logger.info("After inherit: " + NDC.get());

328

329

// Final cleanup

330

NDC.remove();

331

}

332

}

333

```

334

335

### Thread Context Inheritance

336

```java

337

import org.apache.log4j.MDC;

338

import org.apache.log4j.NDC;

339

import org.apache.log4j.Logger;

340

import java.util.Map;

341

import java.util.Stack;

342

import java.util.concurrent.ExecutorService;

343

import java.util.concurrent.Executors;

344

345

public class ThreadContextInheritance {

346

private static final Logger logger = Logger.getLogger(ThreadContextInheritance.class);

347

348

public void processWithThreads() {

349

// Set up context in main thread

350

MDC.put("mainThread", "true");

351

MDC.put("operation", "multiThreadProcess");

352

NDC.push("MainProcessor");

353

354

// Capture context for inheritance

355

Map<String, String> mdcContext = MDC.getCopyOfContextMap();

356

Stack ndcStack = NDC.cloneStack();

357

358

ExecutorService executor = Executors.newFixedThreadPool(3);

359

360

for (int i = 0; i < 3; i++) {

361

final int taskId = i;

362

executor.submit(() -> {

363

try {

364

// Inherit context from parent thread

365

MDC.setContextMap(mdcContext);

366

NDC.inherit(ndcStack);

367

368

// Add thread-specific context

369

MDC.put("threadId", String.valueOf(taskId));

370

NDC.push("Worker-" + taskId);

371

372

logger.info("Processing task in worker thread");

373

374

// Simulate work

375

Thread.sleep(1000);

376

377

logger.info("Task completed in worker thread");

378

379

} catch (InterruptedException e) {

380

logger.warn("Thread interrupted", e);

381

} finally {

382

// Clean up thread context

383

MDC.clear();

384

NDC.remove();

385

}

386

});

387

}

388

389

executor.shutdown();

390

391

// Clean up main thread context

392

MDC.clear();

393

NDC.clear();

394

}

395

}

396

```

397

398

## Pattern Layout Integration

399

400

### Using MDC in Pattern Layouts

401

```java

402

import org.apache.log4j.*;

403

404

public class ContextPatternExample {

405

406

public void setupContextLogging() {

407

// Pattern that includes MDC values

408

PatternLayout mdcPattern = new PatternLayout(

409

"%d{ISO8601} [%t] %-5p %c - [%X{userId}:%X{sessionId}] %m%n"

410

);

411

412

// Pattern that includes specific MDC keys

413

PatternLayout specificMDC = new PatternLayout(

414

"%d %-5p %c - User:%X{userId} Session:%X{sessionId} - %m%n"

415

);

416

417

// Pattern that includes NDC

418

PatternLayout ndcPattern = new PatternLayout(

419

"%d %-5p %c %x - %m%n"

420

);

421

422

// Pattern with both MDC and NDC

423

PatternLayout combinedPattern = new PatternLayout(

424

"%d [%t] %-5p %c - %X{userId} %x - %m%n"

425

);

426

427

// Create appenders

428

ConsoleAppender mdcAppender = new ConsoleAppender(mdcPattern);

429

ConsoleAppender ndcAppender = new ConsoleAppender(ndcPattern);

430

431

// Configure loggers

432

Logger mdcLogger = Logger.getLogger("mdc-logger");

433

mdcLogger.addAppender(mdcAppender);

434

435

Logger ndcLogger = Logger.getLogger("ndc-logger");

436

ndcLogger.addAppender(ndcAppender);

437

}

438

}

439

```

440

441

## Best Practices

442

443

### Context Cleanup Patterns

444

```java

445

import org.apache.log4j.MDC;

446

import org.apache.log4j.NDC;

447

import org.apache.log4j.Logger;

448

449

public class ContextCleanupExample {

450

private static final Logger logger = Logger.getLogger(ContextCleanupExample.class);

451

452

// Using try-with-resources pattern for MDC

453

public static class MDCCloseable implements AutoCloseable {

454

public MDCCloseable(String key, String value) {

455

MDC.put(key, value);

456

}

457

458

@Override

459

public void close() {

460

MDC.clear();

461

}

462

}

463

464

// Using try-with-resources pattern for NDC

465

public static class NDCCloseable implements AutoCloseable {

466

public NDCCloseable(String context) {

467

NDC.push(context);

468

}

469

470

@Override

471

public void close() {

472

NDC.pop();

473

}

474

}

475

476

public void processWithAutoCleanup(String userId, String operation) {

477

// MDC with automatic cleanup

478

try (MDCCloseable mdcContext = new MDCCloseable("userId", userId)) {

479

MDC.put("operation", operation);

480

481

// NDC with automatic cleanup

482

try (NDCCloseable ndcContext = new NDCCloseable("ProcessorService")) {

483

484

logger.info("Starting processing with auto-cleanup");

485

486

// Business logic here

487

performBusinessLogic();

488

489

logger.info("Processing completed");

490

491

} // NDC automatically popped here

492

} // MDC automatically cleared here

493

}

494

495

// Manual cleanup with finally blocks

496

public void processWithManualCleanup(String userId, String operation) {

497

// Set up MDC

498

MDC.put("userId", userId);

499

MDC.put("operation", operation);

500

501

// Set up NDC

502

NDC.push("ManualService");

503

504

try {

505

logger.info("Starting processing with manual cleanup");

506

507

performBusinessLogic();

508

509

logger.info("Processing completed");

510

511

} catch (Exception e) {

512

logger.error("Processing failed", e);

513

throw e;

514

} finally {

515

// Always clean up in reverse order

516

NDC.pop(); // Remove ManualService

517

MDC.clear(); // Clear all MDC values

518

}

519

}

520

521

private void performBusinessLogic() {

522

// This method inherits the context

523

logger.debug("Performing business logic");

524

525

// Can add temporary context

526

MDC.put("step", "validation");

527

NDC.push("validator");

528

529

try {

530

logger.debug("Validating input");

531

// Validation logic

532

} finally {

533

// Clean up temporary context

534

NDC.pop();

535

MDC.remove("step");

536

}

537

}

538

}

539

```

540

541

### Context Performance Considerations

542

```java

543

import org.apache.log4j.MDC;

544

import org.apache.log4j.Logger;

545

546

public class ContextPerformanceExample {

547

private static final Logger logger = Logger.getLogger(ContextPerformanceExample.class);

548

549

public void efficientContextUsage() {

550

// Avoid expensive operations in context values

551

String userId = getCurrentUserId(); // Expensive call

552

MDC.put("userId", userId); // Store result, don't call repeatedly

553

554

// Use conditional logging to avoid context lookups

555

if (logger.isDebugEnabled()) {

556

String contextInfo = buildContextInfo(); // Only when needed

557

logger.debug("Context info: " + contextInfo);

558

}

559

560

// Prefer specific key access over full context maps

561

String user = (String) MDC.get("userId"); // Efficient

562

// Map<String, String> fullContext = MDC.getCopyOfContextMap(); // Less efficient

563

564

// Clean up promptly to avoid memory leaks

565

MDC.clear();

566

}

567

568

private String getCurrentUserId() {

569

// Simulate expensive operation

570

return "user123";

571

}

572

573

private String buildContextInfo() {

574

// Build debug info only when needed

575

return "User: " + MDC.get("userId") + ", Session: " + MDC.get("sessionId");

576

}

577

}

578

```