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實(shí)現(xiàn)了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques來實(shí)現(xiàn)
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,同時(shí)修改操作會(huì)同時(shí)調(diào)用nullifyReadOnlyThreadLocalMap,將readOnlyThreadLocalMap設(shè)置為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則新創(chuàng)建HashMap返回;getPropertyMap先從readOnlyThreadLocalMap讀取,如果readOnlyThreadLocalMap為null則從readWriteThreadLocalMap拷貝一份unmodifiableMap,并設(shè)置到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>>>實(shí)現(xiàn)的
小結(jié)
slf4j定義了MDCAdapter接口,該接口定義了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法;LogbackMDCAdapter實(shí)現(xiàn)了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques來實(shí)現(xiàn),其中put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques。
以上就是Logback MDCAdapter日志跟蹤及自定義效果源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于Logback MDCAdapter日志跟蹤的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Security OAuth 自定義授權(quán)方式實(shí)現(xiàn)手機(jī)驗(yàn)證碼
這篇文章主要介紹了Spring Security OAuth 自定義授權(quán)方式實(shí)現(xiàn)手機(jī)驗(yàn)證碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Springboot集成shiro之登錄攔截/權(quán)限控制方式
文章介紹了Shiro框架的的配置和使用,包括添加依賴、配置ShiroConfig、創(chuàng)建realm、配置安全管理器、配置過濾器和權(quán)限控制,還介紹了配置ehcache緩存、自定義加密和處理404重定向等問題,總結(jié)了Shiro框架中的常用配置和解決常見問題的方法2026-05-05
SpringBoot中的自定義FailureAnalyzer詳解
這篇文章主要介紹了SpringBoot中的自定義FailureAnalyzer詳解,FailureAnalyzer是一種很好的方式在啟動(dòng)時(shí)攔截異常并將其轉(zhuǎn)換為易讀的消息,并將其包含在FailureAnalysis中, Spring Boot為應(yīng)用程序上下文相關(guān)異常、JSR-303驗(yàn)證等提供了此類分析器,需要的朋友可以參考下2023-12-12
解析Tomcat 6、7在EL表達(dá)式解析時(shí)存在的一個(gè)Bug
這篇文章主要是對(duì)Tomcat 6、7在EL表達(dá)式解析時(shí)存在的一個(gè)Bug進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-12-12
解析Idea為什么不推薦使用@Autowired進(jìn)行Field注入
這篇文章主要介紹了Idea不推薦使用@Autowired進(jìn)行Field注入的原因,網(wǎng)上文章大部分都是介紹兩者的區(qū)別,沒有提到為什么,當(dāng)時(shí)想了好久想出了可能的原因,今天來總結(jié)一下2022-05-05
clickhouse?批量插入數(shù)據(jù)及ClickHouse常用命令詳解
這篇文章主要介紹了clickhouse?批量插入數(shù)據(jù)及ClickHouse常用命令,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
Java動(dòng)態(tài)規(guī)劃之編輯距離問題示例代碼
這篇文章主要介紹了Java動(dòng)態(tài)規(guī)劃之編輯距離問題示例代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11

