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