add support for keyed deques in MDC

Signed-off-by: Ceki Gulcu <ceki@qos.ch>
This commit is contained in:
Ceki Gulcu 2022-01-05 22:10:34 +01:00
parent 12b5a6b676
commit f09e33dd15
6 changed files with 131 additions and 35 deletions

View File

@ -25,6 +25,7 @@
package org.slf4j;
import java.io.Closeable;
import java.util.Deque;
import java.util.Map;
import org.slf4j.helpers.BasicMDCAdapter;
@ -64,6 +65,7 @@ import org.slf4j.spi.SLF4JServiceProvider;
public class MDC {
static final String NULL_MDCA_URL = "http://www.slf4j.org/codes.html#null_MDCA";
private static final String MDC_APAPTER_CANNOT_BE_NULL_MESSAGE = "MDCAdapter cannot be null. See also " + NULL_MDCA_URL;
static final String NO_STATIC_MDC_BINDER_URL = "http://www.slf4j.org/codes.html#no_static_mdc_binder";
static MDCAdapter mdcAdapter;
@ -116,7 +118,7 @@ public class MDC {
throw new IllegalArgumentException("key parameter cannot be null");
}
if (mdcAdapter == null) {
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.put(key, val);
}
@ -172,7 +174,7 @@ public class MDC {
}
if (mdcAdapter == null) {
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.get(key);
}
@ -193,7 +195,7 @@ public class MDC {
}
if (mdcAdapter == null) {
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.remove(key);
}
@ -203,7 +205,7 @@ public class MDC {
*/
public static void clear() {
if (mdcAdapter == null) {
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.clear();
}
@ -217,7 +219,7 @@ public class MDC {
*/
public static Map<String, String> getCopyOfContextMap() {
if (mdcAdapter == null) {
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.getCopyOfContextMap();
}
@ -235,7 +237,7 @@ public class MDC {
*/
public static void setContextMap(Map<String, String> contextMap) {
if (mdcAdapter == null) {
throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.setContextMap(contextMap);
}
@ -250,4 +252,48 @@ public class MDC {
return mdcAdapter;
}
/**
* 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
*/
static public void pushByKey(String key, String value) {
if (mdcAdapter == null) {
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
mdcAdapter.pushByKey(key, 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
*/
static public String popByKey(String key) {
if (mdcAdapter == null) {
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.popByKey(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) {
if (mdcAdapter == null) {
throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE);
}
return mdcAdapter.getCopyOfDequeByKey(key);
}
}

View File

@ -43,7 +43,7 @@ import java.util.*;
*/
public class BasicMDCAdapter implements MDCAdapter {
private final ThreadLocalMapOfStacks threadLocalMapOfStacks = new ThreadLocalMapOfStacks();
private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();
private final InheritableThreadLocal<Map<String, String>> inheritableThreadLocalMap = new InheritableThreadLocal<Map<String, String>>() {
@Override
@ -151,16 +151,20 @@ public class BasicMDCAdapter implements MDCAdapter {
@Override
public void pushByKey(String key, String value) {
threadLocalMapOfStacks.pushByKey(key, value);
threadLocalMapOfDeques.pushByKey(key, value);
}
@Override
public String popByKey(String key) {
return threadLocalMapOfStacks.popByKey(key);
return threadLocalMapOfDeques.popByKey(key);
}
@Override
public Deque<String> getCopyOfStackByKey(String key) {
return threadLocalMapOfStacks.getCopyOfStackByKey(key);
public Deque<String> getCopyOfDequeByKey(String key) {
return threadLocalMapOfDeques.getCopyOfDequeByKey(key);
}
@Override
public void clearDequeByKey(String key) {
threadLocalMapOfDeques.clearDequeByKey(key);
}
}

View File

@ -71,8 +71,11 @@ public class NOPMDCAdapter implements MDCAdapter {
}
@Override
public Deque<String> getCopyOfStackByKey(String key) {
public Deque<String> getCopyOfDequeByKey(String key) {
return null;
}
public void clearDequeByKey(String key) {
}
}

View File

@ -5,6 +5,14 @@ import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
/**
* A simple implementation of ThreadLocal backed Map containing values of type
* Deque<String>.
*
* @author Ceki Guuml;c&uuml;
* @since 2.0.0
*/
public class ThreadLocalMapOfStacks {
final ThreadLocal<Map<String, Deque<String>>> tlMapOfStacks = new ThreadLocal<>();
@ -20,12 +28,12 @@ public class ThreadLocalMapOfStacks {
tlMapOfStacks.set(map);
}
Deque<String> stack = map.get(key);
if (stack == null) {
stack = new ArrayDeque<>();
Deque<String> deque = map.get(key);
if (deque == null) {
deque = new ArrayDeque<>();
}
stack.push(value);
map.put(key, stack);
deque.push(value);
map.put(key, deque);
}
public String popByKey(String key) {
@ -35,24 +43,44 @@ public class ThreadLocalMapOfStacks {
Map<String, Deque<String>> map = tlMapOfStacks.get();
if (map == null)
return null;
Deque<String> stack = map.get(key);
if (stack == null)
Deque<String> deque = map.get(key);
if (deque == null)
return null;
return stack.pop();
return deque.pop();
}
public Deque<String> getCopyOfStackByKey(String key) {
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> stack = map.get(key);
if (stack == null)
Deque<String> deque = map.get(key);
if (deque == null)
return null;
return new ArrayDeque<String>(stack);
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();
}
}

View File

@ -93,8 +93,8 @@ public interface MDCAdapter {
public void setContextMap(Map<String, String> contextMap);
/**
* Push a value into the stack referenced by 'key'.
* *
* 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
@ -104,19 +104,30 @@ public interface MDCAdapter {
/**
* Pop the stack referenced by 'key' and return the value possibly null.
*
* @param key identifies the stack
* @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 stack referenced by 'key'. May be null.
* 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> getCopyOfStackByKey(String key);
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);
}

View File

@ -34,7 +34,7 @@ import org.slf4j.spi.MDCAdapter;
public class Log4jMDCAdapter implements MDCAdapter {
private final ThreadLocalMapOfStacks threadLocalMapOfStacks = new ThreadLocalMapOfStacks();
private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();
static {
if (VersionUtil.getJavaMajorVersion() >= 9) {
@ -113,17 +113,21 @@ public class Log4jMDCAdapter implements MDCAdapter {
@Override
public void pushByKey(String key, String value) {
threadLocalMapOfStacks.pushByKey(key, value);
threadLocalMapOfDeques.pushByKey(key, value);
}
@Override
public String popByKey(String key) {
return threadLocalMapOfStacks.popByKey(key);
return threadLocalMapOfDeques.popByKey(key);
}
@Override
public Deque<String> getCopyOfStackByKey(String key) {
return threadLocalMapOfStacks.getCopyOfStackByKey(key);
public Deque<String> getCopyOfDequeByKey(String key) {
return threadLocalMapOfDeques.getCopyOfDequeByKey(key);
}
@Override
public void clearDequeByKey(String key) {
threadLocalMapOfDeques.clearDequeByKey(key);
}
}