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 DefaultThreadContextMap#INHERITABLE_MAP} Log4j system property. 046 * </p> 047 * @see <a href="https://logging.apache.org/log4j/2.x/manual/thread-context.html">Thread Context Manual</a> 048 */ 049public final class ThreadContext { 050 051 /** 052 * An empty read-only ThreadContextStack. 053 */ 054 private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack { 055 056 private static final long serialVersionUID = 1L; 057 058 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>(); 059 060 @Override 061 public String pop() { 062 return null; 063 } 064 065 @Override 066 public String peek() { 067 return null; 068 } 069 070 @Override 071 public void push(final String message) { 072 throw new UnsupportedOperationException(); 073 } 074 075 @Override 076 public int getDepth() { 077 return 0; 078 } 079 080 @Override 081 public List<String> asList() { 082 return Collections.emptyList(); 083 } 084 085 @Override 086 public void trim(final int depth) { 087 // Do nothing 088 } 089 090 @Override 091 public boolean equals(final Object o) { 092 // Similar to java.util.Collections.EmptyList.equals(Object) 093 return (o instanceof Collection) && ((Collection<?>) o).isEmpty(); 094 } 095 096 @Override 097 public int hashCode() { 098 // Same as java.util.Collections.EmptyList.hashCode() 099 return 1; 100 } 101 102 @Override 103 public ContextStack copy() { 104 return this; 105 } 106 107 @Override 108 public <T> T[] toArray(final T[] a) { 109 throw new UnsupportedOperationException(); 110 } 111 112 @Override 113 public boolean add(final String e) { 114 throw new UnsupportedOperationException(); 115 } 116 117 @Override 118 public boolean containsAll(final Collection<?> c) { 119 return false; 120 } 121 122 @Override 123 public boolean addAll(final Collection<? extends String> c) { 124 throw new UnsupportedOperationException(); 125 } 126 127 @Override 128 public boolean removeAll(final Collection<?> c) { 129 throw new UnsupportedOperationException(); 130 } 131 132 @Override 133 public boolean retainAll(final Collection<?> c) { 134 throw new UnsupportedOperationException(); 135 } 136 137 @Override 138 public Iterator<String> iterator() { 139 return EMPTY_ITERATOR; 140 } 141 142 @Override 143 public int size() { 144 return 0; 145 } 146 147 @Override 148 public ContextStack getImmutableStackOrNull() { 149 return this; 150 } 151 } 152 153 /** 154 * An empty iterator. Since Java 1.7 added the Collections.emptyIterator() method, we have to make do. 155 * 156 * @param <E> the type of the empty iterator 157 */ 158 private static class EmptyIterator<E> implements Iterator<E> { 159 160 @Override 161 public boolean hasNext() { 162 return false; 163 } 164 165 @Override 166 public E next() { 167 throw new NoSuchElementException("This is an empty iterator!"); 168 } 169 170 @Override 171 public void remove() { 172 // no-op 173 } 174 } 175 176 /** 177 * Empty, immutable Map. 178 */ 179 // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse 180 @SuppressWarnings("PublicStaticCollectionField") 181 // I like irony, so I won't delete it... 182 public static final Map<String, String> EMPTY_MAP = Collections.emptyMap(); 183 184 /** 185 * Empty, immutable ContextStack. 186 */ 187 // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse 188 @SuppressWarnings("PublicStaticCollectionField") 189 public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack(); 190 191 private static final String DISABLE_MAP = "disableThreadContextMap"; 192 private static final String DISABLE_STACK = "disableThreadContextStack"; 193 private static final String DISABLE_ALL = "disableThreadContext"; 194 195 private static boolean disableAll; 196 private static boolean useMap; 197 private static boolean useStack; 198 private static ThreadContextMap contextMap; 199 private static ThreadContextStack contextStack; 200 private static ReadOnlyThreadContextMap readOnlyContextMap; 201 202 static { 203 init(); 204 } 205 206 private ThreadContext() { 207 // empty 208 } 209 210 /** 211 * <em>Consider private, used for testing.</em> 212 */ 213 static void init() { 214 contextMap = null; 215 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 216 disableAll = managerProps.getBooleanProperty(DISABLE_ALL); 217 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll); 218 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 } 229 } 230 231 /** 232 * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into 233 * the current thread's context map. 234 * 235 * <p> 236 * If the current thread does not have a context map it is created as a side effect. 237 * </p> 238 * 239 * @param key The key name. 240 * @param value The key value. 241 */ 242 public static void put(final String key, final String value) { 243 contextMap.put(key, value); 244 } 245 246 /** 247 * Puts all given context map entries into the current thread's 248 * context map. 249 * 250 * <p>If the current thread does not have a context map it is 251 * created as a side effect.</p> 252 * @param m The map. 253 * @since 2.7 254 */ 255 public static void putAll(final Map<String, String> m) { 256 if (contextMap instanceof ThreadContextMap2) { 257 ((ThreadContextMap2) contextMap).putAll(m); 258 } else if (contextMap instanceof DefaultThreadContextMap) { 259 ((DefaultThreadContextMap) contextMap).putAll(m); 260 } else { 261 for (final Map.Entry<String, String> entry: m.entrySet()) { 262 contextMap.put(entry.getKey(), entry.getValue()); 263 } 264 } 265 } 266 267 /** 268 * Gets the context value identified by the <code>key</code> parameter. 269 * 270 * <p> 271 * This method has no side effects. 272 * </p> 273 * 274 * @param key The key to locate. 275 * @return The value associated with the key or null. 276 */ 277 public static String get(final String key) { 278 return contextMap.get(key); 279 } 280 281 /** 282 * Removes the context value identified by the <code>key</code> parameter. 283 * 284 * @param key The key to remove. 285 */ 286 public static void remove(final String key) { 287 contextMap.remove(key); 288 } 289 290 /** 291 * Removes the context values identified by the <code>keys</code> parameter. 292 * 293 * @param keys The keys to remove. 294 * 295 * @since 2.8 296 */ 297 public static void removeAll(final Iterable<String> keys) { 298 if (contextMap instanceof CleanableThreadContextMap) { 299 ((CleanableThreadContextMap) contextMap).removeAll(keys); 300 } else if (contextMap instanceof DefaultThreadContextMap) { 301 ((DefaultThreadContextMap) contextMap).removeAll(keys); 302 } else { 303 for (final String key : keys) { 304 contextMap.remove(key); 305 } 306 } 307 } 308 309 /** 310 * Clears the context map. 311 */ 312 public static void clearMap() { 313 contextMap.clear(); 314 } 315 316 /** 317 * Clears the context map and stack. 318 */ 319 public static void clearAll() { 320 clearMap(); 321 clearStack(); 322 } 323 324 /** 325 * Determines if the key is in the context. 326 * 327 * @param key The key to locate. 328 * @return True if the key is in the context, false otherwise. 329 */ 330 public static boolean containsKey(final String key) { 331 return contextMap.containsKey(key); 332 } 333 334 /** 335 * Returns a mutable copy of current thread's context Map. 336 * 337 * @return a mutable copy of the context. 338 */ 339 public static Map<String, String> getContext() { 340 return contextMap.getCopy(); 341 } 342 343 /** 344 * Returns an immutable view of the current thread's context Map. 345 * 346 * @return An immutable view of the ThreadContext Map. 347 */ 348 public static Map<String, String> getImmutableContext() { 349 final Map<String, String> map = contextMap.getImmutableMapOrNull(); 350 return map == null ? EMPTY_MAP : map; 351 } 352 353 /** 354 * Returns a read-only view of the internal data structure used to store thread context key-value pairs, 355 * or {@code null} if the internal data structure does not implement the 356 * {@code ReadOnlyThreadContextMap} interface. 357 * <p> 358 * The {@link DefaultThreadContextMap} implementation does not implement {@code ReadOnlyThreadContextMap}, so by 359 * default this method returns {@code null}. 360 * </p> 361 * 362 * @return the internal data structure used to store thread context key-value pairs or {@code null} 363 * @see ThreadContextMapFactory 364 * @see DefaultThreadContextMap 365 * @see org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap 366 * @see org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap 367 * @since 2.8 368 */ 369 public static ReadOnlyThreadContextMap getThreadContextMap() { 370 return readOnlyContextMap; 371 } 372 373 /** 374 * Returns true if the Map is empty. 375 * 376 * @return true if the Map is empty, false otherwise. 377 */ 378 public static boolean isEmpty() { 379 return contextMap.isEmpty(); 380 } 381 382 /** 383 * Clears the stack for this thread. 384 */ 385 public static void clearStack() { 386 contextStack.clear(); 387 } 388 389 /** 390 * Returns a copy of this thread's stack. 391 * 392 * @return A copy of this thread's stack. 393 */ 394 public static ContextStack cloneStack() { 395 return contextStack.copy(); 396 } 397 398 /** 399 * Gets an immutable copy of this current thread's context stack. 400 * 401 * @return an immutable copy of the ThreadContext stack. 402 */ 403 public static ContextStack getImmutableStack() { 404 final ContextStack result = contextStack.getImmutableStackOrNull(); 405 return result == null ? EMPTY_STACK : result; 406 } 407 408 /** 409 * Sets this thread's stack. 410 * 411 * @param stack The stack to use. 412 */ 413 public static void setStack(final Collection<String> stack) { 414 if (stack.isEmpty() || !useStack) { 415 return; 416 } 417 contextStack.clear(); 418 contextStack.addAll(stack); 419 } 420 421 /** 422 * Gets the current nesting depth of this thread's stack. 423 * 424 * @return the number of items in the stack. 425 * 426 * @see #trim 427 */ 428 public static int getDepth() { 429 return contextStack.getDepth(); 430 } 431 432 /** 433 * Returns the value of the last item placed on the stack. 434 * 435 * <p> 436 * The returned value is the value that was pushed last. If no context is available, then the empty string "" is 437 * returned. 438 * </p> 439 * 440 * @return String The innermost diagnostic context. 441 */ 442 public static String pop() { 443 return contextStack.pop(); 444 } 445 446 /** 447 * Looks at the last diagnostic context at the top of this NDC without removing it. 448 * 449 * <p> 450 * The returned value is the value that was pushed last. If no context is available, then the empty string "" is 451 * returned. 452 * </p> 453 * 454 * @return String The innermost diagnostic context. 455 */ 456 public static String peek() { 457 return contextStack.peek(); 458 } 459 460 /** 461 * Pushes new diagnostic context information for the current thread. 462 * 463 * <p> 464 * The contents of the <code>message</code> parameter is determined solely by the client. 465 * </p> 466 * 467 * @param message The new diagnostic context information. 468 */ 469 public static void push(final String message) { 470 contextStack.push(message); 471 } 472 473 /** 474 * Pushes new diagnostic context information for the current thread. 475 * 476 * <p> 477 * The contents of the <code>message</code> and args parameters are determined solely by the client. The message 478 * will be treated as a format String and tokens will be replaced with the String value of the arguments in 479 * accordance with ParameterizedMessage. 480 * </p> 481 * 482 * @param message The new diagnostic context information. 483 * @param args Parameters for the message. 484 */ 485 public static void push(final String message, final Object... args) { 486 contextStack.push(ParameterizedMessage.format(message, args)); 487 } 488 489 /** 490 * Removes the diagnostic context for this thread. 491 * 492 * <p> 493 * Each thread that created a diagnostic context by calling {@link #push} should call this method before exiting. 494 * Otherwise, the memory used by the <b>thread</b> cannot be reclaimed by the VM. 495 * </p> 496 * 497 * <p> 498 * As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that 499 * the remove method is called before exiting a thread, this method has been augmented to lazily remove references 500 * to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call 501 * {@link #remove} before exiting a thread. However, you must call <code>remove</code> sometime. If you never call 502 * it, then your application is sure to run out of memory. 503 * </p> 504 */ 505 public static void removeStack() { 506 contextStack.clear(); 507 } 508 509 /** 510 * Trims elements from this diagnostic context. If the current depth is smaller or equal to <code>maxDepth</code>, 511 * then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are 512 * discarded. 513 * 514 * <p> 515 * This method is a convenient alternative to multiple {@link #pop} calls. Moreover, it is often the case that at 516 * the end of complex call sequences, the depth of the ThreadContext is unpredictable. The <code>trim</code> method 517 * circumvents this problem. 518 * </p> 519 * 520 * <p> 521 * For example, the combination 522 * </p> 523 * 524 * <pre> 525 * void foo() { 526 * final int depth = ThreadContext.getDepth(); 527 * 528 * // ... complex sequence of calls 529 * 530 * ThreadContext.trim(depth); 531 * } 532 * </pre> 533 * 534 * <p> 535 * ensures that between the entry and exit of {@code foo} the depth of the diagnostic stack is conserved. 536 * </p> 537 * 538 * @see #getDepth 539 * @param depth The number of elements to keep. 540 */ 541 public static void trim(final int depth) { 542 contextStack.trim(depth); 543 } 544 545 /** 546 * The ThreadContext Stack interface. 547 */ 548 public interface ContextStack extends Serializable, Collection<String> { 549 550 /** 551 * Returns the element at the top of the stack. 552 * 553 * @return The element at the top of the stack. 554 * @throws java.util.NoSuchElementException if the stack is empty. 555 */ 556 String pop(); 557 558 /** 559 * Returns the element at the top of the stack without removing it or null if the stack is empty. 560 * 561 * @return the element at the top of the stack or null if the stack is empty. 562 */ 563 String peek(); 564 565 /** 566 * Pushes an element onto the stack. 567 * 568 * @param message The element to add. 569 */ 570 void push(String message); 571 572 /** 573 * Returns the number of elements in the stack. 574 * 575 * @return the number of elements in the stack. 576 */ 577 int getDepth(); 578 579 /** 580 * Returns all the elements in the stack in a List. 581 * 582 * @return all the elements in the stack in a List. 583 */ 584 List<String> asList(); 585 586 /** 587 * Trims elements from the end of the stack. 588 * 589 * @param depth The maximum number of items in the stack to keep. 590 */ 591 void trim(int depth); 592 593 /** 594 * Returns a copy of the ContextStack. 595 * 596 * @return a copy of the ContextStack. 597 */ 598 ContextStack copy(); 599 600 /** 601 * Returns a ContextStack with the same contents as this ContextStack or {@code null}. Attempts to modify the 602 * returned stack may or may not throw an exception, but will not affect the contents of this ContextStack. 603 * 604 * @return a ContextStack with the same contents as this ContextStack or {@code null}. 605 */ 606 ContextStack getImmutableStackOrNull(); 607 } 608}