From 0fddb7139d2e4845b3dc347479fe6edd3359ddf4 Mon Sep 17 00:00:00 2001 From: "James R. Perkins" Date: Thu, 8 Jun 2023 12:33:56 -0700 Subject: [PATCH] [36] Override the ThreadContextMap in the provider. resolves #36 Signed-off-by: James R. Perkins --- .../jboss/logmanager/log4j/JBossLogger.java | 11 +-- .../jboss/logmanager/log4j/JBossProvider.java | 11 +++ .../logmanager/log4j/ThreadContextMDCMap.java | 78 +++++++++++++++++ .../log4j/ThreadContextMapTestCase.java | 87 ++++++++++++++++++- 4 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/jboss/logmanager/log4j/ThreadContextMDCMap.java diff --git a/src/main/java/org/jboss/logmanager/log4j/JBossLogger.java b/src/main/java/org/jboss/logmanager/log4j/JBossLogger.java index 94f9633..de58cad 100644 --- a/src/main/java/org/jboss/logmanager/log4j/JBossLogger.java +++ b/src/main/java/org/jboss/logmanager/log4j/JBossLogger.java @@ -20,7 +20,6 @@ package org.jboss.logmanager.log4j; import java.util.Collections; -import java.util.Iterator; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; @@ -164,14 +163,6 @@ private String getNdc() { if (contextStack.isEmpty()) { return ""; } - final StringBuilder result = new StringBuilder(); - final Iterator iter = contextStack.iterator(); - while (iter.hasNext()) { - result.append(iter.next()); - if (iter.hasNext()) { - result.append('.'); - } - } - return result.toString(); + return String.join(".", contextStack); } } diff --git a/src/main/java/org/jboss/logmanager/log4j/JBossProvider.java b/src/main/java/org/jboss/logmanager/log4j/JBossProvider.java index dbed6bd..fe3897c 100644 --- a/src/main/java/org/jboss/logmanager/log4j/JBossProvider.java +++ b/src/main/java/org/jboss/logmanager/log4j/JBossProvider.java @@ -20,6 +20,7 @@ package org.jboss.logmanager.log4j; import org.apache.logging.log4j.spi.Provider; +import org.apache.logging.log4j.spi.ThreadContextMap; /** * @author James R. Perkins @@ -29,4 +30,14 @@ public class JBossProvider extends Provider { public JBossProvider() { super(500, "2.6.0", JBossLoggerContextFactory.class); } + + @Override + public String getThreadContextMap() { + return ThreadContextMDCMap.class.getName(); + } + + @Override + public Class loadThreadContextMap() { + return ThreadContextMDCMap.class; + } } diff --git a/src/main/java/org/jboss/logmanager/log4j/ThreadContextMDCMap.java b/src/main/java/org/jboss/logmanager/log4j/ThreadContextMDCMap.java new file mode 100644 index 0000000..1b25b77 --- /dev/null +++ b/src/main/java/org/jboss/logmanager/log4j/ThreadContextMDCMap.java @@ -0,0 +1,78 @@ +/* + * JBoss, Home of Professional Open Source. + * + * Copyright 2023 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jboss.logmanager.log4j; + +import java.util.Map; + +import org.apache.logging.log4j.spi.ThreadContextMap; +import org.jboss.logmanager.MDC; + +/** + * A {@link ThreadContextMap} implementation which delegates to {@link MDC}. + * + * @author James R. Perkins + */ +public class ThreadContextMDCMap implements ThreadContextMap { + @Override + public void clear() { + MDC.clear(); + } + + @Override + public boolean containsKey(final String key) { + return MDC.get(key) != null; + } + + @Override + public String get(final String key) { + return MDC.get(key); + } + + @Override + public Map getCopy() { + return MDC.copy(); + } + + @Override + public Map getImmutableMapOrNull() { + final Map copy = MDC.copy(); + return copy.isEmpty() ? null : copy; + } + + @Override + public boolean isEmpty() { + // Performance here is not great, but we need to use it as MDC.isEmpty() is not available in the log manager + return MDC.copy().isEmpty(); + } + + @Override + public void put(final String key, final String value) { + if (value == null) { + MDC.remove(key); + } else { + MDC.put(key, value); + } + } + + @Override + public void remove(final String key) { + MDC.remove(key); + } +} diff --git a/src/test/java/org/jboss/logmanager/log4j/ThreadContextMapTestCase.java b/src/test/java/org/jboss/logmanager/log4j/ThreadContextMapTestCase.java index 4cdb3d5..0dc3e05 100644 --- a/src/test/java/org/jboss/logmanager/log4j/ThreadContextMapTestCase.java +++ b/src/test/java/org/jboss/logmanager/log4j/ThreadContextMapTestCase.java @@ -22,8 +22,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.ThreadContext; +import org.jboss.logmanager.MDC; +import org.jboss.logmanager.NDC; import org.jboss.logmanager.formatters.PatternFormatter; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** @@ -31,8 +34,41 @@ */ public class ThreadContextMapTestCase extends AbstractTestCase { + @BeforeEach + public void clear() { + ThreadContext.clearAll(); + MDC.clear(); + NDC.clear(); + } + @Test - public void testPut() { + public void clearThreadContext() { + final String key = "test.clear.key"; + ThreadContext.put(key, "test clear value"); + + Assertions.assertEquals("test clear value", ThreadContext.get(key)); + Assertions.assertEquals("test clear value", MDC.get(key)); + + ThreadContext.clearMap(); + Assertions.assertTrue(ThreadContext.isEmpty()); + Assertions.assertTrue(MDC.copy().isEmpty()); + } + + @Test + public void clearMdc() { + final String key = "test.clear.key"; + ThreadContext.put(key, "test clear value"); + + Assertions.assertEquals("test clear value", ThreadContext.get(key)); + Assertions.assertEquals("test clear value", MDC.get(key)); + + MDC.clear(); + Assertions.assertTrue(ThreadContext.isEmpty()); + Assertions.assertTrue(MDC.copy().isEmpty()); + } + + @Test + public void putThreadContext() { final String key = "test.key"; final TestQueueHandler handler = new TestQueueHandler(new PatternFormatter("%X{" + key + "}")); org.jboss.logmanager.Logger.getLogger("").addHandler(handler); @@ -51,7 +87,26 @@ public void testPut() { } @Test - public void testPush() { + public void putMdc() { + final String key = "test.key"; + final TestQueueHandler handler = new TestQueueHandler(new PatternFormatter("%X{" + key + "}")); + org.jboss.logmanager.Logger.getLogger("").addHandler(handler); + MDC.put(key, "test value"); + + final Logger logger = LogManager.getLogger(); + + logger.info("Test message"); + + Assertions.assertEquals("test value", handler.pollFormatted()); + + ThreadContext.remove(key); + + logger.info("Test message"); + Assertions.assertEquals("", handler.pollFormatted()); + } + + @Test + public void pushThreadContext() { final TestQueueHandler handler = new TestQueueHandler(new PatternFormatter("%x")); org.jboss.logmanager.Logger.getLogger("").addHandler(handler); @@ -71,4 +126,32 @@ public void testPush() { Assertions.assertEquals("value-1.value-2", handler.pollFormatted()); } + @Test + public void removeThreadContext() { + final String key = "test.clear.key"; + ThreadContext.put(key, "test clear value"); + + Assertions.assertEquals("test clear value", ThreadContext.get(key)); + Assertions.assertEquals("test clear value", MDC.get(key)); + + ThreadContext.remove(key); + + Assertions.assertNull(ThreadContext.get(key)); + Assertions.assertNull(MDC.get(key)); + } + + @Test + public void removeMdc() { + final String key = "test.clear.key"; + MDC.put(key, "test clear value"); + + Assertions.assertEquals("test clear value", ThreadContext.get(key)); + Assertions.assertEquals("test clear value", MDC.get(key)); + + MDC.remove(key); + + Assertions.assertNull(ThreadContext.get(key)); + Assertions.assertNull(MDC.get(key)); + } + }