This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch recycler-api-3.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 7cdd07593178281d69afda32746a3452016f5a41
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Fri Mar 24 22:24:46 2023 +0100

    More structural fixes
---
 .../logging/log4j/spi/RecyclerFactoriesTest.java   | 101 +++++++++++++++
 .../log4j/spi/ThreadLocalRecyclerFactoryTest.java  |  36 +++---
 .../log4j/util/StringParameterParserTest.java      |  49 +++-----
 .../logging/log4j/message/MessageFactory.java      |   4 +-
 .../message/ReusableParameterizedMessage.java      |   5 +-
 .../apache/logging/log4j/spi/AbstractLogger.java   |   5 +-
 .../logging/log4j/spi/QueueingRecyclerFactory.java |  14 ++-
 .../logging/log4j/spi/RecyclerFactories.java       |  64 ++++------
 .../log4j/spi/ThreadLocalRecyclerFactory.java      |  16 +--
 .../apache/logging/log4j/status/StatusLogger.java  |   4 +-
 .../util/{Queues.java => QueueFactories.java}      | 106 ++++++++++------
 .../apache/logging/log4j/util/QueueFactory.java    |   9 ++
 .../logging/log4j/util/StringParameterParser.java  |  15 +--
 .../logging/log4j/core/impl/MutableLogEvent.java   |   3 +-
 .../logging/log4j/spi/RecyclerFactoriesTest.java   | 140 ---------------------
 .../java/org/apache/logging/slf4j/SLF4JLogger.java |  11 +-
 16 files changed, 290 insertions(+), 292 deletions(-)

diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
new file mode 100644
index 0000000000..265b5cb16f
--- /dev/null
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.logging.log4j.spi;
+
+import java.util.ArrayDeque;
+import java.util.concurrent.ArrayBlockingQueue;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class RecyclerFactoriesTest {
+
+    @Test
+    void DummyRecyclerFactory_should_work() {
+        final Object actualDummyRecyclerFactory = 
RecyclerFactories.ofSpec("dummy");
+        Assertions
+                .assertThat(actualDummyRecyclerFactory)
+                .isSameAs(DummyRecyclerFactory.getInstance());
+    }
+
+    @Test
+    void ThreadLocalRecyclerFactory_should_work() {
+        final Object actualThreadLocalRecyclerFactory = 
RecyclerFactories.ofSpec("threadLocal");
+        Assertions
+                .assertThat(actualThreadLocalRecyclerFactory)
+                .isSameAs(ThreadLocalRecyclerFactory.getInstance());
+    }
+
+    @Test
+    void QueueingRecyclerFactory_should_work() {
+        final Object actualQueueingRecyclerFactory = 
RecyclerFactories.ofSpec("queue");
+        Assertions
+                .assertThat(actualQueueingRecyclerFactory)
+                .isInstanceOf(QueueingRecyclerFactory.class);
+    }
+
+    @Test
+    void QueueingRecyclerFactory_should_work_with_supplier() {
+        final Object recyclerFactory = 
RecyclerFactories.ofSpec("queue:supplier=java.util.ArrayDeque.new");
+        Assertions
+                .assertThat(recyclerFactory)
+                .isInstanceOf(QueueingRecyclerFactory.class);
+        final QueueingRecyclerFactory queueingRecyclerFactory = 
(QueueingRecyclerFactory) recyclerFactory;
+        final Recycler<Object> recycler = 
queueingRecyclerFactory.create(Object::new);
+        Assertions
+                .assertThat(recycler)
+                .isInstanceOf(QueueingRecyclerFactory.QueueingRecycler.class);
+        final QueueingRecyclerFactory.QueueingRecycler<Object> 
queueingRecycler =
+                (QueueingRecyclerFactory.QueueingRecycler<Object>) recycler;
+        Assertions
+                .assertThat(queueingRecycler.getQueue())
+                .isInstanceOf(ArrayDeque.class);
+    }
+
+    @Test
+    void QueueingRecyclerFactory_should_work_with_capacity() {
+        final Object actualQueueingRecyclerFactory = 
RecyclerFactories.ofSpec("queue:capacity=100");
+        Assertions
+                .assertThat(actualQueueingRecyclerFactory)
+                .isInstanceOf(QueueingRecyclerFactory.class);
+    }
+
+    @Test
+    void QueueingRecyclerFactory_should_work_with_supplier_and_capacity() {
+        final Object recyclerFactory = RecyclerFactories.ofSpec(
+                "queue:" +
+                        
"supplier=java.util.concurrent.ArrayBlockingQueue.new," +
+                        "capacity=100");
+        Assertions
+                .assertThat(recyclerFactory)
+                .isInstanceOf(QueueingRecyclerFactory.class);
+        final QueueingRecyclerFactory queueingRecyclerFactory = 
(QueueingRecyclerFactory) recyclerFactory;
+        final Recycler<Object> recycler = 
queueingRecyclerFactory.create(Object::new);
+        Assertions
+                .assertThat(recycler)
+                .isInstanceOf(QueueingRecyclerFactory.QueueingRecycler.class);
+        final QueueingRecyclerFactory.QueueingRecycler<Object> 
queueingRecycler =
+                (QueueingRecyclerFactory.QueueingRecycler<Object>) recycler;
+        Assertions
+                .assertThat(queueingRecycler.getQueue())
+                .isInstanceOf(ArrayBlockingQueue.class);
+        final ArrayBlockingQueue<Object> queue = (ArrayBlockingQueue<Object>) 
queueingRecycler.getQueue();
+        Assertions.assertThat(queue.remainingCapacity()).isEqualTo(100);
+
+    }
+
+}
diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactoryTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactoryTest.java
index b7ab339375..71334fdb90 100644
--- 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactoryTest.java
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactoryTest.java
@@ -30,44 +30,38 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 class ThreadLocalRecyclerFactoryTest {
 
-    static class RecyclableObject {
-        boolean using;
-        boolean returned;
-    }
+    private static class RecyclableObject {}
 
     private Recycler<RecyclableObject> recycler;
 
-    private Queue<RecyclableObject> getRecyclerQueue() {
-        return 
((ThreadLocalRecyclerFactory.ThreadLocalRecycler<RecyclableObject>) 
recycler).getQueue();
-    }
+    private Queue<RecyclableObject> recyclerQueue;
 
     @BeforeEach
     void setUp() {
-        recycler = 
ThreadLocalRecyclerFactory.getInstance().create(RecyclableObject::new, object 
-> {
-            object.using = true;
-            object.returned = false;
-        });
+        recycler = 
ThreadLocalRecyclerFactory.getInstance().create(RecyclableObject::new);
+        recyclerQueue = 
((ThreadLocalRecyclerFactory.ThreadLocalRecycler<RecyclableObject>) 
recycler).getQueue();
     }
 
     @ParameterizedTest
     @IntRangeSource(from = 1, to = ThreadLocalRecyclerFactory.MAX_QUEUE_SIZE, 
closed = true)
-    void nestedAcquiresDoNotInterfere(int acquisitionCount) {
+    void nested_acquires_should_not_interfere(final int acquisitionCount) {
+
         // pool should start empty
-        assertThat(getRecyclerQueue()).isEmpty();
+        assertThat(recyclerQueue).isEmpty();
 
         final List<RecyclableObject> acquiredObjects = IntStream.range(0, 
acquisitionCount)
                 .mapToObj(i -> recycler.acquire())
                 .collect(Collectors.toList());
 
         // still nothing returned to pool
-        assertThat(getRecyclerQueue()).isEmpty();
+        assertThat(recyclerQueue).isEmpty();
 
         // don't want any duplicate instances
         
assertThat(acquiredObjects).containsOnlyOnceElementsOf(acquiredObjects);
         acquiredObjects.forEach(recycler::release);
 
         // and now they should be back in the pool
-        assertThat(getRecyclerQueue()).hasSize(acquisitionCount);
+        assertThat(recyclerQueue).hasSize(acquisitionCount);
 
         // then reacquire them to see that they're still the same object as 
we've filled in
         // the thread-local queue with returned objects
@@ -76,11 +70,13 @@ class ThreadLocalRecyclerFactoryTest {
                 .collect(Collectors.toList());
 
         
assertThat(reacquiredObjects).containsExactlyElementsOf(acquiredObjects);
+
     }
 
     @Test
-    void nestedAcquiresPastMaximumQueueSizeShouldDiscardExtraReleases() {
-        assertThat(getRecyclerQueue()).isEmpty();
+    void nested_acquires_past_max_queue_size_should_discard_extra_releases() {
+
+        assertThat(recyclerQueue).isEmpty();
 
         // simulate a massively callstack with tons of logging
         final List<RecyclableObject> acquiredObjects = IntStream.range(0, 1024)
@@ -88,13 +84,15 @@ class ThreadLocalRecyclerFactoryTest {
                 .collect(Collectors.toList());
 
         // still nothing returned to pool
-        assertThat(getRecyclerQueue()).isEmpty();
+        assertThat(recyclerQueue).isEmpty();
 
         // don't want any duplicate instances
         
assertThat(acquiredObjects).containsOnlyOnceElementsOf(acquiredObjects);
         acquiredObjects.forEach(recycler::release);
 
         // upon return, we should only have 
ThreadLocalRecyclerFactory.MAX_QUEUE_SIZE retained for future use
-        
assertThat(getRecyclerQueue()).hasSize(ThreadLocalRecyclerFactory.MAX_QUEUE_SIZE);
+        
assertThat(recyclerQueue).hasSize(ThreadLocalRecyclerFactory.MAX_QUEUE_SIZE);
+
     }
+
 }
diff --git 
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java
similarity index 88%
rename from 
log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java
rename to 
log4j-api-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java
index 9e17e08e12..e37dc0a159 100644
--- 
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/StringParameterParserTest.java
@@ -16,18 +16,9 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.logging.log4j.util.StringParameterParser;
-import 
org.apache.logging.log4j.util.StringParameterParser.DoubleQuotedStringValue;
-import org.apache.logging.log4j.util.StringParameterParser.NullValue;
-import org.apache.logging.log4j.util.StringParameterParser.StringValue;
-import org.apache.logging.log4j.util.StringParameterParser.Value;
-import org.apache.logging.log4j.util.StringParameterParser.Values;
+import java.util.*;
+
+import org.apache.logging.log4j.util.StringParameterParser.*;
 import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -94,7 +85,7 @@ class StringParameterParserTest {
     void test_null_value_2() {
         testSuccess(
                 "a,b=c,d=",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.nullValue());
                     put("b", Values.stringValue("c"));
                     put("d", Values.nullValue());
@@ -105,7 +96,7 @@ class StringParameterParserTest {
     void test_null_value_3() {
         testSuccess(
                 "a,b=c,d",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.nullValue());
                     put("b", Values.stringValue("c"));
                     put("d", Values.nullValue());
@@ -116,7 +107,7 @@ class StringParameterParserTest {
     void test_null_value_4() {
         testSuccess(
                 "a,b=\"c,=\\\"\",d=,e=f",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.nullValue());
                     put("b", Values.doubleQuotedStringValue("c,=\""));
                     put("d", Values.nullValue());
@@ -128,7 +119,7 @@ class StringParameterParserTest {
     void test_two_pairs() {
         testSuccess(
                 "a=b,c=d",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.stringValue("b"));
                     put("c", Values.stringValue("d"));
                 }});
@@ -145,7 +136,7 @@ class StringParameterParserTest {
     void test_quoted_string_02() {
         testSuccess(
                 "a=\"b\",c=d",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("b"));
                     put("c", Values.stringValue("d"));
                 }});
@@ -155,7 +146,7 @@ class StringParameterParserTest {
     void test_quoted_string_03() {
         testSuccess(
                 "a=b,c=\"d\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.stringValue("b"));
                     put("c", Values.doubleQuotedStringValue("d"));
                 }});
@@ -165,7 +156,7 @@ class StringParameterParserTest {
     void test_quoted_string_04() {
         testSuccess(
                 "a=\"b\",c=\"d\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("b"));
                     put("c", Values.doubleQuotedStringValue("d"));
                 }});
@@ -189,7 +180,7 @@ class StringParameterParserTest {
     void test_quoted_string_07() {
         testSuccess(
                 "a=\"\\\"b\",c=d",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b"));
                     put("c", Values.stringValue("d"));
                 }});
@@ -209,7 +200,7 @@ class StringParameterParserTest {
     void test_quoted_string_09() {
         testSuccess(
                 "a=\"\\\"b,\",c=d",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b,"));
                     put("c", Values.stringValue("d"));
                 }});
@@ -219,7 +210,7 @@ class StringParameterParserTest {
     void test_quoted_string_10() {
         testSuccess(
                 "a=\"\\\"b\\\",\",c=d",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b\","));
                     put("c", Values.stringValue("d"));
                 }});
@@ -229,7 +220,7 @@ class StringParameterParserTest {
     void test_quoted_string_11() {
         testSuccess(
                 "a=\"\\\"b\",c=\"d\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b"));
                     put("c", Values.doubleQuotedStringValue("d"));
                 }});
@@ -239,7 +230,7 @@ class StringParameterParserTest {
     void test_quoted_string_12() {
         testSuccess(
                 "a=\"\\\"b\\\"\",c=\"d\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b\""));
                     put("c", Values.doubleQuotedStringValue("d"));
                 }});
@@ -259,7 +250,7 @@ class StringParameterParserTest {
     void test_quoted_string_14() {
         testSuccess(
                 "a=\"\\\"b\\\",\",c=\"\\\"d\\\"\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b\","));
                     put("c", Values.doubleQuotedStringValue("\"d\""));
                 }});
@@ -269,7 +260,7 @@ class StringParameterParserTest {
     void test_quoted_string_15() {
         testSuccess(
                 "a=\"\\\"b\",c=\",d\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b"));
                     put("c", Values.doubleQuotedStringValue(",d"));
                 }});
@@ -279,7 +270,7 @@ class StringParameterParserTest {
     void test_quoted_string_16() {
         testSuccess(
                 "a=\"\\\"b\\\"\",c=\",d\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b\""));
                     put("c", Values.doubleQuotedStringValue(",d"));
                 }});
@@ -289,7 +280,7 @@ class StringParameterParserTest {
     void test_quoted_string_17() {
         testSuccess(
                 "a=\"\\\"b,\",c=\"\\\"d,\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b,"));
                     put("c", Values.doubleQuotedStringValue("\"d,"));
                 }});
@@ -299,7 +290,7 @@ class StringParameterParserTest {
     void test_quoted_string_18() {
         testSuccess(
                 "a=\"\\\"b\\\",\",c=\"\\\"d\\\",\"",
-                new LinkedHashMap<String, Value>() {{
+                new LinkedHashMap<>() {{
                     put("a", Values.doubleQuotedStringValue("\"b\","));
                     put("c", Values.doubleQuotedStringValue("\"d\","));
                 }});
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java
index 142d63b1d3..fa777d3110 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/MessageFactory.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.message;
 
+import org.apache.logging.log4j.spi.Recycler;
+
 /**
  * Creates messages. Implementations can provide different message format 
syntaxes.
  * If messages created by an implementation are reusable, then the {@link 
#recycle(Message)} method must
@@ -243,7 +245,7 @@ public interface MessageFactory {
      * Recycles a message back for potential reuse or cleanup.
      *
      * @since 3.0.0
-     * @see org.apache.logging.log4j.spi.Recycler
+     * @see Recycler
      */
     default void recycle(Message message) {
         if (message instanceof ReusableMessage) {
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
index 24982934d2..4318a81b48 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/ReusableParameterizedMessage.java
@@ -46,7 +46,7 @@ public class ReusableParameterizedMessage implements 
ReusableMessage, ParameterV
     private Object[] params = new Object[MAX_PARMS];
     private Throwable throwable;
 
-    private final Recycler<StringBuilder> bufferRecycler; // non-static: 
LOG4J2-1583
+    private final Recycler<StringBuilder> bufferRecycler;
 
     /**
      * Creates a reusable message.
@@ -59,7 +59,8 @@ public class ReusableParameterizedMessage implements 
ReusableMessage, ParameterV
         bufferRecycler = recyclerFactory.create(
                 () -> {
                     final int currentPatternLength = messagePattern == null ? 
0 : messagePattern.length();
-                    return new StringBuilder(Math.max(MIN_BUILDER_SIZE, 
currentPatternLength * 2));
+                    int capacity = Math.max(MIN_BUILDER_SIZE, 
Math.multiplyExact(currentPatternLength, 2));
+                    return new StringBuilder(capacity);
                 },
                 buffer -> {
                     StringBuilders.trimToMaxSize(buffer, 
Constants.MAX_REUSABLE_MESSAGE_SIZE);
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
index 043da09bc6..06277b481d 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractLogger.java
@@ -69,7 +69,8 @@ public abstract class AbstractLogger implements 
ExtendedLogger {
     private final MessageFactory messageFactory;
     private final FlowMessageFactory flowMessageFactory;
     private static final ThreadLocal<int[]> recursionDepthHolder = new 
ThreadLocal<>(); // LOG4J2-1518, LOG4J2-2031
-    protected final Recycler<LogBuilder> recycler = 
LoggingSystem.getRecyclerFactory()
+    protected final Recycler<DefaultLogBuilder> recycler = LoggingSystem
+            .getRecyclerFactory()
             .create(() -> new DefaultLogBuilder(this, null));
 
     /**
@@ -2747,7 +2748,7 @@ public abstract class AbstractLogger implements 
ExtendedLogger {
      * @since 2.20.0
      */
     protected LogBuilder getLogBuilder(Level level) {
-        DefaultLogBuilder builder = (DefaultLogBuilder) recycler.acquire();
+        DefaultLogBuilder builder = recycler.acquire();
         return builder.reset(this, level);
     }
 
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/QueueingRecyclerFactory.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/QueueingRecyclerFactory.java
index 7579566ef1..e0b5a17a42 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/QueueingRecyclerFactory.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/QueueingRecyclerFactory.java
@@ -22,21 +22,28 @@ import java.util.function.Supplier;
 
 import org.apache.logging.log4j.util.QueueFactory;
 
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A {@link RecyclerFactory} pooling objects in a queue created using the 
provided {@link QueueFactory}.
+ */
 public class QueueingRecyclerFactory implements RecyclerFactory {
 
     private final QueueFactory queueFactory;
 
     public QueueingRecyclerFactory(final QueueFactory queueFactory) {
-        this.queueFactory = queueFactory;
+        this.queueFactory = requireNonNull(queueFactory, "queueFactory");
     }
 
     @Override
     public <V> Recycler<V> create(final Supplier<V> supplier, final 
Consumer<V> cleaner) {
+        requireNonNull(supplier, "supplier");
+        requireNonNull(cleaner, "cleaner");
         final Queue<V> queue = queueFactory.create();
         return new QueueingRecycler<>(supplier, cleaner, queue);
     }
 
-    // Visible for tests.
+    // Visible for tests
     static class QueueingRecycler<V> implements Recycler<V> {
 
         private final Supplier<V> supplier;
@@ -54,7 +61,7 @@ public class QueueingRecyclerFactory implements 
RecyclerFactory {
             this.queue = queue;
         }
 
-        // Visible for tests.
+        // Visible for tests
         Queue<V> getQueue() {
             return queue;
         }
@@ -67,6 +74,7 @@ public class QueueingRecyclerFactory implements 
RecyclerFactory {
 
         @Override
         public void release(final V value) {
+            requireNonNull(value, "value");
             cleaner.accept(value);
             queue.offer(value);
         }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/RecyclerFactories.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/RecyclerFactories.java
index 665bd2b215..55510019c8 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/RecyclerFactories.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/RecyclerFactories.java
@@ -19,26 +19,24 @@ package org.apache.logging.log4j.spi;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.logging.log4j.util.QueueFactories;
 import org.apache.logging.log4j.util.QueueFactory;
-import org.apache.logging.log4j.util.Queues;
 import org.apache.logging.log4j.util.StringParameterParser;
 
 import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled;
 
 public final class RecyclerFactories {
 
-    private RecyclerFactories() {}
+    private static final int DEFAULT_QUEUE_CAPACITY = Math.max(
+            2 * Runtime.getRuntime().availableProcessors() + 1,
+            8);
 
-    private static int getDefaultCapacity() {
-        return Math.max(
-                2 * Runtime.getRuntime().availableProcessors() + 1,
-                8);
-    }
+    private RecyclerFactories() {}
 
     public static RecyclerFactory getDefault() {
         return isThreadLocalsEnabled()
                 ? ThreadLocalRecyclerFactory.getInstance()
-                : new 
QueueingRecyclerFactory(Queues.MPMC.factory(getDefaultCapacity()));
+                : new 
QueueingRecyclerFactory(QueueFactories.MPMC.factory(DEFAULT_QUEUE_CAPACITY));
     }
 
     public static RecyclerFactory ofSpec(final String recyclerFactorySpec) {
@@ -60,11 +58,7 @@ public final class RecyclerFactories {
 
         // Is a queueing factory requested?
         else if (recyclerFactorySpec.startsWith("queue")) {
-
-            // Determine the default capacity.
-            final int defaultCapacity = getDefaultCapacity();
-
-            return readQueueingRecyclerFactory(recyclerFactorySpec, 
defaultCapacity);
+            return readQueueingRecyclerFactory(recyclerFactorySpec);
         }
 
         // Bogus input, bail out.
@@ -75,53 +69,41 @@ public final class RecyclerFactories {
 
     }
 
-    private static RecyclerFactory readQueueingRecyclerFactory(
-            final String recyclerFactorySpec,
-            final int defaultCapacity) {
+    private static RecyclerFactory readQueueingRecyclerFactory(final String 
recyclerFactorySpec) {
 
         // Parse the spec.
         final String queueFactorySpec = recyclerFactorySpec.substring(
-                "queue".length() +
-                        (recyclerFactorySpec.startsWith("queue:")
-                                ? 1
-                                : 0));
+                "queue".length() + (recyclerFactorySpec.startsWith("queue:") ? 
1 : 0));
         final Map<String, StringParameterParser.Value> parsedValues =
-                StringParameterParser.parse(
-                        queueFactorySpec, Set.of("supplier", "capacity"));
+                StringParameterParser.parse(queueFactorySpec, 
Set.of("supplier", "capacity"));
 
         // Read the capacity.
         final StringParameterParser.Value capacityValue = 
parsedValues.get("capacity");
         final int capacity;
         if (capacityValue == null || capacityValue instanceof 
StringParameterParser.NullValue) {
-            capacity = defaultCapacity;
+            capacity = DEFAULT_QUEUE_CAPACITY;
         } else {
             try {
                 capacity = Integer.parseInt(capacityValue.toString());
             } catch (final NumberFormatException error) {
                 throw new IllegalArgumentException(
-                        "failed reading capacity in queueing recycler " +
-                                "factory: " + queueFactorySpec, error);
+                        "failed reading capacity in queueing recycler factory: 
" + queueFactorySpec,
+                        error);
             }
         }
 
-        // Read the supplier path.
+        // Read the supplier path
         final StringParameterParser.Value supplierValue = 
parsedValues.get("supplier");
-        final String supplierPath;
-        if (supplierValue == null || supplierValue instanceof 
StringParameterParser.NullValue) {
-            supplierPath = null;
-        } else {
-            supplierPath = supplierValue.toString();
-        }
-
-        // Execute the read spec.
-        final QueueFactory queueFactory;
-        if (supplierPath != null) {
-            queueFactory = Queues.createQueueFactory(supplierPath, capacity);
-        } else {
-            queueFactory = Queues.MPMC.factory(capacity);
-        }
-
+        final String supplierPath = supplierValue == null || supplierValue 
instanceof StringParameterParser.NullValue
+                ? null
+                : supplierValue.toString();
+
+        // Execute the read spec
+        final QueueFactory queueFactory = supplierPath != null
+                ? QueueFactories.createQueueFactory(supplierPath, capacity)
+                : QueueFactories.MPMC.factory(capacity);
         return new QueueingRecyclerFactory(queueFactory);
+
     }
 
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactory.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactory.java
index 65a8d1915f..43144a5ae8 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactory.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadLocalRecyclerFactory.java
@@ -20,13 +20,14 @@ import java.util.Queue;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
-import org.apache.logging.log4j.util.Queues;
+import org.apache.logging.log4j.util.QueueFactories;
 
 /**
- * Recycling strategy that caches instances in a ThreadLocal value to allow 
threads to reuse objects. This strategy
- * may not be appropriate in workloads where units of work are independent of 
operating system threads such as
- * reactive streams, coroutines, or virtual threads; a {@linkplain 
QueueingRecyclerFactory queue-based approach}
- * is more flexible.
+ * A {@link RecyclerFactory} pooling objects in a queue stored in a {@link 
ThreadLocal}.
+ * <p>
+ * This strategy may not be appropriate in workloads where units of work are 
independent of operating system threads such as reactive streams, coroutines, 
or virtual threads.
+ * For such use cases, see {@link QueueingRecyclerFactory}.
+ * </p>
  *
  * @since 3.0.0
  */
@@ -39,8 +40,7 @@ public class ThreadLocalRecyclerFactory implements 
RecyclerFactory {
     // Visible for testing
     static final int MAX_QUEUE_SIZE = 8;
 
-    private static final ThreadLocalRecyclerFactory INSTANCE =
-            new ThreadLocalRecyclerFactory();
+    private static final ThreadLocalRecyclerFactory INSTANCE = new 
ThreadLocalRecyclerFactory();
 
     private ThreadLocalRecyclerFactory() {}
 
@@ -65,7 +65,7 @@ public class ThreadLocalRecyclerFactory implements 
RecyclerFactory {
         private ThreadLocalRecycler(final Supplier<V> supplier, final 
Consumer<V> cleaner) {
             this.supplier = supplier;
             this.cleaner = cleaner;
-            this.holder = ThreadLocal.withInitial(() -> 
Queues.SPSC.create(MAX_QUEUE_SIZE));
+            this.holder = ThreadLocal.withInitial(() -> 
QueueFactories.SPSC.create(MAX_QUEUE_SIZE));
         }
 
         @Override
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
index d25e3aedf6..6387829e2f 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
@@ -34,7 +34,7 @@ import org.apache.logging.log4j.simple.SimpleLoggerContext;
 import org.apache.logging.log4j.spi.AbstractLogger;
 import org.apache.logging.log4j.spi.LoggingSystemProperties;
 import org.apache.logging.log4j.util.LowLevelLogUtil;
-import org.apache.logging.log4j.util.Queues;
+import org.apache.logging.log4j.util.QueueFactories;
 
 /**
  * Records events that occur in the logging system. By default, only error 
messages are logged to {@link System#err}.
@@ -97,7 +97,7 @@ public final class StatusLogger extends AbstractLogger {
         this.logger = logger;
         this.configuration = configuration;
         this.listenersLevel = configuration.getDefaultLevel().intLevel();
-        messages = Queues.MPMC.create(configuration.getMaxEntries());
+        messages = QueueFactories.MPMC.create(configuration.getMaxEntries());
     }
 
     /**
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Queues.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactories.java
similarity index 66%
rename from log4j-api/src/main/java/org/apache/logging/log4j/util/Queues.java
rename to 
log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactories.java
index 2f0167f2ea..0d2f04216b 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Queues.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactories.java
@@ -27,38 +27,40 @@ import org.jctools.queues.SpmcArrayQueue;
 import org.jctools.queues.SpscArrayQueue;
 
 /**
- * Provides {@link QueueFactory} and {@link Queue} instances for different use 
cases. When the
- * <a href="https://jctools.github.io/JCTools/";>JCTools</a> library is 
included at runtime, then
- * the specialized lock free or wait free queues are used from there. 
Otherwise, {@link ArrayBlockingQueue}
- * is provided as a fallback for thread-safety. Custom implementations of 
{@link QueueFactory} may also be
- * created via {@link #createQueueFactory(String, int)}.
+ * Provides {@link QueueFactory} and {@link Queue} instances for different use 
cases.
+ * <p>
+ * Implementations provided by <a 
href="https://jctools.github.io/JCTools/";>JCTools</a> will be preferred, if 
available at runtime.
+ * Otherwise, {@link ArrayBlockingQueue} will be used.
+ * </p>
+ *
+ * @since 3.0.0
  */
 @InternalApi
-public enum Queues {
+public enum QueueFactories {
+
     /**
-     * Provides a bounded queue for single-producer/single-consumer usage. 
Only one thread may offer objects
-     * while only one thread may poll for them.
+     * Provides a bounded queue for single-producer/single-consumer usage.
      */
     SPSC(Lazy.lazy(JCToolsQueueFactory.SPSC::load)),
+
     /**
-     * Provides a bounded queue for multi-producer/single-consumer usage. Any 
thread may offer objects while only
-     * one thread may poll for them.
+     * Provides a bounded queue for multi-producer/single-consumer usage.
      */
     MPSC(Lazy.lazy(JCToolsQueueFactory.MPSC::load)),
+
     /**
-     * Provides a bounded queue for single-producer/multi-consumer usage. Only 
one thread may offer objects but
-     * any thread may poll for them.
+     * Provides a bounded queue for single-producer/multi-consumer usage.
      */
     SPMC(Lazy.lazy(JCToolsQueueFactory.SPMC::load)),
+
     /**
-     * Provides a bounded queue for multi-producer/multi-consumer usage. Any 
thread may offer objects and any thread
-     * may poll for them.
+     * Provides a bounded queue for multi-producer/multi-consumer usage.
      */
     MPMC(Lazy.lazy(JCToolsQueueFactory.MPMC::load));
 
     private final Lazy<BoundedQueueFactory> queueFactory;
 
-    Queues(final Lazy<BoundedQueueFactory> queueFactory) {
+    QueueFactories(final Lazy<BoundedQueueFactory> queueFactory) {
         this.queueFactory = queueFactory;
     }
 
@@ -70,10 +72,25 @@ public enum Queues {
         return queueFactory.get().create(capacity);
     }
 
+    /**
+     * Creates a {@link QueueFactory} producing queues of provided capacity 
from the provided supplier.
+     * <p>
+     * A supplier path must be formatted as follows:
+     * <ul>
+     * <li>{@code <fully-qualified-class-name>.new} – the class constructor 
accepting a single {@code int} argument (denoting the capacity) will be used 
(e.g., {@code org.jctools.queues.MpmcArrayQueue.new})</li>
+     * <li>{@code <fully-qualified-class-name>.<static-factory-method>} – the 
static factory method accepting a single {@code int} argument (denoting the 
capacity) will be used (e.g., {@code com.acme.Queues.createBoundedQueue})</li>
+     * </ul>
+     * </p>
+     *
+     * @param supplierPath a queue supplier path (e.g., {@code 
org.jctools.queues.MpmcArrayQueue.new}, {@code 
com.acme.Queues.createBoundedQueue})
+     * @param capacity the capacity that will be passed to the queue supplier
+     * @return a new {@link QueueFactory} instance
+     */
     public static QueueFactory createQueueFactory(final String supplierPath, 
final int capacity) {
         final int supplierPathSplitterIndex = supplierPath.lastIndexOf('.');
         if (supplierPathSplitterIndex < 0) {
-            throw new IllegalArgumentException("invalid supplier in queue 
factory: " + supplierPath);
+            final String message = String.format("invalid queue factory 
supplier path: `%s`", supplierPath);
+            throw new IllegalArgumentException(message);
         }
         final String supplierClassName = supplierPath.substring(0, 
supplierPathSplitterIndex);
         final String supplierMethodName = 
supplierPath.substring(supplierPathSplitterIndex + 1);
@@ -81,22 +98,24 @@ public enum Queues {
             final Class<?> supplierClass = 
LoaderUtil.loadClass(supplierClassName);
             final BoundedQueueFactory queueFactory;
             if ("new".equals(supplierMethodName)) {
-                final Constructor<?> supplierCtor =
-                        supplierClass.getDeclaredConstructor(int.class);
+                final Constructor<?> supplierCtor = 
supplierClass.getDeclaredConstructor(int.class);
                 queueFactory = new 
ConstructorProvidedQueueFactory(supplierCtor);
             } else {
-                final Method supplierMethod =
-                        supplierClass.getMethod(supplierMethodName, int.class);
+                final Method supplierMethod = 
supplierClass.getMethod(supplierMethodName, int.class);
                 queueFactory = new 
StaticMethodProvidedQueueFactory(supplierMethod);
             }
             return new ProxyQueueFactory(queueFactory, capacity);
         } catch (final ReflectiveOperationException | LinkageError | 
SecurityException error) {
-            throw new RuntimeException("failed executing queue factory", 
error);
+            final String message = String.format(
+                    "failed to create the queue factory using the supplier 
path `%s`", supplierPath);
+            throw new RuntimeException(message, error);
         }
     }
 
-    private static class ProxyQueueFactory implements QueueFactory {
+    private static final class ProxyQueueFactory implements QueueFactory {
+
         private final BoundedQueueFactory factory;
+
         private final int capacity;
 
         private ProxyQueueFactory(final BoundedQueueFactory factory, final int 
capacity) {
@@ -108,38 +127,52 @@ public enum Queues {
         public <E> Queue<E> create() {
             return factory.create(capacity);
         }
+
     }
 
+    @FunctionalInterface
     private interface BoundedQueueFactory {
+
         <E> Queue<E> create(final int capacity);
+
     }
 
-    private static class ArrayBlockingQueueFactory implements 
BoundedQueueFactory {
+    private static final class ArrayBlockingQueueFactory implements 
BoundedQueueFactory {
+
+        private static final ArrayBlockingQueueFactory INSTANCE = new 
ArrayBlockingQueueFactory();
+
+        private ArrayBlockingQueueFactory() {}
+
         @Override
         public <E> Queue<E> create(final int capacity) {
             return new ArrayBlockingQueue<>(capacity);
         }
+
     }
 
     private enum JCToolsQueueFactory implements BoundedQueueFactory {
+
         SPSC {
             @Override
             public <E> Queue<E> create(final int capacity) {
                 return new SpscArrayQueue<>(capacity);
             }
         },
+
         MPSC {
             @Override
             public <E> Queue<E> create(final int capacity) {
                 return new MpscArrayQueue<>(capacity);
             }
         },
+
         SPMC {
             @Override
             public <E> Queue<E> create(final int capacity) {
                 return new SpmcArrayQueue<>(capacity);
             }
         },
+
         MPMC {
             @Override
             public <E> Queue<E> create(final int capacity) {
@@ -147,21 +180,20 @@ public enum Queues {
             }
         };
 
-        BoundedQueueFactory load() {
+        private BoundedQueueFactory load() {
             try {
-                // if JCTools is unavailable at runtime, then we'll only find 
out once we attempt to invoke
-                // BoundedQueueFactory::create which is the first time the 
ClassLoader will try to link the
-                // referenced JCTools class causing a NoClassDefFoundError or 
some other LinkageError potentially.
-                // also, test with a large enough capacity to avoid any 
IllegalArgumentExceptions from trivial queues
+                // Test with a large enough capacity to avoid any 
`IllegalArgumentExceptions` from trivial queues
                 create(16);
                 return this;
             } catch (final LinkageError ignored) {
-                return new ArrayBlockingQueueFactory();
+                return ArrayBlockingQueueFactory.INSTANCE;
             }
         }
+
     }
 
-    private static class ConstructorProvidedQueueFactory implements 
BoundedQueueFactory {
+    private static final class ConstructorProvidedQueueFactory implements 
BoundedQueueFactory {
+
         private final Constructor<?> constructor;
 
         private ConstructorProvidedQueueFactory(final Constructor<?> 
constructor) {
@@ -173,13 +205,15 @@ public enum Queues {
             final Constructor<Queue<E>> typedConstructor = 
Cast.cast(constructor);
             try {
                 return typedConstructor.newInstance(capacity);
-            } catch (final ReflectiveOperationException e) {
-                throw new RuntimeException("queue construction failed for 
factory", e);
+            } catch (final ReflectiveOperationException error) {
+                throw new RuntimeException("queue construction failure", 
error);
             }
         }
+
     }
 
-    private static class StaticMethodProvidedQueueFactory implements 
BoundedQueueFactory {
+    private static final class StaticMethodProvidedQueueFactory implements 
BoundedQueueFactory {
+
         private final Method method;
 
         private StaticMethodProvidedQueueFactory(final Method method) {
@@ -190,9 +224,11 @@ public enum Queues {
         public <E> Queue<E> create(final int capacity) {
             try {
                 return Cast.cast(method.invoke(null, capacity));
-            } catch (final ReflectiveOperationException e) {
-                throw new RuntimeException("queue construction failed for 
factory", e);
+            } catch (final ReflectiveOperationException error) {
+                throw new RuntimeException("queue construction failure", 
error);
             }
         }
+
     }
+
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java
index 53a6d6db29..5fcd4240e4 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java
@@ -18,6 +18,15 @@ package org.apache.logging.log4j.util;
 
 import java.util.Queue;
 
+/**
+ * A {@link Queue} factory contract.
+ *
+ * @see QueueFactories
+ * @since 3.0.0
+ */
+@FunctionalInterface
 public interface QueueFactory {
+
     <E> Queue<E> create();
+
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
index 653877c1f4..2e5105b21c 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
@@ -16,15 +16,16 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.Callable;
 
-import org.apache.logging.log4j.util.Strings;
-
+/**
+ * Utility class for parsing string-formatted parameters, e.g., {@code 
queue:supplier=com.acme.FastestQueue.new,capacity=42}.
+ * <p>
+ * See the associated test class for possible combinations and double-, 
single-quote handling.
+ * </p>
+ */
+@InternalApi
 public final class StringParameterParser {
 
     private StringParameterParser() {}
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index a009dd201b..da403a010e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -35,6 +35,7 @@ import org.apache.logging.log4j.message.ParameterVisitable;
 import org.apache.logging.log4j.message.ReusableMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
 import org.apache.logging.log4j.message.TimestampMessage;
+import org.apache.logging.log4j.spi.Recycler;
 import org.apache.logging.log4j.util.StackLocatorUtil;
 import org.apache.logging.log4j.util.StringBuilders;
 import org.apache.logging.log4j.util.StringMap;
@@ -43,7 +44,7 @@ import org.apache.logging.log4j.util.Strings;
 /**
  * Mutable implementation of the {@code ReusableLogEvent} interface.
  * @since 2.6
- * @see org.apache.logging.log4j.spi.Recycler
+ * @see Recycler
  */
 public class MutableLogEvent implements ReusableLogEvent, ReusableMessage, 
ParameterVisitable {
     private static final Message EMPTY = new SimpleMessage(Strings.EMPTY);
diff --git 
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
 
b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
deleted file mode 100644
index 74771534aa..0000000000
--- 
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.logging.log4j.spi;
-
-import java.lang.reflect.Field;
-import java.util.ArrayDeque;
-import java.util.concurrent.ArrayBlockingQueue;
-
-import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
-import org.apache.logging.log4j.core.test.junit.Named;
-import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout;
-import org.apache.logging.log4j.plugins.convert.TypeConverter;
-import org.apache.logging.log4j.plugins.di.DI;
-import org.apache.logging.log4j.plugins.di.Injector;
-import org.assertj.core.api.Assertions;
-import org.jctools.queues.MpmcArrayQueue;
-import org.junit.jupiter.api.Test;
-
-class RecyclerFactoriesTest {
-
-    @Test
-    void test_RecyclerFactoryConverter() throws Exception {
-
-        final Injector injector = DI.createInjector();
-        injector.init();
-        // Check if the type converter is registered.
-        final TypeConverter<?> converter = 
injector.getTypeConverter(RecyclerFactory.class);
-        Assertions.assertThat(converter).isNotNull();
-
-        // Check dummy recycler factory.
-        {
-            final Object actualDummyRecyclerFactory = 
converter.convert("dummy");
-            Assertions
-                    .assertThat(actualDummyRecyclerFactory)
-                    .isSameAs(DummyRecyclerFactory.getInstance());
-        }
-
-        // Check thread-local recycler factory.
-        {
-            final Object actualThreadLocalRecyclerFactory = 
converter.convert("threadLocal");
-            Assertions
-                    .assertThat(actualThreadLocalRecyclerFactory)
-                    .isSameAs(ThreadLocalRecyclerFactory.getInstance());
-        }
-
-        // Check queueing recycler factory.
-        {
-            final Object actualQueueingRecyclerFactory = 
converter.convert("queue");
-            Assertions
-                    .assertThat(actualQueueingRecyclerFactory)
-                    .isInstanceOf(QueueingRecyclerFactory.class);
-        }
-
-        // Check queueing recycler factory with supplier.
-        {
-            final Object recyclerFactory = converter.convert(
-                    "queue:supplier=java.util.ArrayDeque.new");
-            Assertions
-                    .assertThat(recyclerFactory)
-                    .isInstanceOf(QueueingRecyclerFactory.class);
-            final QueueingRecyclerFactory queueingRecyclerFactory =
-                    (QueueingRecyclerFactory) recyclerFactory;
-            final Recycler<Object> recycler =
-                    queueingRecyclerFactory.create(Object::new);
-            Assertions
-                    .assertThat(recycler)
-                    
.isInstanceOf(QueueingRecyclerFactory.QueueingRecycler.class);
-            final QueueingRecyclerFactory.QueueingRecycler<Object> 
queueingRecycler =
-                    (QueueingRecyclerFactory.QueueingRecycler<Object>) 
recycler;
-            Assertions
-                    .assertThat(queueingRecycler.getQueue())
-                    .isInstanceOf(ArrayDeque.class);
-        }
-
-        // Check queueing recycler factory with capacity.
-        {
-            final Object actualQueueingRecyclerFactory = converter.convert(
-                    "queue:capacity=100");
-            Assertions
-                    .assertThat(actualQueueingRecyclerFactory)
-                    .isInstanceOf(QueueingRecyclerFactory.class);
-        }
-
-        // Check queueing recycler factory with supplier and capacity.
-        {
-            final Object recyclerFactory = converter.convert(
-                    "queue:" +
-                            
"supplier=java.util.concurrent.ArrayBlockingQueue.new," +
-                            "capacity=100");
-            Assertions
-                    .assertThat(recyclerFactory)
-                    .isInstanceOf(QueueingRecyclerFactory.class);
-            final QueueingRecyclerFactory queueingRecyclerFactory =
-                    (QueueingRecyclerFactory) recyclerFactory;
-            final Recycler<Object> recycler =
-                    queueingRecyclerFactory.create(Object::new);
-            Assertions
-                    .assertThat(recycler)
-                    
.isInstanceOf(QueueingRecyclerFactory.QueueingRecycler.class);
-            final QueueingRecyclerFactory.QueueingRecycler<Object> 
queueingRecycler =
-                    (QueueingRecyclerFactory.QueueingRecycler<Object>) 
recycler;
-            Assertions
-                    .assertThat(queueingRecycler.getQueue())
-                    .isInstanceOf(ArrayBlockingQueue.class);
-            final ArrayBlockingQueue<Object> queue =
-                    (ArrayBlockingQueue<Object>) queueingRecycler.getQueue();
-            Assertions.assertThat(queue.remainingCapacity()).isEqualTo(100);
-        }
-
-    }
-
-    @Test
-    
@LoggerContextSource("recyclerFactoryCustomizedJsonTemplateLayoutLogging.xml")
-    void test_RecyclerFactoryConverter_using_XML_config(
-            final @Named(value = "List") ListAppender appender)
-            throws Exception {
-        final JsonTemplateLayout layout = (JsonTemplateLayout) 
appender.getLayout();
-        final Field field = 
JsonTemplateLayout.class.getDeclaredField("contextRecycler");
-        field.setAccessible(true);
-        final QueueingRecyclerFactory.QueueingRecycler<?> contextRecycler = 
(QueueingRecyclerFactory.QueueingRecycler<?>) field.get(layout);
-        final MpmcArrayQueue<?> queue = (MpmcArrayQueue<?>) 
contextRecycler.getQueue();
-        Assertions.assertThat(queue.capacity()).isEqualTo(512);
-    }
-
-}
diff --git 
a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java 
b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java
index 4034b1ba3f..edd8483fe9 100644
--- a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java
+++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/SLF4JLogger.java
@@ -40,10 +40,12 @@ public class SLF4JLogger extends AbstractLogger {
      */
     private static final boolean LAZY_LEVEL_CHECK = 
"ch.qos.logback.classic.LoggerContext"
             .equals(LoggerFactory.getILoggerFactory().getClass().getName());
-    private static final Recycler<SLF4JLogBuilder> logBuilderRecycler =
+
+    private static final Recycler<SLF4JLogBuilder> LOG_BUILDER_RECYCLER =
             LoggingSystem.getRecyclerFactory().create(SLF4JLogBuilder::new);
 
     private final org.slf4j.Logger logger;
+
     private final LocationAwareLogger locationAwareLogger;
 
     public SLF4JLogger(final String name, final MessageFactory messageFactory, 
final org.slf4j.Logger logger) {
@@ -271,6 +273,11 @@ public class SLF4JLogger extends AbstractLogger {
         }
     }
 
+    @Override
+    public LogBuilder always() {
+        return atLevel(Level.OFF);
+    }
+
     @Override
     public LogBuilder atTrace() {
         return atLevel(Level.TRACE);
@@ -303,7 +310,7 @@ public class SLF4JLogger extends AbstractLogger {
 
     @Override
     protected LogBuilder getLogBuilder(Level level) {
-        SLF4JLogBuilder builder = logBuilderRecycler.acquire();
+        SLF4JLogBuilder builder = LOG_BUILDER_RECYCLER.acquire();
         return builder.reset(this, level);
     }
 

Reply via email to