Logback MDCAdapter日志跟踪及自定义效果源码解读
作者:codecraft
这篇文章主要为大家介绍了Logback MDCAdapter日志跟踪及自定义效果源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
序
本文主要研究一下LogbackMDCAdapter
MDCAdapter
org/slf4j/spi/MDCAdapter.java
public interface MDCAdapter { /** * Put a context value (the <code>val</code> parameter) as identified with * the <code>key</code> parameter into the current thread's context map. * The <code>key</code> parameter cannot be null. The <code>val</code> parameter * can be null only if the underlying implementation supports it. * * <p>If the current thread does not have a context map it is created as a side * effect of this call. */ public void put(String key, String val); /** * Get the context identified by the <code>key</code> parameter. * The <code>key</code> parameter cannot be null. * * @return the string value identified by the <code>key</code> parameter. */ public String get(String key); /** * Remove the context identified by the <code>key</code> parameter. * The <code>key</code> parameter cannot be null. * * <p> * This method does nothing if there is no previous value * associated with <code>key</code>. */ public void remove(String key); /** * Clear all entries in the MDC. */ public void clear(); /** * Return a copy of the current thread's context map, with keys and * values of type String. Returned value may be null. * * @return A copy of the current thread's context map. May be null. * @since 1.5.1 */ public Map<String, String> getCopyOfContextMap(); /** * Set the current thread's context map by first clearing any existing * map and then copying the map passed as parameter. The context map * parameter must only contain keys and values of type String. * * Implementations must support null valued map passed as parameter. * * @param contextMap must contain only keys and values of type String * * @since 1.5.1 */ public void setContextMap(Map<String, String> contextMap); /** * Push a value into the deque(stack) referenced by 'key'. * * @param key identifies the appropriate stack * @param value the value to push into the stack * @since 2.0.0 */ public void pushByKey(String key, String value); /** * Pop the stack referenced by 'key' and return the value possibly null. * * @param key identifies the deque(stack) * @return the value just popped. May be null/ * @since 2.0.0 */ public String popByKey(String key); /** * Returns a copy of the deque(stack) referenced by 'key'. May be null. * * @param key identifies the stack * @return copy of stack referenced by 'key'. May be null. * * @since 2.0.0 */ public Deque<String> getCopyOfDequeByKey(String key); /** * Clear the deque(stack) referenced by 'key'. * * @param key identifies the stack * * @since 2.0.0 */ public void clearDequeByKey(String key); }
slf4j定义了MDCAdapter接口,该接口定义了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法
LogbackMDCAdapter
ch/qos/logback/classic/util/LogbackMDCAdapter.java
public class LogbackMDCAdapter implements MDCAdapter { // BEWARE: Keys or values placed in a ThreadLocal should not be of a type/class // not included in the JDK. See also https://jira.qos.ch/browse/LOGBACK-450 final ThreadLocal<Map<String, String>> readWriteThreadLocalMap = new ThreadLocal<Map<String, String>>(); final ThreadLocal<Map<String, String>> readOnlyThreadLocalMap = new ThreadLocal<Map<String, String>>(); private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks(); //...... }
LogbackMDCAdapter实现了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques来实现
readWriteThreadLocalMap
public void put(String key, String val) throws IllegalArgumentException { if (key == null) { throw new IllegalArgumentException("key cannot be null"); } Map<String, String> current = readWriteThreadLocalMap.get(); if (current == null) { current = new HashMap<String, String>(); readWriteThreadLocalMap.set(current); } current.put(key, val); nullifyReadOnlyThreadLocalMap(); } @Override public String get(String key) { Map<String, String> hashMap = readWriteThreadLocalMap.get(); if ((hashMap != null) && (key != null)) { return hashMap.get(key); } else { return null; } } @Override public void remove(String key) { if (key == null) { return; } Map<String, String> current = readWriteThreadLocalMap.get(); if (current != null) { current.remove(key); nullifyReadOnlyThreadLocalMap(); } } @Override public void clear() { readWriteThreadLocalMap.set(null); nullifyReadOnlyThreadLocalMap(); } private void nullifyReadOnlyThreadLocalMap() { readOnlyThreadLocalMap.set(null); } public void setContextMap(Map contextMap) { if (contextMap != null) { readWriteThreadLocalMap.set(new HashMap<String, String>(contextMap)); } else { readWriteThreadLocalMap.set(null); } nullifyReadOnlyThreadLocalMap(); }
put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,同时修改操作会同时调用nullifyReadOnlyThreadLocalMap,将readOnlyThreadLocalMap设置为null
getCopyOfContextMap
public Map getCopyOfContextMap() { Map<String, String> readOnlyMap = getPropertyMap(); if (readOnlyMap == null) { return null; } else { return new HashMap<String, String>(readOnlyMap); } } public Map<String, String> getPropertyMap() { Map<String, String> readOnlyMap = readOnlyThreadLocalMap.get(); if (readOnlyMap == null) { Map<String, String> current = readWriteThreadLocalMap.get(); if (current != null) { final Map<String, String> tempMap = new HashMap<String, String>(current); readOnlyMap = Collections.unmodifiableMap(tempMap); readOnlyThreadLocalMap.set(readOnlyMap); } } return readOnlyMap; }
getCopyOfContextMap方法通过getPropertyMap获取,如果不为null则新创建HashMap返回;getPropertyMap先从readOnlyThreadLocalMap读取,如果readOnlyThreadLocalMap为null则从readWriteThreadLocalMap拷贝一份unmodifiableMap,并设置到readOnlyThreadLocalMap
threadLocalMapOfDeques
@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<String> getCopyOfDequeByKey(String key) { return threadLocalMapOfDeques.getCopyOfDequeByKey(key); } @Override public void clearDequeByKey(String key) { threadLocalMapOfDeques.clearDequeByKey(key); }
pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques,它是ThreadLocalMapOfStacks类型
ThreadLocalMapOfStacks
org/slf4j/helpers/ThreadLocalMapOfStacks.java
public class ThreadLocalMapOfStacks { // BEWARE: Keys or values placed in a ThreadLocal should not be of a type/class // not included in the JDK. See also https://jira.qos.ch/browse/LOGBACK-450 final ThreadLocal<Map<String, Deque<String>>> tlMapOfStacks = new ThreadLocal<>(); public void pushByKey(String key, String value) { if (key == null) return; Map<String, Deque<String>> map = tlMapOfStacks.get(); if (map == null) { map = new HashMap<>(); tlMapOfStacks.set(map); } Deque<String> deque = map.get(key); if (deque == null) { deque = new ArrayDeque<>(); } deque.push(value); map.put(key, deque); } public String popByKey(String key) { if (key == null) return null; Map<String, Deque<String>> map = tlMapOfStacks.get(); if (map == null) return null; Deque<String> deque = map.get(key); if (deque == null) return null; return deque.pop(); } public Deque<String> getCopyOfDequeByKey(String key) { if (key == null) return null; Map<String, Deque<String>> map = tlMapOfStacks.get(); if (map == null) return null; Deque<String> deque = map.get(key); if (deque == null) return null; return new ArrayDeque<String>(deque); } /** * Clear the deque(stack) referenced by 'key'. * * @param key identifies the stack * * @since 2.0.0 */ public void clearDequeByKey(String key) { if (key == null) return; Map<String, Deque<String>> map = tlMapOfStacks.get(); if (map == null) return; Deque<String> deque = map.get(key); if (deque == null) return; deque.clear(); } }
ThreadLocalMapOfStacks是slf4j定义的,基于ThreadLocal<Map<String, Deque<String>>>实现的
小结
slf4j定义了MDCAdapter接口,该接口定义了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法;LogbackMDCAdapter实现了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques来实现,其中put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques。
以上就是Logback MDCAdapter日志跟踪及自定义效果源码解读的详细内容,更多关于Logback MDCAdapter日志跟踪的资料请关注脚本之家其它相关文章!