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