001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 018package org.apache.logging.log4j; 019 020import java.io.Serializable; 021import java.util.AbstractCollection; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027import java.util.NoSuchElementException; 028 029import org.apache.logging.log4j.message.ParameterizedMessage; 030import org.apache.logging.log4j.spi.DefaultThreadContextMap; 031import org.apache.logging.log4j.spi.DefaultThreadContextStack; 032import org.apache.logging.log4j.spi.NoOpThreadContextMap; 033import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap; 034import org.apache.logging.log4j.spi.ThreadContextMap; 035import org.apache.logging.log4j.spi.ThreadContextMap2; 036import org.apache.logging.log4j.spi.CleanableThreadContextMap; 037import org.apache.logging.log4j.spi.ThreadContextMapFactory; 038import org.apache.logging.log4j.spi.ThreadContextStack; 039import org.apache.logging.log4j.util.PropertiesUtil; 040 041/** 042 * The ThreadContext allows applications to store information either in a Map or a Stack. 043 * <p> 044 * <b><em>The MDC is managed on a per thread basis</em></b>. To enable automatic inheritance of <i>copies</i> of the MDC 045 * to newly created threads, enable the {@value org.apache.logging.log4j.spi.DefaultThreadContextMap#INHERITABLE_MAP} 046 * Log4j system property. 047 * </p> 048 * @see <a href="https://logging.apache.org/log4j/2.x/manual/thread-context.html">Thread Context Manual</a> 049 */ 050public final class ThreadContext { 051 052 /** 053 * An empty read-only ThreadContextStack. 054 */ 055 private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack { 056 057 private static final long serialVersionUID = 1L; 058 059 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>(); 060 061 @Override 062 public String pop() { 063 return null; 064 } 065 066 @Override 067 public String peek() { 068 return null; 069 } 070 071 @Override 072 public void push(final String message) { 073 throw new UnsupportedOperationException(); 074 } 075 076 @Override 077 public int getDepth() { 078 return 0; 079 } 080 081 @Override 082 public List<String> asList() { 083 return Collections.emptyList(); 084 } 085 086 @Override 087 public void trim(final int depth) { 088 // Do nothing 089 } 090 091 @Override 092 public boolean equals(final Object o) { 093 // Similar to java.util.Collections.EmptyList.equals(Object) 094 return (o instanceof Collection) && ((Collection<?>) o).isEmpty(); 095 } 096 097 @Override 098 public int hashCode() { 099 // 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}