1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j;
19
20 import java.io.Serializable;
21 import java.util.AbstractCollection;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.NoSuchElementException;
28
29 import org.apache.logging.log4j.message.ParameterizedMessage;
30 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
31 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
32 import org.apache.logging.log4j.spi.Provider;
33 import org.apache.logging.log4j.spi.ThreadContextMap;
34 import org.apache.logging.log4j.spi.ThreadContextStack;
35 import org.apache.logging.log4j.status.StatusLogger;
36 import org.apache.logging.log4j.util.PropertiesUtil;
37 import org.apache.logging.log4j.util.ProviderUtil;
38
39
40
41
42
43
44
45
46 public final class ThreadContext {
47
48
49
50
51 private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack {
52
53 private static final long serialVersionUID = 1L;
54
55 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>();
56
57 @Override
58 public String pop() {
59 return null;
60 }
61
62 @Override
63 public String peek() {
64 return null;
65 }
66
67 @Override
68 public void push(final String message) {
69 throw new UnsupportedOperationException();
70 }
71
72 @Override
73 public int getDepth() {
74 return 0;
75 }
76
77 @Override
78 public List<String> asList() {
79 return Collections.emptyList();
80 }
81
82 @Override
83 public void trim(final int depth) {
84
85 }
86
87 @Override
88 public boolean equals(final Object o) {
89
90 return (o instanceof Collection) && ((Collection<?>) o).isEmpty();
91 }
92
93 @Override
94 public int hashCode() {
95
96 return 1;
97 }
98
99 @Override
100 public ContextStack copy() {
101 return this;
102 }
103
104 @Override
105 public <T> T[] toArray(final T[] a) {
106 throw new UnsupportedOperationException();
107 }
108
109 @Override
110 public boolean add(final String e) {
111 throw new UnsupportedOperationException();
112 }
113
114 @Override
115 public boolean containsAll(final Collection<?> c) {
116 return false;
117 }
118
119 @Override
120 public boolean addAll(final Collection<? extends String> c) {
121 throw new UnsupportedOperationException();
122 }
123
124 @Override
125 public boolean removeAll(final Collection<?> c) {
126 throw new UnsupportedOperationException();
127 }
128
129 @Override
130 public boolean retainAll(final Collection<?> c) {
131 throw new UnsupportedOperationException();
132 }
133
134 @Override
135 public Iterator<String> iterator() {
136 return EMPTY_ITERATOR;
137 }
138
139 @Override
140 public int size() {
141 return 0;
142 }
143
144 @Override
145 public ContextStack getImmutableStackOrNull() {
146 return this;
147 }
148 }
149
150
151
152
153
154
155 private static class EmptyIterator<E> implements Iterator<E> {
156
157 @Override
158 public boolean hasNext() {
159 return false;
160 }
161
162 @Override
163 public E next() {
164 throw new NoSuchElementException("This is an empty iterator!");
165 }
166
167 @Override
168 public void remove() {
169
170 }
171 }
172
173
174
175
176
177 @SuppressWarnings("PublicStaticCollectionField")
178
179 public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
180
181
182
183
184
185 @SuppressWarnings("PublicStaticCollectionField")
186 public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack();
187
188 private static final String DISABLE_MAP = "disableThreadContextMap";
189 private static final String DISABLE_STACK = "disableThreadContextStack";
190 private static final String DISABLE_ALL = "disableThreadContext";
191 private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
192
193 private static boolean disableAll;
194 private static boolean useMap;
195 private static boolean useStack;
196 private static ThreadContextMap contextMap;
197 private static ThreadContextStack contextStack;
198 private static final Logger LOGGER = StatusLogger.getLogger();
199
200 static {
201 init();
202 }
203
204 private ThreadContext() {
205
206 }
207
208
209
210
211 static void init() {
212 contextMap = null;
213 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
214 disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
215 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
216 useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
217
218 contextStack = new DefaultThreadContextStack(useStack);
219 final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
220 final ClassLoader cl = ProviderUtil.findClassLoader();
221 if (threadContextMapName != null) {
222 try {
223 final Class<?> clazz = cl.loadClass(threadContextMapName);
224 if (ThreadContextMap.class.isAssignableFrom(clazz)) {
225 contextMap = (ThreadContextMap) clazz.newInstance();
226 }
227 } catch (final ClassNotFoundException cnfe) {
228 LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName);
229 } catch (final Exception ex) {
230 LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex);
231 }
232 }
233 if (contextMap == null && ProviderUtil.hasProviders()) {
234 final String factoryClassName = LogManager.getFactory().getClass().getName();
235 for (final Provider provider : ProviderUtil.getProviders()) {
236 if (factoryClassName.equals(provider.getClassName())) {
237 final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap();
238 if (clazz != null) {
239 try {
240 contextMap = clazz.newInstance();
241 break;
242 } catch (final Exception e) {
243 LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
244 provider.getThreadContextMap(), e);
245 contextMap = new DefaultThreadContextMap(useMap);
246 }
247 }
248 }
249 }
250 }
251 if (contextMap == null) {
252 contextMap = new DefaultThreadContextMap(useMap);
253 }
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267 public static void put(final String key, final String value) {
268 contextMap.put(key, value);
269 }
270
271
272
273
274
275
276
277
278
279
280
281 public static String get(final String key) {
282 return contextMap.get(key);
283 }
284
285
286
287
288
289
290 public static void remove(final String key) {
291 contextMap.remove(key);
292 }
293
294
295
296
297 public static void clearMap() {
298 contextMap.clear();
299 }
300
301
302
303
304 public static void clearAll() {
305 clearMap();
306 clearStack();
307 }
308
309
310
311
312
313
314
315 public static boolean containsKey(final String key) {
316 return contextMap.containsKey(key);
317 }
318
319
320
321
322
323
324 public static Map<String, String> getContext() {
325 return contextMap.getCopy();
326 }
327
328
329
330
331
332
333 public static Map<String, String> getImmutableContext() {
334 final Map<String, String> map = contextMap.getImmutableMapOrNull();
335 return map == null ? EMPTY_MAP : map;
336 }
337
338
339
340
341
342
343 public static boolean isEmpty() {
344 return contextMap.isEmpty();
345 }
346
347
348
349
350 public static void clearStack() {
351 contextStack.clear();
352 }
353
354
355
356
357
358
359 public static ContextStack cloneStack() {
360 return contextStack.copy();
361 }
362
363
364
365
366
367
368 public static ContextStack getImmutableStack() {
369 final ContextStack result = contextStack.getImmutableStackOrNull();
370 return result == null ? EMPTY_STACK : result;
371 }
372
373
374
375
376
377
378 public static void setStack(final Collection<String> stack) {
379 if (stack.isEmpty() || !useStack) {
380 return;
381 }
382 contextStack.clear();
383 contextStack.addAll(stack);
384 }
385
386
387
388
389
390
391
392
393 public static int getDepth() {
394 return contextStack.getDepth();
395 }
396
397
398
399
400
401
402
403
404
405
406
407 public static String pop() {
408 return contextStack.pop();
409 }
410
411
412
413
414
415
416
417
418
419
420
421 public static String peek() {
422 return contextStack.peek();
423 }
424
425
426
427
428
429
430
431
432
433
434 public static void push(final String message) {
435 contextStack.push(message);
436 }
437
438
439
440
441
442
443
444
445
446
447
448
449
450 public static void push(final String message, final Object... args) {
451 contextStack.push(ParameterizedMessage.format(message, args));
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470 public static void removeStack() {
471 contextStack.clear();
472 }
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506 public static void trim(final int depth) {
507 contextStack.trim(depth);
508 }
509
510
511
512
513 public interface ContextStack extends Serializable, Collection<String> {
514
515
516
517
518
519
520
521 String pop();
522
523
524
525
526
527
528 String peek();
529
530
531
532
533
534
535 void push(String message);
536
537
538
539
540
541
542 int getDepth();
543
544
545
546
547
548
549 List<String> asList();
550
551
552
553
554
555
556 void trim(int depth);
557
558
559
560
561
562
563 ContextStack copy();
564
565
566
567
568
569
570
571 ContextStack getImmutableStackOrNull();
572 }
573 }