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