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<String>();
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 private static class EmptyIterator<E> implements Iterator<E> {
155
156 @Override
157 public boolean hasNext() {
158 return false;
159 }
160
161 @Override
162 public E next() {
163 throw new NoSuchElementException("This is an empty iterator!");
164 }
165
166 @Override
167 public void remove() {
168
169 }
170 }
171
172
173
174
175
176 @SuppressWarnings("PublicStaticCollectionField")
177 public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
178
179
180
181
182
183 @SuppressWarnings("PublicStaticCollectionField")
184 public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack();
185
186 private static final String DISABLE_MAP = "disableThreadContextMap";
187 private static final String DISABLE_STACK = "disableThreadContextStack";
188 private static final String DISABLE_ALL = "disableThreadContext";
189 private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
190
191 private static boolean disableAll;
192 private static boolean useMap;
193 private static boolean useStack;
194 private static ThreadContextMap contextMap;
195 private static ThreadContextStack contextStack;
196 private static final Logger LOGGER = StatusLogger.getLogger();
197
198 static {
199 init();
200 }
201
202
203
204
205 static void init() {
206 contextMap = null;
207 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
208 disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
209 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
210 useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
211
212 contextStack = new DefaultThreadContextStack(useStack);
213 final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
214 final ClassLoader cl = ProviderUtil.findClassLoader();
215 if (threadContextMapName != null) {
216 try {
217 final Class<?> clazz = cl.loadClass(threadContextMapName);
218 if (ThreadContextMap.class.isAssignableFrom(clazz)) {
219 contextMap = (ThreadContextMap) clazz.newInstance();
220 }
221 } catch (final ClassNotFoundException cnfe) {
222 LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName);
223 } catch (final Exception ex) {
224 LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex);
225 }
226 }
227 if (contextMap == null && ProviderUtil.hasProviders()) {
228 final String factoryClassName = LogManager.getFactory().getClass().getName();
229 for (final Provider provider : ProviderUtil.getProviders()) {
230 if (factoryClassName.equals(provider.getClassName())) {
231 final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap();
232 if (clazz != null) {
233 try {
234 contextMap = clazz.newInstance();
235 break;
236 } catch (final Exception e) {
237 LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
238 provider.getThreadContextMap(), e);
239 contextMap = new DefaultThreadContextMap(useMap);
240 }
241 }
242 }
243 }
244 }
245 if (contextMap == null) {
246 contextMap = new DefaultThreadContextMap(useMap);
247 }
248 }
249
250 private ThreadContext() {
251
252 }
253
254
255
256
257
258
259
260
261
262
263
264 public static void put(final String key, final String value) {
265 contextMap.put(key, value);
266 }
267
268
269
270
271
272
273
274
275 public static String get(final String key) {
276 return contextMap.get(key);
277 }
278
279
280
281
282
283 public static void remove(final String key) {
284 contextMap.remove(key);
285 }
286
287
288
289
290 public static void clearMap() {
291 contextMap.clear();
292 }
293
294
295
296
297 public static void clearAll() {
298 clearMap();
299 clearStack();
300 }
301
302
303
304
305
306
307 public static boolean containsKey(final String key) {
308 return contextMap.containsKey(key);
309 }
310
311
312
313
314
315 public static Map<String, String> getContext() {
316 return contextMap.getCopy();
317 }
318
319
320
321
322
323 public static Map<String, String> getImmutableContext() {
324 final Map<String, String> map = contextMap.getImmutableMapOrNull();
325 return map == null ? EMPTY_MAP : map;
326 }
327
328
329
330
331
332 public static boolean isEmpty() {
333 return contextMap.isEmpty();
334 }
335
336
337
338
339 public static void clearStack() {
340 contextStack.clear();
341 }
342
343
344
345
346
347 public static ContextStack cloneStack() {
348 return contextStack.copy();
349 }
350
351
352
353
354
355 public static ContextStack getImmutableStack() {
356 final ContextStack result = contextStack.getImmutableStackOrNull();
357 return result == null ? EMPTY_STACK : result;
358 }
359
360
361
362
363
364 public static void setStack(final Collection<String> stack) {
365 if (stack.isEmpty() || !useStack) {
366 return;
367 }
368 contextStack.clear();
369 contextStack.addAll(stack);
370 }
371
372
373
374
375
376
377
378 public static int getDepth() {
379 return contextStack.getDepth();
380 }
381
382
383
384
385
386
387
388
389
390 public static String pop() {
391 return contextStack.pop();
392 }
393
394
395
396
397
398
399
400
401
402
403 public static String peek() {
404 return contextStack.peek();
405 }
406
407
408
409
410
411
412
413
414
415 public static void push(final String message) {
416 contextStack.push(message);
417 }
418
419
420
421
422
423
424
425
426
427
428
429 public static void push(final String message, final Object... args) {
430 contextStack.push(ParameterizedMessage.format(message, args));
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 public static void removeStack() {
452 contextStack.clear();
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484 public static void trim(final int depth) {
485 contextStack.trim(depth);
486 }
487
488
489
490
491 public interface ContextStack extends Serializable, Collection<String> {
492
493
494
495
496
497
498 String pop();
499
500
501
502
503
504 String peek();
505
506
507
508
509
510 void push(String message);
511
512
513
514
515
516 int getDepth();
517
518
519
520
521
522 List<String> asList();
523
524
525
526
527
528 void trim(int depth);
529
530
531
532
533
534 ContextStack copy();
535
536
537
538
539
540
541
542 ContextStack getImmutableStackOrNull();
543 }
544 }