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<String>(); 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 * @param <E> the type of the empty iterator 153 */ 154 private static class EmptyIterator<E> implements Iterator<E> { 155 156 @Override 157 public boolean hasNext() { 158 return false; 159 } 160 161 @Override 162 public E next() { 163 throw new NoSuchElementException("This is an empty iterator!"); 164 } 165 166 @Override 167 public void remove() { 168 // no-op 169 } 170 } 171 172 /** 173 * Empty, immutable Map. 174 */ 175 // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse 176 @SuppressWarnings("PublicStaticCollectionField") // I like irony, so I won't delete it... 177 public static final Map<String, String> EMPTY_MAP = Collections.emptyMap(); 178 179 /** 180 * Empty, immutable ContextStack. 181 */ 182 // ironically, this annotation gives an "unsupported @SuppressWarnings" warning in Eclipse 183 @SuppressWarnings("PublicStaticCollectionField") 184 public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack(); 185 186 private static final String DISABLE_MAP = "disableThreadContextMap"; 187 private static final String DISABLE_STACK = "disableThreadContextStack"; 188 private static final String DISABLE_ALL = "disableThreadContext"; 189 private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap"; 190 191 private static boolean disableAll; 192 private static boolean useMap; 193 private static boolean useStack; 194 private static ThreadContextMap contextMap; 195 private static ThreadContextStack contextStack; 196 private static final Logger LOGGER = StatusLogger.getLogger(); 197 198 static { 199 init(); 200 } 201 202 /** 203 * <em>Consider private, used for testing.</em> 204 */ 205 static void init() { 206 contextMap = null; 207 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 208 disableAll = managerProps.getBooleanProperty(DISABLE_ALL); 209 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll); 210 useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll); 211 212 contextStack = new DefaultThreadContextStack(useStack); 213 final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY); 214 final ClassLoader cl = ProviderUtil.findClassLoader(); 215 if (threadContextMapName != null) { 216 try { 217 final Class<?> clazz = cl.loadClass(threadContextMapName); 218 if (ThreadContextMap.class.isAssignableFrom(clazz)) { 219 contextMap = (ThreadContextMap) clazz.newInstance(); 220 } 221 } catch (final ClassNotFoundException cnfe) { 222 LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName); 223 } catch (final Exception ex) { 224 LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex); 225 } 226 } 227 if (contextMap == null && ProviderUtil.hasProviders()) { 228 final String factoryClassName = LogManager.getFactory().getClass().getName(); 229 for (final Provider provider : ProviderUtil.getProviders()) { 230 if (factoryClassName.equals(provider.getClassName())) { 231 final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap(); 232 if (clazz != null) { 233 try { 234 contextMap = clazz.newInstance(); 235 break; 236 } catch (final Exception e) { 237 LOGGER.error("Unable to locate or load configured ThreadContextMap {}", 238 provider.getThreadContextMap(), e); 239 contextMap = new DefaultThreadContextMap(useMap); 240 } 241 } 242 } 243 } 244 } 245 if (contextMap == null) { 246 contextMap = new DefaultThreadContextMap(useMap); 247 } 248 } 249 250 private ThreadContext() { 251 // empty 252 } 253 254 /** 255 * Puts a context value (the <code>value</code> parameter) as identified 256 * with the <code>key</code> parameter into the current thread's 257 * context map. 258 * 259 * <p>If the current thread does not have a context map it is 260 * created as a side effect.</p> 261 * @param key The key name. 262 * @param value The key value. 263 */ 264 public static void put(final String key, final String value) { 265 contextMap.put(key, value); 266 } 267 268 /** 269 * Gets the context value identified by the <code>key</code> parameter. 270 * 271 * <p>This method has no side effects.</p> 272 * @param key The key to locate. 273 * @return The value associated with the key or null. 274 */ 275 public static String get(final String key) { 276 return contextMap.get(key); 277 } 278 279 /** 280 * Removes the context value identified by the <code>key</code> parameter. 281 * @param key The key to remove. 282 */ 283 public static void remove(final String key) { 284 contextMap.remove(key); 285 } 286 287 /** 288 * Clears the context map. 289 */ 290 public static void clearMap() { 291 contextMap.clear(); 292 } 293 294 /** 295 * Clears the context map and stack. 296 */ 297 public static void clearAll() { 298 clearMap(); 299 clearStack(); 300 } 301 302 /** 303 * Determines if the key is in the context. 304 * @param key The key to locate. 305 * @return True if the key is in the context, false otherwise. 306 */ 307 public static boolean containsKey(final String key) { 308 return contextMap.containsKey(key); 309 } 310 311 /** 312 * Returns a mutable copy of current thread's context Map. 313 * @return a mutable copy of the context. 314 */ 315 public static Map<String, String> getContext() { 316 return contextMap.getCopy(); 317 } 318 319 /** 320 * Returns an immutable view of the current thread's context Map. 321 * @return An immutable view of the ThreadContext Map. 322 */ 323 public static Map<String, String> getImmutableContext() { 324 final Map<String, String> map = contextMap.getImmutableMapOrNull(); 325 return map == null ? EMPTY_MAP : map; 326 } 327 328 /** 329 * Returns true if the Map is empty. 330 * @return true if the Map is empty, false otherwise. 331 */ 332 public static boolean isEmpty() { 333 return contextMap.isEmpty(); 334 } 335 336 /** 337 * Clears the stack for this thread. 338 */ 339 public static void clearStack() { 340 contextStack.clear(); 341 } 342 343 /** 344 * Returns a copy of this thread's stack. 345 * @return A copy of this thread's stack. 346 */ 347 public static ContextStack cloneStack() { 348 return contextStack.copy(); 349 } 350 351 /** 352 * Gets an immutable copy of this current thread's context stack. 353 * @return an immutable copy of the ThreadContext stack. 354 */ 355 public static ContextStack getImmutableStack() { 356 final ContextStack result = contextStack.getImmutableStackOrNull(); 357 return result == null ? EMPTY_STACK : result; 358 } 359 360 /** 361 * Sets this thread's stack. 362 * @param stack The stack to use. 363 */ 364 public static void setStack(final Collection<String> stack) { 365 if (stack.isEmpty() || !useStack) { 366 return; 367 } 368 contextStack.clear(); 369 contextStack.addAll(stack); 370 } 371 372 /** 373 * Gets the current nesting depth of this thread's stack. 374 * @return the number of items in the stack. 375 * 376 * @see #trim 377 */ 378 public static int getDepth() { 379 return contextStack.getDepth(); 380 } 381 382 /** 383 * Returns the value of the last item placed on the stack. 384 * 385 * <p>The returned value is the value that was pushed last. If no 386 * context is available, then the empty string "" is returned.</p> 387 * 388 * @return String The innermost diagnostic context. 389 */ 390 public static String pop() { 391 return contextStack.pop(); 392 } 393 394 /** 395 * Looks at the last diagnostic context at the top of this NDC 396 * without removing it. 397 * 398 * <p>The returned value is the value that was pushed last. If no 399 * context is available, then the empty string "" is returned.</p> 400 * 401 * @return String The innermost diagnostic context. 402 */ 403 public static String peek() { 404 return contextStack.peek(); 405 } 406 407 /** 408 * Pushes new diagnostic context information for the current thread. 409 * 410 * <p>The contents of the <code>message</code> parameter is 411 * determined solely by the client.</p> 412 * 413 * @param message The new diagnostic context information. 414 */ 415 public static void push(final String message) { 416 contextStack.push(message); 417 } 418 /** 419 * Pushes new diagnostic context information for the current thread. 420 * 421 * <p>The contents of the <code>message</code> and args parameters are 422 * determined solely by the client. The message will be treated as a format String 423 * and tokens will be replaced with the String value of the arguments in accordance 424 * with ParameterizedMessage.</p> 425 * 426 * @param message The new diagnostic context information. 427 * @param args Parameters for the message. 428 */ 429 public static void push(final String message, final Object... args) { 430 contextStack.push(ParameterizedMessage.format(message, args)); 431 } 432 433 /** 434 * Removes the diagnostic context for this thread. 435 * 436 * <p>Each thread that created a diagnostic context by calling 437 * {@link #push} should call this method before exiting. Otherwise, 438 * the memory used by the <b>thread</b> cannot be reclaimed by the 439 * VM.</p> 440 * 441 * <p>As this is such an important problem in heavy duty systems and 442 * because it is difficult to always guarantee that the remove 443 * method is called before exiting a thread, this method has been 444 * augmented to lazily remove references to dead threads. In 445 * practice, this means that you can be a little sloppy and 446 * occasionally forget to call {@link #remove} before exiting a 447 * thread. However, you must call <code>remove</code> sometime. If 448 * you never call it, then your application is sure to run out of 449 * memory.</p> 450 */ 451 public static void removeStack() { 452 contextStack.clear(); 453 } 454 455 /** 456 * Trims elements from this diagnostic context. If the current 457 * depth is smaller or equal to <code>maxDepth</code>, then no 458 * action is taken. If the current depth is larger than newDepth 459 * then all elements at maxDepth or higher are discarded. 460 * 461 * <p>This method is a convenient alternative to multiple {@link 462 * #pop} calls. Moreover, it is often the case that at the end of 463 * complex call sequences, the depth of the ThreadContext is 464 * unpredictable. The <code>trim</code> method circumvents 465 * this problem.</p> 466 * 467 * <p>For example, the combination</p> 468 * <pre> 469 * void foo() { 470 * final int depth = ThreadContext.getDepth(); 471 * 472 * // ... complex sequence of calls 473 * 474 * ThreadContext.trim(depth); 475 * } 476 * </pre> 477 * 478 * <p>ensures that between the entry and exit of {@code foo} the depth of the 479 * diagnostic stack is conserved.</p> 480 * 481 * @see #getDepth 482 * @param depth The number of elements to keep. 483 */ 484 public static void trim(final int depth) { 485 contextStack.trim(depth); 486 } 487 488 /** 489 * The ThreadContext Stack interface. 490 */ 491 public interface ContextStack extends Serializable, Collection<String> { 492 493 /** 494 * Returns the element at the top of the stack. 495 * @return The element at the top of the stack. 496 * @throws java.util.NoSuchElementException if the stack is empty. 497 */ 498 String pop(); 499 500 /** 501 * Returns the element at the top of the stack without removing it or null if the stack is empty. 502 * @return the element at the top of the stack or null if the stack is empty. 503 */ 504 String peek(); 505 506 /** 507 * Pushes an element onto the stack. 508 * @param message The element to add. 509 */ 510 void push(String message); 511 512 /** 513 * Returns the number of elements in the stack. 514 * @return the number of elements in the stack. 515 */ 516 int getDepth(); 517 518 /** 519 * Returns all the elements in the stack in a List. 520 * @return all the elements in the stack in a List. 521 */ 522 List<String> asList(); 523 524 /** 525 * Trims elements from the end of the stack. 526 * @param depth The maximum number of items in the stack to keep. 527 */ 528 void trim(int depth); 529 530 /** 531 * Returns a copy of the ContextStack. 532 * @return a copy of the ContextStack. 533 */ 534 ContextStack copy(); 535 536 /** 537 * Returns a ContextStack with the same contents as this ContextStack or {@code null}. 538 * Attempts to modify the returned stack may or may not throw an exception, but will not affect the contents 539 * of this ContextStack. 540 * @return a ContextStack with the same contents as this ContextStack or {@code null}. 541 */ 542 ContextStack getImmutableStackOrNull(); 543 } 544}