From f09e33dd15f60b4480d9a60bfb9083ef739fea2f Mon Sep 17 00:00:00 2001 From: Ceki Gulcu Date: Wed, 5 Jan 2022 22:10:34 +0100 Subject: [PATCH] add support for keyed deques in MDC Signed-off-by: Ceki Gulcu --- slf4j-api/src/main/java/org/slf4j/MDC.java | 58 +++++++++++++++++-- .../org/slf4j/helpers/BasicMDCAdapter.java | 14 +++-- .../java/org/slf4j/helpers/NOPMDCAdapter.java | 5 +- .../slf4j/helpers/ThreadLocalMapOfStacks.java | 52 +++++++++++++---- .../main/java/org/slf4j/spi/MDCAdapter.java | 21 +++++-- .../org/slf4j/log4j12/Log4jMDCAdapter.java | 16 +++-- 6 files changed, 131 insertions(+), 35 deletions(-) diff --git a/slf4j-api/src/main/java/org/slf4j/MDC.java b/slf4j-api/src/main/java/org/slf4j/MDC.java index 36fbf8cc..ec6cb76c 100644 --- a/slf4j-api/src/main/java/org/slf4j/MDC.java +++ b/slf4j-api/src/main/java/org/slf4j/MDC.java @@ -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 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 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 getCopyOfDequeByKey(String key) { + if (mdcAdapter == null) { + throw new IllegalStateException(MDC_APAPTER_CANNOT_BE_NULL_MESSAGE); + } + return mdcAdapter.getCopyOfDequeByKey(key); + } } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java b/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java index 77f6dfea..8cba7031 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/BasicMDCAdapter.java @@ -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> inheritableThreadLocalMap = new InheritableThreadLocal>() { @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 getCopyOfStackByKey(String key) { - return threadLocalMapOfStacks.getCopyOfStackByKey(key); + public Deque getCopyOfDequeByKey(String key) { + return threadLocalMapOfDeques.getCopyOfDequeByKey(key); + } + @Override + public void clearDequeByKey(String key) { + threadLocalMapOfDeques.clearDequeByKey(key); } } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/NOPMDCAdapter.java b/slf4j-api/src/main/java/org/slf4j/helpers/NOPMDCAdapter.java index 24cad696..7c34fca0 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/NOPMDCAdapter.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/NOPMDCAdapter.java @@ -71,8 +71,11 @@ public class NOPMDCAdapter implements MDCAdapter { } @Override - public Deque getCopyOfStackByKey(String key) { + public Deque getCopyOfDequeByKey(String key) { return null; } + + public void clearDequeByKey(String key) { + } } diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/ThreadLocalMapOfStacks.java b/slf4j-api/src/main/java/org/slf4j/helpers/ThreadLocalMapOfStacks.java index 9ab6852f..58eb71f7 100644 --- a/slf4j-api/src/main/java/org/slf4j/helpers/ThreadLocalMapOfStacks.java +++ b/slf4j-api/src/main/java/org/slf4j/helpers/ThreadLocalMapOfStacks.java @@ -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. + * + * @author Ceki Guuml;cü + * @since 2.0.0 + */ public class ThreadLocalMapOfStacks { final ThreadLocal>> tlMapOfStacks = new ThreadLocal<>(); @@ -20,12 +28,12 @@ public class ThreadLocalMapOfStacks { tlMapOfStacks.set(map); } - Deque stack = map.get(key); - if (stack == null) { - stack = new ArrayDeque<>(); + Deque 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> map = tlMapOfStacks.get(); if (map == null) return null; - Deque stack = map.get(key); - if (stack == null) + Deque deque = map.get(key); + if (deque == null) return null; - return stack.pop(); + return deque.pop(); } - public Deque getCopyOfStackByKey(String key) { + public Deque getCopyOfDequeByKey(String key) { if (key == null) return null; Map> map = tlMapOfStacks.get(); if (map == null) return null; - Deque stack = map.get(key); - if (stack == null) + Deque deque = map.get(key); + if (deque == null) return null; - return new ArrayDeque(stack); + return new ArrayDeque(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> map = tlMapOfStacks.get(); + if (map == null) + return; + Deque deque = map.get(key); + if (deque == null) + return; + deque.clear(); } } diff --git a/slf4j-api/src/main/java/org/slf4j/spi/MDCAdapter.java b/slf4j-api/src/main/java/org/slf4j/spi/MDCAdapter.java index 22f2dcb6..0ed14728 100644 --- a/slf4j-api/src/main/java/org/slf4j/spi/MDCAdapter.java +++ b/slf4j-api/src/main/java/org/slf4j/spi/MDCAdapter.java @@ -93,8 +93,8 @@ public interface MDCAdapter { public void setContextMap(Map 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 getCopyOfStackByKey(String key); + public Deque getCopyOfDequeByKey(String key); + + + /** + * Clear the deque(stack) referenced by 'key'. + * + * @param key identifies the stack + * + * @since 2.0.0 + */ + public void clearDequeByKey(String key); + } diff --git a/slf4j-log4j12/src/main/java/org/slf4j/log4j12/Log4jMDCAdapter.java b/slf4j-log4j12/src/main/java/org/slf4j/log4j12/Log4jMDCAdapter.java index 23b3d749..823399c6 100644 --- a/slf4j-log4j12/src/main/java/org/slf4j/log4j12/Log4jMDCAdapter.java +++ b/slf4j-log4j12/src/main/java/org/slf4j/log4j12/Log4jMDCAdapter.java @@ -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 getCopyOfStackByKey(String key) { - return threadLocalMapOfStacks.getCopyOfStackByKey(key); + public Deque getCopyOfDequeByKey(String key) { + return threadLocalMapOfDeques.getCopyOfDequeByKey(key); + } + + @Override + public void clearDequeByKey(String key) { + threadLocalMapOfDeques.clearDequeByKey(key); } - }