All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.qos.logback.classic.util.LogbackMDCAdapterSimple Maven / Gradle / Ivy

There is a newer version: 1.5.12
Show newest version
/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.classic.util;

import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.slf4j.helpers.ThreadLocalMapOfStacks;
import org.slf4j.spi.MDCAdapter;

/**
 * A Mapped Diagnostic Context, or MDC in short, is an instrument for
 * distinguishing interleaved log output from different sources. Log output is
 * typically interleaved when a server handles multiple clients
 * near-simultaneously.
 * 

* The MDC is managed on a per thread basis. Note that a child * thread does not inherit the mapped diagnostic context of its parent. *

*

* For more information about MDC, please refer to the online manual at * http://logback.qos.ch/manual/mdc.html * * @author Ceki Gülcü */ public class LogbackMDCAdapterSimple implements MDCAdapter { // We wish to avoid unnecessarily copying of the map. To ensure // efficient/timely copying, we have a variable keeping track of the previous // operation. A copy is necessary on 'put' or 'remove' but only if the last // operation was a 'get'. Get operations never necessitate a copy nor // successive 'put/remove' operations, only a get followed by a 'put/remove' // requires copying the map. // See http://jira.qos.ch/browse/LOGBACK-620 for the original discussion. // We no longer use CopyOnInheritThreadLocal in order to solve LBCLASSIC-183 // Initially the contents of the thread local in parent and child threads // reference the same map. However, as soon as a thread invokes the put() // method, the maps diverge as they should. // final ThreadLocal> modifiableMap = new ThreadLocal>(); final ThreadLocal> threadLocalUnmodifiableMap = new ThreadLocal>(); // private static final int WRITE_OPERATION = 1; // private static final int MAP_COPY_OPERATION = 2; // keeps track of the previous operation performed // final ThreadLocal previousOperation = new ThreadLocal(); private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks(); // private Integer getAndSetPreviousOperation(int op) { // Integer penultimateOp = previousOperation.get(); // previousOperation.set(op); // return penultimateOp; // } // private boolean wasPreviousOpReadOrNull(Integer lastOp) { // return lastOp == null || lastOp.intValue() == MAP_COPY_OPERATION; // } // private Map duplicateAndInsertNewMap(Map oldMap) { // Map newMap = duplicateOldMap(oldMap); // modifiableMap.set(newMap); // return newMap; // } private Map duplicateMap(Map oldMap) { if(oldMap != null) return new HashMap<>(oldMap); else return new HashMap<>(); } /** * Put a context value (the val parameter) as identified with the * key parameter into the current thread's context map. Note that * contrary to log4j, the val parameter can be null. *

*

* If the current thread does not have a context map it is created as a side * effect of this call. * * @throws IllegalArgumentException in case the "key" parameter is null */ public void put(String key, String val) throws IllegalArgumentException { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } Map oldMap = threadLocalUnmodifiableMap.get(); Map newMap = duplicateMap(oldMap); newMap.put(key, val); makeUnmodifiableAndThreadLocalSet(newMap); } private void makeUnmodifiableAndThreadLocalSet(Map aMap) { Map unmodifiable = Collections.unmodifiableMap(aMap); threadLocalUnmodifiableMap.set(unmodifiable); } /** * Remove the context identified by the key parameter. *

*/ public void remove(String key) { if (key == null) { return; } Map oldMap = threadLocalUnmodifiableMap.get(); if (oldMap == null) return; Map newMap = duplicateMap(oldMap); newMap.remove(key); makeUnmodifiableAndThreadLocalSet(newMap); } /** * Clear all entries in the MDC. */ public void clear() { threadLocalUnmodifiableMap.remove(); } /** * Get the context identified by the key parameter. *

*/ public String get(String key) { final Map map = threadLocalUnmodifiableMap.get(); if ((map != null) && (key != null)) { return map.get(key); } else { return null; } } /** * Get the current thread's MDC as a map. This method is intended to be used * internally. */ public Map getPropertyMap() { return threadLocalUnmodifiableMap.get(); } /** * Returns the keys in the MDC as a {@link Set}. The returned value can be null. */ public Set getKeys() { Map map = getPropertyMap(); if (map != null) { return map.keySet(); } else { return null; } } /** * Return a copy of the current thread's context map. Returned value may be * null. */ public Map getCopyOfContextMap() { Map hashMap = threadLocalUnmodifiableMap.get(); return duplicateMap(hashMap); } /** * Set the MDC map to the map passed as parameter. * * @param contextMap the new map */ public void setContextMap(Map contextMap) { duplicateMap(contextMap); } @Override public void pushByKey(String key, String value) { threadLocalMapOfDeques.pushByKey(key, value); } @Override public String popByKey(String key) { return threadLocalMapOfDeques.popByKey(key); } @Override public Deque getCopyOfDequeByKey(String key) { return threadLocalMapOfDeques.getCopyOfDequeByKey(key); } @Override public void clearDequeByKey(String key) { threadLocalMapOfDeques.clearDequeByKey(key); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy