1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
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.NoOpThreadContextMap;
33 import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
34 import org.apache.logging.log4j.spi.ThreadContextMap;
35 import org.apache.logging.log4j.spi.ThreadContextMap2;
36 import org.apache.logging.log4j.spi.CleanableThreadContextMap;
37 import org.apache.logging.log4j.spi.ThreadContextMapFactory;
38 import org.apache.logging.log4j.spi.ThreadContextStack;
39 import org.apache.logging.log4j.util.PropertiesUtil;
40
41 /**
42 * The ThreadContext allows applications to store information either in a Map or a Stack.
43 * <p>
44 * <b><em>The MDC is managed on a per thread basis</em></b>. To enable automatic inheritance of <i>copies</i> of the MDC
45 * to newly created threads, enable the {@value org.apache.logging.log4j.spi.DefaultThreadContextMap#INHERITABLE_MAP}
46 * Log4j system property.
47 * </p>
48 * @see <a href="https://logging.apache.org/log4j/2.x/manual/thread-context.html">Thread Context Manual</a>
49 */
50 public final class ThreadContext {
51
52 /**
53 * An empty read-only ThreadContextStack.
54 */
55 private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack {
56
57 private static final long serialVersionUID = 1L;
58
59 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>();
60
61 @Override
62 public String pop() {
63 return null;
64 }
65
66 @Override
67 public String peek() {
68 return null;
69 }
70
71 @Override
72 public void push(final String message) {
73 throw new UnsupportedOperationException();
74 }
75
76 @Override
77 public int getDepth() {
78 return 0;
79 }
80
81 @Override
82 public List<String> asList() {
83 return Collections.emptyList();
84 }
85
86 @Override
87 public void trim(final int depth) {
88 // Do nothing
89 }
90
91 @Override
92 public boolean equals(final Object o) {
93 // Similar to java.util.Collections.EmptyList.equals(Object)
94 return (o instanceof Collection) && ((Collection<?>) o).isEmpty();
95 }
96
97 @Override
98 public int hashCode() {
99 // Same as java.util.Collections.EmptyList.hashCode()
100 return 1;
101 }
102
103 @Override
104 public ContextStack copy() {
105 return this;
106 }
107
108 @Override
109 public <T> T[] toArray(final T[] a) {
110 throw new UnsupportedOperationException();
111 }
112
113 @Override
114 public boolean add(final String e) {
115 throw new UnsupportedOperationException();
116 }
117
118 @Override
119 public boolean containsAll(final Collection<?> c) {
120 return false;
121 }
122
123 @Override
124 public boolean addAll(final Collection<? extends String> c) {
125 throw new UnsupportedOperationException();
126 }
127
128 @Override
129 public boolean removeAll(final Collection<?> c) {
130 throw new UnsupportedOperationException();
131 }
132
133 @Override
134 public boolean retainAll(final Collection<?> c) {
135 throw new UnsupportedOperationException();
136 }
137
138 @Override
139 public Iterator<String> iterator() {
140 return EMPTY_ITERATOR;
141 }
142
143 @Override
144 public int size() {
145 return 0;
146 }
147
148 @Override
149 public ContextStack getImmutableStackOrNull() {
150 return this;
151 }
152 }
153
154 /**
155 * An empty iterator. Since Java 1.7 added the Collections.emptyIterator() method, we have to make do.
156 *
157 * @param <E> the type of the empty iterator
158 */
159 private static class EmptyIterator<E> implements Iterator<E> {
160
161 @Override
162 public boolean hasNext() {
163 return false;
164 }
165
166 @Override
167 public E next() {
168 throw new NoSuchElementException("This is an empty iterator!");
169 }
170
171 @Override
172 public void remove() {
173 // no-op
174 }
175 }
176
177 /**
178 * Empty, immutable Map.
179 */
180 // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse
181 @SuppressWarnings("PublicStaticCollectionField")
182 // I like irony, so I won't delete it...
183 public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
184
185 /**
186 * Empty, immutable ContextStack.
187 */
188 // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse
189 @SuppressWarnings("PublicStaticCollectionField")
190 public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack();
191
192 private static final String DISABLE_MAP = "disableThreadContextMap";
193 private static final String DISABLE_STACK = "disableThreadContextStack";
194 private static final String DISABLE_ALL = "disableThreadContext";
195
196 private static boolean useStack;
197 private static ThreadContextMap contextMap;
198 private static ThreadContextStack contextStack;
199 private static ReadOnlyThreadContextMap readOnlyContextMap;
200
201 static {
202 init();
203 }
204
205 private ThreadContext() {
206 // empty
207 }
208
209 /**
210 * <em>Consider private, used for testing.</em>
211 */
212 static void init() {
213 ThreadContextMapFactory.init();
214 contextMap = null;
215 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
216 boolean disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
217 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
218 boolean useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
219
220 contextStack = new DefaultThreadContextStack(useStack);
221 if (!useMap) {
222 contextMap = new NoOpThreadContextMap();
223 } else {
224 contextMap = ThreadContextMapFactory.createThreadContextMap();
225 }
226 if (contextMap instanceof ReadOnlyThreadContextMap) {
227 readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap;
228 } else {
229 readOnlyContextMap = null;
230 }
231 }
232
233 /**
234 * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into
235 * the current thread's context map.
236 *
237 * <p>
238 * If the current thread does not have a context map it is created as a side effect.
239 * </p>
240 *
241 * @param key The key name.
242 * @param value The key value.
243 */
244 public static void put(final String key, final String value) {
245 contextMap.put(key, value);
246 }
247
248 /**
249 * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into
250 * the current thread's context map if the key does not exist.
251 *
252 * <p>
253 * If the current thread does not have a context map it is created as a side effect.
254 * </p>
255 *
256 * @param key The key name.
257 * @param value The key value.
258 * @since 2.13.0
259 */
260 public static void putIfNull(final String key, final String value) {
261 if(!contextMap.containsKey(key)) {
262 contextMap.put(key, value);
263 }
264 }
265
266 /**
267 * Puts all given context map entries into the current thread's
268 * context map.
269 *
270 * <p>If the current thread does not have a context map it is
271 * created as a side effect.</p>
272 * @param m The map.
273 * @since 2.7
274 */
275 public static void putAll(final Map<String, String> m) {
276 if (contextMap instanceof ThreadContextMap2) {
277 ((ThreadContextMap2) contextMap).putAll(m);
278 } else if (contextMap instanceof DefaultThreadContextMap) {
279 ((DefaultThreadContextMap) contextMap).putAll(m);
280 } else {
281 for (final Map.Entry<String, String> entry: m.entrySet()) {
282 contextMap.put(entry.getKey(), entry.getValue());
283 }
284 }
285 }
286
287 /**
288 * Gets the context value identified by the <code>key</code> parameter.
289 *
290 * <p>
291 * This method has no side effects.
292 * </p>
293 *
294 * @param key The key to locate.
295 * @return The value associated with the key or null.
296 */
297 public static String get(final String key) {
298 return contextMap.get(key);
299 }
300
301 /**
302 * Removes the context value identified by the <code>key</code> parameter.
303 *
304 * @param key The key to remove.
305 */
306 public static void remove(final String key) {
307 contextMap.remove(key);
308 }
309
310 /**
311 * Removes the context values identified by the <code>keys</code> parameter.
312 *
313 * @param keys The keys to remove.
314 *
315 * @since 2.8
316 */
317 public static void removeAll(final Iterable<String> keys) {
318 if (contextMap instanceof CleanableThreadContextMap) {
319 ((CleanableThreadContextMap) contextMap).removeAll(keys);
320 } else if (contextMap instanceof DefaultThreadContextMap) {
321 ((DefaultThreadContextMap) contextMap).removeAll(keys);
322 } else {
323 for (final String key : keys) {
324 contextMap.remove(key);
325 }
326 }
327 }
328
329 /**
330 * Clears the context map.
331 */
332 public static void clearMap() {
333 contextMap.clear();
334 }
335
336 /**
337 * Clears the context map and stack.
338 */
339 public static void clearAll() {
340 clearMap();
341 clearStack();
342 }
343
344 /**
345 * Determines if the key is in the context.
346 *
347 * @param key The key to locate.
348 * @return True if the key is in the context, false otherwise.
349 */
350 public static boolean containsKey(final String key) {
351 return contextMap.containsKey(key);
352 }
353
354 /**
355 * Returns a mutable copy of current thread's context Map.
356 *
357 * @return a mutable copy of the context.
358 */
359 public static Map<String, String> getContext() {
360 return contextMap.getCopy();
361 }
362
363 /**
364 * Returns an immutable view of the current thread's context Map.
365 *
366 * @return An immutable view of the ThreadContext Map.
367 */
368 public static Map<String, String> getImmutableContext() {
369 final Map<String, String> map = contextMap.getImmutableMapOrNull();
370 return map == null ? EMPTY_MAP : map;
371 }
372
373 /**
374 * Returns a read-only view of the internal data structure used to store thread context key-value pairs,
375 * or {@code null} if the internal data structure does not implement the
376 * {@code ReadOnlyThreadContextMap} interface.
377 * <p>
378 * The {@link DefaultThreadContextMap} implementation does not implement {@code ReadOnlyThreadContextMap}, so by
379 * default this method returns {@code null}.
380 * </p>
381 *
382 * @return the internal data structure used to store thread context key-value pairs or {@code null}
383 * @see ThreadContextMapFactory
384 * @see DefaultThreadContextMap
385 * @see org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap
386 * @see org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap
387 * @since 2.8
388 */
389 public static ReadOnlyThreadContextMap getThreadContextMap() {
390 return readOnlyContextMap;
391 }
392
393 /**
394 * Returns true if the Map is empty.
395 *
396 * @return true if the Map is empty, false otherwise.
397 */
398 public static boolean isEmpty() {
399 return contextMap.isEmpty();
400 }
401
402 /**
403 * Clears the stack for this thread.
404 */
405 public static void clearStack() {
406 contextStack.clear();
407 }
408
409 /**
410 * Returns a copy of this thread's stack.
411 *
412 * @return A copy of this thread's stack.
413 */
414 public static ContextStack cloneStack() {
415 return contextStack.copy();
416 }
417
418 /**
419 * Gets an immutable copy of this current thread's context stack.
420 *
421 * @return an immutable copy of the ThreadContext stack.
422 */
423 public static ContextStack getImmutableStack() {
424 final ContextStack result = contextStack.getImmutableStackOrNull();
425 return result == null ? EMPTY_STACK : result;
426 }
427
428 /**
429 * Sets this thread's stack.
430 *
431 * @param stack The stack to use.
432 */
433 public static void setStack(final Collection<String> stack) {
434 if (stack.isEmpty() || !useStack) {
435 return;
436 }
437 contextStack.clear();
438 contextStack.addAll(stack);
439 }
440
441 /**
442 * Gets the current nesting depth of this thread's stack.
443 *
444 * @return the number of items in the stack.
445 *
446 * @see #trim
447 */
448 public static int getDepth() {
449 return contextStack.getDepth();
450 }
451
452 /**
453 * Returns the value of the last item placed on the stack.
454 *
455 * <p>
456 * The returned value is the value that was pushed last. If no context is available, then the empty string "" is
457 * returned.
458 * </p>
459 *
460 * @return String The innermost diagnostic context.
461 */
462 public static String pop() {
463 return contextStack.pop();
464 }
465
466 /**
467 * Looks at the last diagnostic context at the top of this NDC without removing it.
468 *
469 * <p>
470 * The returned value is the value that was pushed last. If no context is available, then the empty string "" is
471 * returned.
472 * </p>
473 *
474 * @return String The innermost diagnostic context.
475 */
476 public static String peek() {
477 return contextStack.peek();
478 }
479
480 /**
481 * Pushes new diagnostic context information for the current thread.
482 *
483 * <p>
484 * The contents of the <code>message</code> parameter is determined solely by the client.
485 * </p>
486 *
487 * @param message The new diagnostic context information.
488 */
489 public static void push(final String message) {
490 contextStack.push(message);
491 }
492
493 /**
494 * Pushes new diagnostic context information for the current thread.
495 *
496 * <p>
497 * The contents of the <code>message</code> and args parameters are determined solely by the client. The message
498 * will be treated as a format String and tokens will be replaced with the String value of the arguments in
499 * accordance with ParameterizedMessage.
500 * </p>
501 *
502 * @param message The new diagnostic context information.
503 * @param args Parameters for the message.
504 */
505 public static void push(final String message, final Object... args) {
506 contextStack.push(ParameterizedMessage.format(message, args));
507 }
508
509 /**
510 * Removes the diagnostic context for this thread.
511 *
512 * <p>
513 * Each thread that created a diagnostic context by calling {@link #push} should call this method before exiting.
514 * Otherwise, the memory used by the <b>thread</b> cannot be reclaimed by the VM.
515 * </p>
516 *
517 * <p>
518 * As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that
519 * the remove method is called before exiting a thread, this method has been augmented to lazily remove references
520 * to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call
521 * {@link #remove} before exiting a thread. However, you must call <code>remove</code> sometime. If you never call
522 * it, then your application is sure to run out of memory.
523 * </p>
524 */
525 public static void removeStack() {
526 contextStack.clear();
527 }
528
529 /**
530 * Trims elements from this diagnostic context. If the current depth is smaller or equal to <code>maxDepth</code>,
531 * then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are
532 * discarded.
533 *
534 * <p>
535 * This method is a convenient alternative to multiple {@link #pop} calls. Moreover, it is often the case that at
536 * the end of complex call sequences, the depth of the ThreadContext is unpredictable. The <code>trim</code> method
537 * circumvents this problem.
538 * </p>
539 *
540 * <p>
541 * For example, the combination
542 * </p>
543 *
544 * <pre>
545 * void foo() {
546 * final int depth = ThreadContext.getDepth();
547 *
548 * // ... complex sequence of calls
549 *
550 * ThreadContext.trim(depth);
551 * }
552 * </pre>
553 *
554 * <p>
555 * ensures that between the entry and exit of {@code foo} the depth of the diagnostic stack is conserved.
556 * </p>
557 *
558 * @see #getDepth
559 * @param depth The number of elements to keep.
560 */
561 public static void trim(final int depth) {
562 contextStack.trim(depth);
563 }
564
565 /**
566 * The ThreadContext Stack interface.
567 */
568 public interface ContextStack extends Serializable, Collection<String> {
569
570 /**
571 * Returns the element at the top of the stack.
572 *
573 * @return The element at the top of the stack.
574 * @throws java.util.NoSuchElementException if the stack is empty.
575 */
576 String pop();
577
578 /**
579 * Returns the element at the top of the stack without removing it or null if the stack is empty.
580 *
581 * @return the element at the top of the stack or null if the stack is empty.
582 */
583 String peek();
584
585 /**
586 * Pushes an element onto the stack.
587 *
588 * @param message The element to add.
589 */
590 void push(String message);
591
592 /**
593 * Returns the number of elements in the stack.
594 *
595 * @return the number of elements in the stack.
596 */
597 int getDepth();
598
599 /**
600 * Returns all the elements in the stack in a List.
601 *
602 * @return all the elements in the stack in a List.
603 */
604 List<String> asList();
605
606 /**
607 * Trims elements from the end of the stack.
608 *
609 * @param depth The maximum number of items in the stack to keep.
610 */
611 void trim(int depth);
612
613 /**
614 * Returns a copy of the ContextStack.
615 *
616 * @return a copy of the ContextStack.
617 */
618 ContextStack copy();
619
620 /**
621 * Returns a ContextStack with the same contents as this ContextStack or {@code null}. Attempts to modify the
622 * returned stack may or may not throw an exception, but will not affect the contents of this ContextStack.
623 *
624 * @return a ContextStack with the same contents as this ContextStack or {@code null}.
625 */
626 ContextStack getImmutableStackOrNull();
627 }
628 }
629