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