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 ThreadContextMapFactory.init(); 215 contextMap = null; 216 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 217 disableAll = managerProps.getBooleanProperty(DISABLE_ALL); 218 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll); 219 useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll); 220 221 contextStack = new DefaultThreadContextStack(useStack); 222 if (!useMap) { 223 contextMap = new NoOpThreadContextMap(); 224 } else { 225 contextMap = ThreadContextMapFactory.createThreadContextMap(); 226 } 227 if (contextMap instanceof ReadOnlyThreadContextMap) { 228 readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap; 229 } else { 230 readOnlyContextMap = null; 231 } 232 } 233 234 /** 235 * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into 236 * the current thread's context map. 237 * 238 * <p> 239 * If the current thread does not have a context map it is created as a side effect. 240 * </p> 241 * 242 * @param key The key name. 243 * @param value The key value. 244 */ 245 public static void put(final String key, final String value) { 246 contextMap.put(key, value); 247 } 248 249 /** 250 * Puts all given context map entries into the current thread's 251 * context map. 252 * 253 * <p>If the current thread does not have a context map it is 254 * created as a side effect.</p> 255 * @param m The map. 256 * @since 2.7 257 */ 258 public static void putAll(final Map<String, String> m) { 259 if (contextMap instanceof ThreadContextMap2) { 260 ((ThreadContextMap2) contextMap).putAll(m); 261 } else if (contextMap instanceof DefaultThreadContextMap) { 262 ((DefaultThreadContextMap) contextMap).putAll(m); 263 } else { 264 for (final Map.Entry<String, String> entry: m.entrySet()) { 265 contextMap.put(entry.getKey(), entry.getValue()); 266 } 267 } 268 } 269 270 /** 271 * Gets the context value identified by the <code>key</code> parameter. 272 * 273 * <p> 274 * This method has no side effects. 275 * </p> 276 * 277 * @param key The key to locate. 278 * @return The value associated with the key or null. 279 */ 280 public static String get(final String key) { 281 return contextMap.get(key); 282 } 283 284 /** 285 * Removes the context value identified by the <code>key</code> parameter. 286 * 287 * @param key The key to remove. 288 */ 289 public static void remove(final String key) { 290 contextMap.remove(key); 291 } 292 293 /** 294 * Removes the context values identified by the <code>keys</code> parameter. 295 * 296 * @param keys The keys to remove. 297 * 298 * @since 2.8 299 */ 300 public static void removeAll(final Iterable<String> keys) { 301 if (contextMap instanceof CleanableThreadContextMap) { 302 ((CleanableThreadContextMap) contextMap).removeAll(keys); 303 } else if (contextMap instanceof DefaultThreadContextMap) { 304 ((DefaultThreadContextMap) contextMap).removeAll(keys); 305 } else { 306 for (final String key : keys) { 307 contextMap.remove(key); 308 } 309 } 310 } 311 312 /** 313 * Clears the context map. 314 */ 315 public static void clearMap() { 316 contextMap.clear(); 317 } 318 319 /** 320 * Clears the context map and stack. 321 */ 322 public static void clearAll() { 323 clearMap(); 324 clearStack(); 325 } 326 327 /** 328 * Determines if the key is in the context. 329 * 330 * @param key The key to locate. 331 * @return True if the key is in the context, false otherwise. 332 */ 333 public static boolean containsKey(final String key) { 334 return contextMap.containsKey(key); 335 } 336 337 /** 338 * Returns a mutable copy of current thread's context Map. 339 * 340 * @return a mutable copy of the context. 341 */ 342 public static Map<String, String> getContext() { 343 return contextMap.getCopy(); 344 } 345 346 /** 347 * Returns an immutable view of the current thread's context Map. 348 * 349 * @return An immutable view of the ThreadContext Map. 350 */ 351 public static Map<String, String> getImmutableContext() { 352 final Map<String, String> map = contextMap.getImmutableMapOrNull(); 353 return map == null ? EMPTY_MAP : map; 354 } 355 356 /** 357 * Returns a read-only view of the internal data structure used to store thread context key-value pairs, 358 * or {@code null} if the internal data structure does not implement the 359 * {@code ReadOnlyThreadContextMap} interface. 360 * <p> 361 * The {@link DefaultThreadContextMap} implementation does not implement {@code ReadOnlyThreadContextMap}, so by 362 * default this method returns {@code null}. 363 * </p> 364 * 365 * @return the internal data structure used to store thread context key-value pairs or {@code null} 366 * @see ThreadContextMapFactory 367 * @see DefaultThreadContextMap 368 * @see org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap 369 * @see org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap 370 * @since 2.8 371 */ 372 public static ReadOnlyThreadContextMap getThreadContextMap() { 373 return readOnlyContextMap; 374 } 375 376 /** 377 * Returns true if the Map is empty. 378 * 379 * @return true if the Map is empty, false otherwise. 380 */ 381 public static boolean isEmpty() { 382 return contextMap.isEmpty(); 383 } 384 385 /** 386 * Clears the stack for this thread. 387 */ 388 public static void clearStack() { 389 contextStack.clear(); 390 } 391 392 /** 393 * Returns a copy of this thread's stack. 394 * 395 * @return A copy of this thread's stack. 396 */ 397 public static ContextStack cloneStack() { 398 return contextStack.copy(); 399 } 400 401 /** 402 * Gets an immutable copy of this current thread's context stack. 403 * 404 * @return an immutable copy of the ThreadContext stack. 405 */ 406 public static ContextStack getImmutableStack() { 407 final ContextStack result = contextStack.getImmutableStackOrNull(); 408 return result == null ? EMPTY_STACK : result; 409 } 410 411 /** 412 * Sets this thread's stack. 413 * 414 * @param stack The stack to use. 415 */ 416 public static void setStack(final Collection<String> stack) { 417 if (stack.isEmpty() || !useStack) { 418 return; 419 } 420 contextStack.clear(); 421 contextStack.addAll(stack); 422 } 423 424 /** 425 * Gets the current nesting depth of this thread's stack. 426 * 427 * @return the number of items in the stack. 428 * 429 * @see #trim 430 */ 431 public static int getDepth() { 432 return contextStack.getDepth(); 433 } 434 435 /** 436 * Returns the value of the last item placed on the stack. 437 * 438 * <p> 439 * The returned value is the value that was pushed last. If no context is available, then the empty string "" is 440 * returned. 441 * </p> 442 * 443 * @return String The innermost diagnostic context. 444 */ 445 public static String pop() { 446 return contextStack.pop(); 447 } 448 449 /** 450 * Looks at the last diagnostic context at the top of this NDC without removing it. 451 * 452 * <p> 453 * The returned value is the value that was pushed last. If no context is available, then the empty string "" is 454 * returned. 455 * </p> 456 * 457 * @return String The innermost diagnostic context. 458 */ 459 public static String peek() { 460 return contextStack.peek(); 461 } 462 463 /** 464 * Pushes new diagnostic context information for the current thread. 465 * 466 * <p> 467 * The contents of the <code>message</code> parameter is determined solely by the client. 468 * </p> 469 * 470 * @param message The new diagnostic context information. 471 */ 472 public static void push(final String message) { 473 contextStack.push(message); 474 } 475 476 /** 477 * Pushes new diagnostic context information for the current thread. 478 * 479 * <p> 480 * The contents of the <code>message</code> and args parameters are determined solely by the client. The message 481 * will be treated as a format String and tokens will be replaced with the String value of the arguments in 482 * accordance with ParameterizedMessage. 483 * </p> 484 * 485 * @param message The new diagnostic context information. 486 * @param args Parameters for the message. 487 */ 488 public static void push(final String message, final Object... args) { 489 contextStack.push(ParameterizedMessage.format(message, args)); 490 } 491 492 /** 493 * Removes the diagnostic context for this thread. 494 * 495 * <p> 496 * Each thread that created a diagnostic context by calling {@link #push} should call this method before exiting. 497 * Otherwise, the memory used by the <b>thread</b> cannot be reclaimed by the VM. 498 * </p> 499 * 500 * <p> 501 * As this is such an important problem in heavy duty systems and because it is difficult to always guarantee that 502 * the remove method is called before exiting a thread, this method has been augmented to lazily remove references 503 * to dead threads. In practice, this means that you can be a little sloppy and occasionally forget to call 504 * {@link #remove} before exiting a thread. However, you must call <code>remove</code> sometime. If you never call 505 * it, then your application is sure to run out of memory. 506 * </p> 507 */ 508 public static void removeStack() { 509 contextStack.clear(); 510 } 511 512 /** 513 * Trims elements from this diagnostic context. If the current depth is smaller or equal to <code>maxDepth</code>, 514 * then no action is taken. If the current depth is larger than newDepth then all elements at maxDepth or higher are 515 * discarded. 516 * 517 * <p> 518 * This method is a convenient alternative to multiple {@link #pop} calls. Moreover, it is often the case that at 519 * the end of complex call sequences, the depth of the ThreadContext is unpredictable. The <code>trim</code> method 520 * circumvents this problem. 521 * </p> 522 * 523 * <p> 524 * For example, the combination 525 * </p> 526 * 527 * <pre> 528 * void foo() { 529 * final int depth = ThreadContext.getDepth(); 530 * 531 * // ... complex sequence of calls 532 * 533 * ThreadContext.trim(depth); 534 * } 535 * </pre> 536 * 537 * <p> 538 * ensures that between the entry and exit of {@code foo} the depth of the diagnostic stack is conserved. 539 * </p> 540 * 541 * @see #getDepth 542 * @param depth The number of elements to keep. 543 */ 544 public static void trim(final int depth) { 545 contextStack.trim(depth); 546 } 547 548 /** 549 * The ThreadContext Stack interface. 550 */ 551 public interface ContextStack extends Serializable, Collection<String> { 552 553 /** 554 * Returns the element at the top of the stack. 555 * 556 * @return The element at the top of the stack. 557 * @throws java.util.NoSuchElementException if the stack is empty. 558 */ 559 String pop(); 560 561 /** 562 * Returns the element at the top of the stack without removing it or null if the stack is empty. 563 * 564 * @return the element at the top of the stack or null if the stack is empty. 565 */ 566 String peek(); 567 568 /** 569 * Pushes an element onto the stack. 570 * 571 * @param message The element to add. 572 */ 573 void push(String message); 574 575 /** 576 * Returns the number of elements in the stack. 577 * 578 * @return the number of elements in the stack. 579 */ 580 int getDepth(); 581 582 /** 583 * Returns all the elements in the stack in a List. 584 * 585 * @return all the elements in the stack in a List. 586 */ 587 List<String> asList(); 588 589 /** 590 * Trims elements from the end of the stack. 591 * 592 * @param depth The maximum number of items in the stack to keep. 593 */ 594 void trim(int depth); 595 596 /** 597 * Returns a copy of the ContextStack. 598 * 599 * @return a copy of the ContextStack. 600 */ 601 ContextStack copy(); 602 603 /** 604 * Returns a ContextStack with the same contents as this ContextStack or {@code null}. Attempts to modify the 605 * returned stack may or may not throw an exception, but will not affect the contents of this ContextStack. 606 * 607 * @return a ContextStack with the same contents as this ContextStack or {@code null}. 608 */ 609 ContextStack getImmutableStackOrNull(); 610 } 611}