diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
index b16ea9dc2af..f212b4ae868 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/SyslogAppenderBuilder.java
@@ -142,6 +142,7 @@ private Appender createAppender(final String name, final Log4j1Configuration con
resolveSyslogHost(syslogHost, host, port);
final org.apache.logging.log4j.core.Layout messageLayout = LayoutAdapter.adapt(layout);
final Log4j1SyslogLayout appenderLayout = Log4j1SyslogLayout.newBuilder()
+ .setConfiguration(configuration)
.setHeader(header)
.setFacility(Facility.toFacility(facility))
.setFacilityPrinting(facilityPrinting)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
index 1bf7ac9c08f..91df856665d 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
@@ -25,6 +25,7 @@
import org.apache.log4j.builders.AbstractBuilder;
import org.apache.log4j.config.PropertiesConfiguration;
import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.HtmlLayout;
import org.apache.logging.log4j.plugins.Namespace;
import org.apache.logging.log4j.plugins.Plugin;
@@ -78,6 +79,7 @@ public Layout parse(final PropertiesConfiguration config) {
private Layout createLayout(final String title, final boolean locationInfo) {
return LayoutWrapper.adapt(HtmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setTitle(title)
.setLocationInfo(locationInfo)
.build());
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
index 82b6eb52b5f..01c0418dd56 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
@@ -25,6 +25,7 @@
import org.apache.log4j.config.PropertiesConfiguration;
import org.apache.log4j.layout.Log4j1XmlLayout;
import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.plugins.Namespace;
import org.apache.logging.log4j.plugins.Plugin;
import org.w3c.dom.Element;
@@ -73,6 +74,6 @@ public Layout parse(final PropertiesConfiguration config) {
}
private Layout createLayout(final boolean properties, final boolean locationInfo) {
- return LayoutWrapper.adapt(Log4j1XmlLayout.createLayout(locationInfo, properties));
+ return LayoutWrapper.adapt(Log4j1XmlLayout.createLayout(new DefaultConfiguration(), locationInfo, properties));
}
}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java
index c167442aee5..0cfb7aa3203 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1SyslogLayout.java
@@ -24,6 +24,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.StringLayout;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.net.Facility;
@@ -85,7 +86,7 @@ public Log4j1SyslogLayout build() {
LOGGER.error("Log4j1SyslogLayout: the message layout must be a StringLayout.");
return null;
}
- return new Log4j1SyslogLayout(facility, facilityPrinting, header, (StringLayout) messageLayout, getCharset());
+ return new Log4j1SyslogLayout(getConfiguration(), facility, facilityPrinting, header, (StringLayout) messageLayout, getCharset());
}
public Facility getFacility() {
@@ -147,9 +148,14 @@ public static > B newBuilder() {
private final LogEventPatternConverter dateConverter = DatePatternConverter.newInstance(dateFormatOptions);
- private Log4j1SyslogLayout(final Facility facility, final boolean facilityPrinting, final boolean header,
- final StringLayout messageLayout, final Charset charset) {
- super(charset);
+ private Log4j1SyslogLayout(
+ final Configuration config,
+ final Facility facility,
+ final boolean facilityPrinting,
+ final boolean header,
+ final StringLayout messageLayout,
+ final Charset charset) {
+ super(config, charset);
this.facility = facility;
this.facilityPrinting = facilityPrinting;
this.header = header;
@@ -168,32 +174,36 @@ public String toSerializable(final LogEvent event) {
// so we generate the message first
final String message = messageLayout != null ? messageLayout.toSerializable(event)
: event.getMessage().getFormattedMessage();
- final StringBuilder buf = getStringBuilder();
-
- buf.append('<');
- buf.append(Priority.getPriority(facility, event.getLevel()));
- buf.append('>');
-
- if (header) {
- final int index = buf.length() + 4;
- dateConverter.format(event, buf);
- // RFC 3164 says leading space, not leading zero on days 1-9
- if (buf.charAt(index) == '0') {
- buf.setCharAt(index, Chars.SPACE);
+ final StringBuilder buf = stringBuilderRecycler.acquire();
+
+ try {
+ buf.append('<');
+ buf.append(Priority.getPriority(facility, event.getLevel()));
+ buf.append('>');
+
+ if (header) {
+ final int index = buf.length() + 4;
+ dateConverter.format(event, buf);
+ // RFC 3164 says leading space, not leading zero on days 1-9
+ if (buf.charAt(index) == '0') {
+ buf.setCharAt(index, Chars.SPACE);
+ }
+
+ buf.append(Chars.SPACE);
+ buf.append(localHostname);
+ buf.append(Chars.SPACE);
}
- buf.append(Chars.SPACE);
- buf.append(localHostname);
- buf.append(Chars.SPACE);
- }
-
if (facilityPrinting) {
buf.append(facility != null ? toRootLowerCase(facility.name()) : "user").append(':');
}
- buf.append(message);
- // TODO: splitting message into 1024 byte chunks?
- return buf.toString();
+ buf.append(message);
+ // TODO: splitting message into 1024 byte chunks?
+ return buf.toString();
+ } finally {
+ stringBuilderRecycler.release(buf);
+ }
}
/**
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
index 66143715ae4..1ede6c4af5d 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/layout/Log4j1XmlLayout.java
@@ -25,8 +25,11 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.Encoder;
import org.apache.logging.log4j.core.util.Transform;
import org.apache.logging.log4j.plugins.Configurable;
import org.apache.logging.log4j.plugins.Plugin;
@@ -53,15 +56,16 @@ public final class Log4j1XmlLayout extends AbstractStringLayout {
@PluginFactory
public static Log4j1XmlLayout createLayout(
// @formatter:off
+ @PluginConfiguration Configuration configuration,
@PluginAttribute(value = "locationInfo") final boolean locationInfo,
@PluginAttribute(value = "properties") final boolean properties
// @formatter:on
) {
- return new Log4j1XmlLayout(locationInfo, properties);
+ return new Log4j1XmlLayout(configuration, locationInfo, properties);
}
- private Log4j1XmlLayout(final boolean locationInfo, final boolean properties) {
- super(StandardCharsets.UTF_8);
+ private Log4j1XmlLayout(final Configuration configuration, final boolean locationInfo, final boolean properties) {
+ super(configuration, StandardCharsets.UTF_8);
this.locationInfo = locationInfo;
this.properties = properties;
}
@@ -76,16 +80,29 @@ public boolean isProperties() {
@Override
public void encode(final LogEvent event, final ByteBufferDestination destination) {
- final StringBuilder text = getStringBuilder();
- formatTo(event, text);
- getStringBuilderEncoder().encode(text, destination);
+ final StringBuilder text = stringBuilderRecycler.acquire();
+ try {
+ formatTo(event, text);
+ final Encoder stringBuilderEncoder = stringBuilderEncoderRecycler.acquire();
+ try {
+ stringBuilderEncoder.encode(text, destination);
+ } finally {
+ stringBuilderEncoderRecycler.release(stringBuilderEncoder);
+ }
+ } finally {
+ stringBuilderRecycler.release(text);
+ }
}
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder text = getStringBuilder();
- formatTo(event, text);
- return text.toString();
+ final StringBuilder text = stringBuilderRecycler.acquire();
+ try {
+ formatTo(event, text);
+ return text.toString();
+ } finally {
+ stringBuilderRecycler.release(text);
+ }
}
@SuppressFBWarnings(
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1SyslogLayoutTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1SyslogLayoutTest.java
index 17f3953add2..1a05ea1ffed 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1SyslogLayoutTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1SyslogLayoutTest.java
@@ -23,6 +23,7 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.StringLayout;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.net.Facility;
import org.apache.logging.log4j.core.time.MutableInstant;
@@ -71,15 +72,18 @@ static Stream configurations() {
public void testSimpleLayout(final String expected, final Facility facility, final boolean header, final boolean facilityPrinting) {
final LogEvent logEvent = createLogEvent();
StringLayout appenderLayout = Log4j1SyslogLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setFacility(facility)
.setHeader(header)
.setFacilityPrinting(facilityPrinting)
.build();
assertEquals(expected, appenderLayout.toSerializable(logEvent));
final StringLayout messageLayout = PatternLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setPattern("%m")
.build();
appenderLayout = Log4j1SyslogLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setFacility(facility)
.setHeader(header)
.setFacilityPrinting(facilityPrinting)
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java
index 0ef2d37b4b2..630549771e4 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/layout/Log4j1XmlLayoutTest.java
@@ -17,6 +17,7 @@
package org.apache.log4j.layout;
import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.SimpleMessage;
@@ -34,7 +35,7 @@ public class Log4j1XmlLayoutTest {
@Test
public void testWithoutThrown() {
- final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(false, true);
+ final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(new DefaultConfiguration(), false, true);
final Log4jLogEvent event = Log4jLogEvent.newBuilder()
.setLoggerName("a.B")
@@ -55,7 +56,7 @@ public void testWithoutThrown() {
@Test
public void testWithPropertiesAndLocationInfo() {
- final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(true, true);
+ final Log4j1XmlLayout layout = Log4j1XmlLayout.createLayout(new DefaultConfiguration(), true, true);
final StringMap contextMap = ContextDataFactory.createContextData(2);
contextMap.putValue("key1", "value1");
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ReusableMessageFactoryTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ReusableMessageFactoryTest.java
index 2cf7ed48d94..ba7a5f758c1 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ReusableMessageFactoryTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/ReusableMessageFactoryTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.logging.log4j.message;
+import org.apache.logging.log4j.spi.ThreadLocalRecyclerFactory;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@@ -25,35 +27,39 @@
*/
public class ReusableMessageFactoryTest {
+ private ReusableMessageFactory factory;
+
+ @BeforeEach
+ void setUp() {
+ factory = new ReusableMessageFactory(new ThreadLocalRecyclerFactory(8));
+ }
+
@Test
public void testCreateEventReturnsDifferentInstanceIfNotReleased() throws Exception {
- final ReusableMessageFactory factory = new ReusableMessageFactory();
final Message message1 = factory.newMessage("text, p0={} p1={} p2={} p3={}", 1, 2, 3, 4);
final Message message2 = factory.newMessage("text, p0={} p1={} p2={} p3={}", 9, 8, 7, 6);
assertNotSame(message1, message2);
- ReusableMessageFactory.release(message1);
- ReusableMessageFactory.release(message2);
+ factory.recycle(message1);
+ factory.recycle(message2);
}
@Test
public void testCreateEventReturnsSameInstance() throws Exception {
- final ReusableMessageFactory factory = new ReusableMessageFactory();
final Message message1 = factory.newMessage("text, p0={} p1={} p2={} p3={}", 1, 2, 3, 4);
- ReusableMessageFactory.release(message1);
+ factory.recycle(message1);
final Message message2 = factory.newMessage("text, p0={} p1={} p2={} p3={}", 9, 8, 7, 6);
assertSame(message1, message2);
- ReusableMessageFactory.release(message2);
+ factory.recycle(message2);
final Message message3 = factory.newMessage("text, AAA={} BBB={} p2={} p3={}", 9, 8, 7, 6);
assertSame(message2, message3);
- ReusableMessageFactory.release(message3);
+ factory.recycle(message3);
}
private void assertReusableParameterizeMessage(final Message message, final String txt, final Object[] params) {
assertTrue(message instanceof ReusableParameterizedMessage);
final ReusableParameterizedMessage msg = (ReusableParameterizedMessage) message;
- assertTrue(msg.reserved, "reserved");
assertEquals(txt, msg.getFormat());
assertEquals(msg.getParameterCount(), params.length, "count");
@@ -65,7 +71,6 @@ private void assertReusableParameterizeMessage(final Message message, final Stri
@Test
public void testCreateEventOverwritesFields() throws Exception {
- final ReusableMessageFactory factory = new ReusableMessageFactory();
final Message message1 = factory.newMessage("text, p0={} p1={} p2={} p3={}", 1, 2, 3, 4);
assertReusableParameterizeMessage(message1, "text, p0={} p1={} p2={} p3={}", new Object[]{
new Integer(1), //
@@ -74,7 +79,7 @@ public void testCreateEventOverwritesFields() throws Exception {
new Integer(4), //
});
- ReusableMessageFactory.release(message1);
+ factory.recycle(message1);
final Message message2 = factory.newMessage("other, A={} B={} C={} D={}", 1, 2, 3, 4);
assertReusableParameterizeMessage(message1, "other, A={} B={} C={} D={}", new Object[]{
new Integer(1), //
@@ -83,12 +88,11 @@ public void testCreateEventOverwritesFields() throws Exception {
new Integer(4), //
});
assertSame(message1, message2);
- ReusableMessageFactory.release(message2);
+ factory.recycle(message2);
}
@Test
public void testCreateEventReturnsThreadLocalInstance() throws Exception {
- final ReusableMessageFactory factory = new ReusableMessageFactory();
final Message[] message1 = new Message[1];
final Message[] message2 = new Message[1];
final Thread t1 = new Thread("THREAD 1") {
@@ -123,8 +127,8 @@ public void run() {
new Integer(3), //
new Integer(4), //
});
- ReusableMessageFactory.release(message1[0]);
- ReusableMessageFactory.release(message2[0]);
+ factory.recycle(message1[0]);
+ factory.recycle(message2[0]);
}
}
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 00000000000..6a38541003f
--- /dev/null
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/RecyclerFactoriesTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.assertj.core.api.InstanceOfAssertFactories;
+import org.junit.jupiter.api.Test;
+
+public class RecyclerFactoriesTest {
+
+ @Test
+ void DummyRecyclerFactory_should_work() {
+ final RecyclerFactory actualDummyRecyclerFactory = RecyclerFactories.ofSpec("dummy");
+ Assertions
+ .assertThat(actualDummyRecyclerFactory)
+ .isSameAs(DummyRecyclerFactory.getInstance());
+ }
+
+ @Test
+ void ThreadLocalRecyclerFactory_should_work() {
+ final RecyclerFactory actualThreadLocalRecyclerFactory = RecyclerFactories.ofSpec("threadLocal");
+ Assertions
+ .assertThat(actualThreadLocalRecyclerFactory)
+ .asInstanceOf(InstanceOfAssertFactories.type(ThreadLocalRecyclerFactory.class))
+ .extracting(ThreadLocalRecyclerFactory::getCapacity)
+ .isEqualTo(RecyclerFactories.DEFAULT_QUEUE_CAPACITY);
+ }
+
+ @Test
+ void ThreadLocalRecyclerFactory_should_work_with_capacity() {
+ final RecyclerFactory actualThreadLocalRecyclerFactory = RecyclerFactories.ofSpec("threadLocal:capacity=13");
+ Assertions
+ .assertThat(actualThreadLocalRecyclerFactory)
+ .asInstanceOf(InstanceOfAssertFactories.type(ThreadLocalRecyclerFactory.class))
+ .extracting(ThreadLocalRecyclerFactory::getCapacity)
+ .isEqualTo(13);
+ }
+
+ @Test
+ void QueueingRecyclerFactory_should_work() {
+ final RecyclerFactory actualQueueingRecyclerFactory = RecyclerFactories.ofSpec("queue");
+ Assertions
+ .assertThat(actualQueueingRecyclerFactory)
+ .isInstanceOf(QueueingRecyclerFactory.class);
+ }
+
+ @Test
+ void QueueingRecyclerFactory_should_work_with_supplier() {
+ final RecyclerFactory recyclerFactory = RecyclerFactories.ofSpec("queue:supplier=java.util.ArrayDeque.new");
+ Assertions
+ .assertThat(recyclerFactory)
+ .isInstanceOf(QueueingRecyclerFactory.class);
+ final QueueingRecyclerFactory queueingRecyclerFactory = (QueueingRecyclerFactory) recyclerFactory;
+ final Recycler
+ *
+ * @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) {
+ 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);
+ try {
+ final Class> supplierClass = LoaderUtil.loadClass(supplierClassName);
+ final BoundedQueueFactory queueFactory;
+ if ("new".equals(supplierMethodName)) {
+ final Constructor> supplierCtor = supplierClass.getDeclaredConstructor(int.class);
+ queueFactory = new ConstructorProvidedQueueFactory(supplierCtor);
+ } else {
+ final Method supplierMethod = supplierClass.getMethod(supplierMethodName, int.class);
+ queueFactory = new StaticMethodProvidedQueueFactory(supplierMethod);
+ }
+ return new ProxyQueueFactory(queueFactory, capacity);
+ } catch (final ReflectiveOperationException | LinkageError | SecurityException 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 final class ProxyQueueFactory implements QueueFactory {
+
+ private final BoundedQueueFactory factory;
+
+ private final int capacity;
+
+ private ProxyQueueFactory(final BoundedQueueFactory factory, final int capacity) {
+ this.factory = factory;
+ this.capacity = capacity;
+ }
+
+ @Override
+ public Queue create() {
+ return factory.create(capacity);
+ }
+
+ }
+
+ @FunctionalInterface
+ private interface BoundedQueueFactory {
+
+ Queue create(final int capacity);
+
+ }
+
+ private static final class ArrayBlockingQueueFactory implements BoundedQueueFactory {
+
+ private static final ArrayBlockingQueueFactory INSTANCE = new ArrayBlockingQueueFactory();
+
+ private ArrayBlockingQueueFactory() {}
+
+ @Override
+ public Queue create(final int capacity) {
+ return new ArrayBlockingQueue<>(capacity);
+ }
+
+ }
+
+ private enum JCToolsQueueFactory implements BoundedQueueFactory {
+
+ SPSC {
+ @Override
+ public Queue create(final int capacity) {
+ return new SpscArrayQueue<>(capacity);
+ }
+ },
+
+ MPSC {
+ @Override
+ public Queue create(final int capacity) {
+ return new MpscArrayQueue<>(capacity);
+ }
+ },
+
+ SPMC {
+ @Override
+ public Queue create(final int capacity) {
+ return new SpmcArrayQueue<>(capacity);
+ }
+ },
+
+ MPMC {
+ @Override
+ public Queue create(final int capacity) {
+ return new MpmcArrayQueue<>(capacity);
+ }
+ };
+
+ private BoundedQueueFactory load() {
+ try {
+ // Test with a large enough capacity to avoid any `IllegalArgumentExceptions` from trivial queues
+ create(16);
+ return this;
+ } catch (final LinkageError ignored) {
+ return ArrayBlockingQueueFactory.INSTANCE;
+ }
+ }
+
+ }
+
+ private static final class ConstructorProvidedQueueFactory implements BoundedQueueFactory {
+
+ private final Constructor> constructor;
+
+ private ConstructorProvidedQueueFactory(final Constructor> constructor) {
+ this.constructor = constructor;
+ }
+
+ @Override
+ public Queue create(final int capacity) {
+ final Constructor> typedConstructor = Cast.cast(constructor);
+ try {
+ return typedConstructor.newInstance(capacity);
+ } catch (final ReflectiveOperationException error) {
+ throw new RuntimeException("queue construction failure", error);
+ }
+ }
+
+ }
+
+ private static final class StaticMethodProvidedQueueFactory implements BoundedQueueFactory {
+
+ private final Method method;
+
+ private StaticMethodProvidedQueueFactory(final Method method) {
+ this.method = method;
+ }
+
+ @Override
+ public Queue create(final int capacity) {
+ try {
+ return Cast.cast(method.invoke(null, capacity));
+ } catch (final ReflectiveOperationException error) {
+ throw new RuntimeException("queue construction failure", error);
+ }
+ }
+
+ }
+
+}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java
similarity index 69%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactory.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java
index 74a6f83239f..f4b54f0f74f 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueFactory.java
@@ -14,18 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.layout.template.json.util;
+package org.apache.logging.log4j.util;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
+import java.util.Queue;
+/**
+ * A {@link Queue} factory contract.
+ *
+ * @see QueueFactories
+ * @since 3.0.0
+ */
@FunctionalInterface
-public interface RecyclerFactory {
-
- default Recycler create(final Supplier supplier) {
- return create(supplier, ignored -> {});
- }
+public interface QueueFactory {
- Recycler create(Supplier supplier, Consumer cleaner);
+ Queue create();
}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
similarity index 96%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
index 37f69f1c8b2..23d87c765ad 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
@@ -14,17 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.layout.template.json.util;
+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}.
+ *
+ * See the associated test class for possible combinations and double-, single-quote handling.
+ *
+ */
+@InternalApi
public final class StringParameterParser {
private StringParameterParser() {}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
index 6c02b6ba06c..cb630d4d8f3 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
@@ -29,8 +29,6 @@
@InternalApi
public final class Strings {
- private static final ThreadLocal tempStr = ThreadLocal.withInitial(StringBuilder::new);
-
/**
* The empty string.
*/
@@ -193,6 +191,26 @@ public static String quote(final String str) {
return Chars.QUOTE + str + Chars.QUOTE;
}
+ /**
+ * Shorthand for {@code str.toLowerCase(Locale.ROOT);}
+ * @param str The string to lower case.
+ * @return a new string
+ * @see String#toLowerCase(Locale)
+ */
+ public static String toRootLowerCase(final String str) {
+ return str.toLowerCase(Locale.ROOT);
+ }
+
+ /**
+ * Shorthand for {@code str.toUpperCase(Locale.ROOT);}
+ * @param str The string to upper case.
+ * @return a new string
+ * @see String#toUpperCase(Locale)
+ */
+ public static String toRootUpperCase(final String str) {
+ return str.toUpperCase(Locale.ROOT);
+ }
+
/**
*
* Removes control characters (char <= 32) from both ends of this String returning {@code null} if the String is
@@ -303,67 +321,4 @@ public static String[] splitList(final String string) {
return string != null ? string.split(COMMA_DELIMITED_RE) : new String[0];
}
- /**
- * Shorthand for {@code str.toLowerCase(Locale.ROOT);}
- * @param str The string to upper case.
- * @return a new string
- * @see String#toLowerCase(Locale)
- */
- public static String toRootLowerCase(final String str) {
- return str.toLowerCase(Locale.ROOT);
- }
-
- /**
- * Shorthand for {@code str.toUpperCase(Locale.ROOT);}
- * @param str The string to lower case.
- * @return a new string
- * @see String#toLowerCase(Locale)
- */
- public static String toRootUpperCase(final String str) {
- return str.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Concatenates 2 Strings without allocation.
- * @param str1 the first string.
- * @param str2 the second string.
- * @return the concatenated String.
- */
- public static String concat(final String str1, final String str2) {
- if (isEmpty(str1)) {
- return str2;
- } else if (isEmpty(str2)) {
- return str1;
- }
- final StringBuilder sb = tempStr.get();
- try {
- return sb.append(str1).append(str2).toString();
- } finally {
- sb.setLength(0);
- }
- }
-
- /**
- * Creates a new string repeating given {@code str} {@code count} times.
- * @param str input string
- * @param count the repetition count
- * @return the new string
- * @throws IllegalArgumentException if either {@code str} is null or {@code count} is negative
- */
- public static String repeat(final String str, final int count) {
- Objects.requireNonNull(str, "str");
- if (count < 0) {
- throw new IllegalArgumentException("count");
- }
- final StringBuilder sb = tempStr.get();
- try {
- for (int index = 0; index < count; index++) {
- sb.append(str);
- }
- return sb.toString();
- } finally {
- sb.setLength(0);
- }
- }
-
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderCustomLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderCustomLayoutTest.java
index 8adfe31d5dc..7b2c8234447 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderCustomLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderCustomLayoutTest.java
@@ -18,6 +18,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.appender.SyslogAppender.Builder;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.SyslogLayout;
import org.apache.logging.log4j.core.net.Facility;
import org.apache.logging.log4j.core.net.Protocol;
@@ -34,6 +35,7 @@ protected Facility getExpectedFacility() {
protected Builder> newSyslogAppenderBuilder(final Protocol protocol, final TlsSyslogMessageFormat format,
final boolean newLine, final int port) {
final Layout layout = SyslogLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setFacility(Facility.LOCAL3)
.setIncludeNewLine(true)
.build();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java
index ba51d5cc671..117f79dd9fc 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java
@@ -20,6 +20,7 @@
import java.net.SocketException;
import org.apache.logging.log4j.core.appender.SyslogAppender.Builder;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.net.Facility;
import org.apache.logging.log4j.core.net.Protocol;
import org.apache.logging.log4j.core.test.net.mock.MockSyslogServerFactory;
@@ -119,6 +120,7 @@ protected Builder> newSyslogAppenderBuilder(final Protocol protocol, final Tls
final boolean newLine, final int port) {
// @formatter:off
return SyslogAppender.newSyslogAppenderBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setHost("localhost")
.setPort(port)
.setProtocol(protocol)
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
index 3843ef6fc0f..4c276a663fb 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
@@ -192,7 +192,7 @@ public void testCreateMementoRetainsParametersAndFormat() {
assertArrayEquals(new String[]{"World"}, actual.getParameters());
assertEquals("Hello World!", actual.getFormattedMessage());
} finally {
- ReusableMessageFactory.release(message);
+ factory.recycle(message);
}
}
@@ -220,7 +220,7 @@ public void testMementoReuse() {
final Message memento2 = evt.memento();
assertThat(memento1, sameInstance(memento2));
} finally {
- ReusableMessageFactory.release(message);
+ factory.recycle(message);
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunConversant.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunConversant.java
index ae683776941..d724aad34ef 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunConversant.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunConversant.java
@@ -25,6 +25,6 @@ public class RunConversant extends AbstractRunQueue {
@Override
BlockingQueue createQueue(final int capacity) {
- return DisruptorBlockingQueueFactory.createFactory(SpinPolicy.SPINNING).create(capacity);
+ return DisruptorBlockingQueueFactory.createFactory(SpinPolicy.SPINNING).create(capacity);
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunJCTools.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunJCTools.java
index c329a4ef43f..0796418eb05 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunJCTools.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/perftest/RunJCTools.java
@@ -25,7 +25,7 @@ public class RunJCTools extends AbstractRunQueue {
@Override
BlockingQueue createQueue(final int capacity) {
- return JCToolsBlockingQueueFactory.createFactory(WaitStrategy.SPIN).create(capacity);
+ return JCToolsBlockingQueueFactory.createFactory(WaitStrategy.SPIN).create(capacity);
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactoryTest.java
index 29bb7cb67b6..34aaa095622 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactoryTest.java
@@ -33,40 +33,39 @@ public class ReusableLogEventFactoryTest {
private final ConfigurableInstanceFactory instanceFactory = DI.createInitializedFactory();
+ private final ReusableLogEventFactory factory = instanceFactory.getInstance(ReusableLogEventFactory.class);
+
@Test
- public void testCreateEventReturnsDifferentInstanceIfNotReleased() throws Exception {
- final ReusableLogEventFactory factory = instanceFactory.getInstance(ReusableLogEventFactory.class);
- final LogEvent event1 = callCreateEvent(factory, "a", Level.DEBUG, new SimpleMessage("abc"), null);
- final LogEvent event2 = callCreateEvent(factory, "b", Level.INFO, new SimpleMessage("xyz"), null);
+ public void testCreateEventReturnsDifferentInstanceIfNotReleased() {
+ final LogEvent event1 = callCreateEvent("a", Level.DEBUG, new SimpleMessage("abc"), null);
+ final LogEvent event2 = callCreateEvent("b", Level.INFO, new SimpleMessage("xyz"), null);
assertNotSame(event1, event2);
- ReusableLogEventFactory.release(event1);
- ReusableLogEventFactory.release(event2);
+ factory.recycle(event1);
+ factory.recycle(event2);
}
@Test
- public void testCreateEventReturnsSameInstance() throws Exception {
- final ReusableLogEventFactory factory = instanceFactory.getInstance(ReusableLogEventFactory.class);
- final LogEvent event1 = callCreateEvent(factory, "a", Level.DEBUG, new SimpleMessage("abc"), null);
- ReusableLogEventFactory.release(event1);
- final LogEvent event2 = callCreateEvent(factory, "b", Level.INFO, new SimpleMessage("xyz"), null);
+ public void testCreateEventReturnsSameInstance() {
+ final LogEvent event1 = callCreateEvent("a", Level.DEBUG, new SimpleMessage("abc"), null);
+ factory.recycle(event1);
+ final LogEvent event2 = callCreateEvent("b", Level.INFO, new SimpleMessage("xyz"), null);
assertSame(event1, event2);
- ReusableLogEventFactory.release(event2);
- final LogEvent event3 = callCreateEvent(factory, "c", Level.INFO, new SimpleMessage("123"), null);
+ factory.recycle(event2);
+ final LogEvent event3 = callCreateEvent("c", Level.INFO, new SimpleMessage("123"), null);
assertSame(event2, event3);
- ReusableLogEventFactory.release(event3);
+ factory.recycle(event3);
}
@Test
- public void testCreateEventOverwritesFields() throws Exception {
- final ReusableLogEventFactory factory = instanceFactory.getInstance(ReusableLogEventFactory.class);
- final LogEvent event1 = callCreateEvent(factory, "a", Level.DEBUG, new SimpleMessage("abc"), null);
+ public void testCreateEventOverwritesFields() {
+ final LogEvent event1 = callCreateEvent("a", Level.DEBUG, new SimpleMessage("abc"), null);
assertEquals("a", event1.getLoggerName(), "logger");
assertEquals(Level.DEBUG, event1.getLevel(), "level");
assertEquals(new SimpleMessage("abc"), event1.getMessage(), "msg");
- ReusableLogEventFactory.release(event1);
- final LogEvent event2 = callCreateEvent(factory, "b", Level.INFO, new SimpleMessage("xyz"), null);
+ factory.recycle(event1);
+ final LogEvent event2 = callCreateEvent("b", Level.INFO, new SimpleMessage("xyz"), null);
assertSame(event1, event2);
assertEquals("b", event1.getLoggerName(), "logger");
@@ -77,26 +76,24 @@ public void testCreateEventOverwritesFields() throws Exception {
assertEquals(new SimpleMessage("xyz"), event2.getMessage(), "msg");
}
- private LogEvent callCreateEvent(final ReusableLogEventFactory factory, final String logger, final Level level,
- final Message message, final Throwable thrown) {
+ private LogEvent callCreateEvent(final String logger, final Level level, final Message message, final Throwable thrown) {
return factory.createEvent(logger, null, getClass().getName(), level, message, null, thrown);
}
@Test
public void testCreateEventReturnsThreadLocalInstance() throws Exception {
- final ReusableLogEventFactory factory = instanceFactory.getInstance(ReusableLogEventFactory.class);
final LogEvent[] event1 = new LogEvent[1];
final LogEvent[] event2 = new LogEvent[1];
final Thread t1 = new Thread("THREAD 1") {
@Override
public void run() {
- event1[0] = callCreateEvent(factory, "a", Level.DEBUG, new SimpleMessage("abc"), null);
+ event1[0] = callCreateEvent("a", Level.DEBUG, new SimpleMessage("abc"), null);
}
};
final Thread t2 = new Thread("Thread 2") {
@Override
public void run() {
- event2[0] = callCreateEvent(factory, "b", Level.INFO, new SimpleMessage("xyz"), null);
+ event2[0] = callCreateEvent("b", Level.INFO, new SimpleMessage("xyz"), null);
}
};
t1.start();
@@ -117,19 +114,18 @@ public void run() {
assertEquals(new SimpleMessage("xyz"), event2[0].getMessage(), "msg");
assertEquals("Thread 2", event2[0].getThreadName(), "thread name");
assertEquals(t2.getId(), event2[0].getThreadId(), "tid");
- ReusableLogEventFactory.release(event1[0]);
- ReusableLogEventFactory.release(event2[0]);
+ factory.recycle(event1[0]);
+ factory.recycle(event2[0]);
}
@Test
- public void testCreateEventInitFieldsProperly() throws Exception {
- final ReusableLogEventFactory factory = instanceFactory.getInstance(ReusableLogEventFactory.class);
- final LogEvent event = callCreateEvent(factory, "logger", Level.INFO, new SimpleMessage("xyz"), null);
+ public void testCreateEventInitFieldsProperly() {
+ final LogEvent event = callCreateEvent("logger", Level.INFO, new SimpleMessage("xyz"), null);
try {
assertNotNull(event.getContextData());
assertNotNull(event.getContextStack());
} finally {
- ReusableLogEventFactory.release(event);
+ factory.recycle(event);
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java
index 875aa0b280a..d34a67b056e 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/AbstractStringLayoutTest.java
@@ -19,9 +19,11 @@
import java.nio.charset.Charset;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests AbstractStringLayout.
@@ -32,11 +34,7 @@ static class ConcreteStringLayout extends AbstractStringLayout {
public static int MAX_STRING_BUILDER_SIZE = AbstractStringLayout.MAX_STRING_BUILDER_SIZE;
public ConcreteStringLayout() {
- super(Charset.defaultCharset());
- }
-
- public static StringBuilder getStringBuilder() {
- return AbstractStringLayout.getStringBuilder();
+ super(new DefaultConfiguration(), Charset.defaultCharset());
}
@Override
@@ -46,36 +44,51 @@ public String toSerializable(final LogEvent event) {
}
@Test
- public void testGetStringBuilderCapacityRestrictedToMax() throws Exception {
- final StringBuilder sb = ConcreteStringLayout.getStringBuilder();
+ public void testGetStringBuilderCapacityRestrictedToMax() {
+
+ final ConcreteStringLayout layout = new ConcreteStringLayout();
+ final StringBuilder sb = layout.stringBuilderRecycler.acquire();
final int initialCapacity = sb.capacity();
- assertEquals(ConcreteStringLayout.DEFAULT_STRING_BUILDER_SIZE, sb.capacity(), "initial capacity");
+ try {
+ assertEquals(ConcreteStringLayout.DEFAULT_STRING_BUILDER_SIZE, sb.capacity(), "initial capacity");
- final int SMALL = 100;
- final String smallMessage = new String(new char[SMALL]);
- sb.append(smallMessage);
- assertEquals(initialCapacity, sb.capacity(), "capacity not grown");
- assertEquals(SMALL, sb.length(), "length=msg length");
+ final int SMALL = 100;
+ final String smallMessage = new String(new char[SMALL]);
+ sb.append(smallMessage);
+ assertEquals(initialCapacity, sb.capacity(), "capacity not grown");
+ assertEquals(SMALL, sb.length(), "length=msg length");
+ } finally {
+ layout.stringBuilderRecycler.release(sb);
+ }
- final StringBuilder sb2 = ConcreteStringLayout.getStringBuilder();
- assertEquals(sb2.capacity(), initialCapacity, "capacity unchanged");
- assertEquals(0, sb2.length(), "empty, ready for use");
+ final StringBuilder sb2 = layout.stringBuilderRecycler.acquire();
+ try {
+ assertEquals(sb2.capacity(), initialCapacity, "capacity unchanged");
+ assertEquals(0, sb2.length(), "empty, ready for use");
- final int LARGE = ConcreteStringLayout.MAX_STRING_BUILDER_SIZE * 2;
- final String largeMessage = new String(new char[LARGE]);
- sb2.append(largeMessage);
- assertTrue(sb2.capacity() >= LARGE, "capacity grown to fit msg length");
- assertTrue(sb2.capacity() >= ConcreteStringLayout.MAX_STRING_BUILDER_SIZE,
- "capacity is now greater than max length");
- assertEquals(LARGE, sb2.length(), "length=msg length");
- sb2.setLength(0); // set 0 before next getStringBuilder() call
- assertEquals(0, sb2.length(), "empty, cleared");
- assertTrue(sb2.capacity() >= ConcreteStringLayout.MAX_STRING_BUILDER_SIZE, "capacity remains very large");
+ final int LARGE = ConcreteStringLayout.MAX_STRING_BUILDER_SIZE * 2;
+ final String largeMessage = new String(new char[LARGE]);
+ sb2.append(largeMessage);
+ assertTrue(sb2.capacity() >= LARGE, "capacity grown to fit msg length");
+ assertTrue(sb2.capacity() >= ConcreteStringLayout.MAX_STRING_BUILDER_SIZE,
+ "capacity is now greater than max length");
+ assertEquals(LARGE, sb2.length(), "length=msg length");
+ sb2.setLength(0); // set 0 before next getStringBuilder() call
+ assertEquals(0, sb2.length(), "empty, cleared");
+ assertTrue(sb2.capacity() >= ConcreteStringLayout.MAX_STRING_BUILDER_SIZE, "capacity remains very large");
+ } finally {
+ layout.stringBuilderRecycler.release(sb2);
+ }
+
+ final StringBuilder sb3 = layout.stringBuilderRecycler.acquire();
+ try {
+ assertEquals(ConcreteStringLayout.MAX_STRING_BUILDER_SIZE, sb3.capacity(),
+ "capacity, trimmed to MAX_STRING_BUILDER_SIZE");
+ assertEquals(0, sb3.length(), "empty, ready for use");
+ } finally {
+ layout.stringBuilderRecycler.release(sb3);
+ }
- final StringBuilder sb3 = ConcreteStringLayout.getStringBuilder();
- assertEquals(ConcreteStringLayout.MAX_STRING_BUILDER_SIZE, sb3.capacity(),
- "capacity, trimmed to MAX_STRING_BUILDER_SIZE");
- assertEquals(0, sb3.length(), "empty, ready for use");
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java
index b02bfa7ac8b..87cf3430fb8 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/GelfLayoutTest.java
@@ -31,6 +31,7 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.GelfLayout.CompressionType;
import org.apache.logging.log4j.core.lookup.JavaLookup;
import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
@@ -284,8 +285,9 @@ public void testFormatTimestamp() {
private void testRequiresLocation(final String messagePattern, final Boolean requiresLocation) {
final GelfLayout layout = GelfLayout.newBuilder()
- .setMessagePattern(messagePattern)
- .build();
+ .setConfiguration(new DefaultConfiguration())
+ .setMessagePattern(messagePattern)
+ .build();
assertEquals(layout.requiresLocation(), requiresLocation);
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java
index 961fff12938..2084e18f274 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/HtmlLayoutTest.java
@@ -29,11 +29,8 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.AbstractLogEvent;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.*;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.junit.ConfigurationFactoryType;
@@ -95,6 +92,7 @@ public void testDefaultContentType() {
@Test
public void testContentType() {
final HtmlLayout layout = HtmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setContentType("text/html; charset=UTF-16")
.build();
assertEquals("text/html; charset=UTF-16", layout.getContentType());
@@ -128,6 +126,7 @@ private void testLayout(final boolean includeLocation) throws Exception {
}
// set up appender
final HtmlLayout layout = HtmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(includeLocation)
.build();
final ListAppender appender = new ListAppender("List", null, layout, true, false);
@@ -181,7 +180,7 @@ private void testLayout(final boolean includeLocation) throws Exception {
@Test
public void testLayoutWithoutDataPattern() {
- final HtmlLayout layout = HtmlLayout.newBuilder().build();
+ final HtmlLayout layout = HtmlLayout.newBuilder().setConfiguration(new DefaultConfiguration()).build();
final MyLogEvent event = new MyLogEvent();
final String actual = getDateLine(layout.toSerializable(event));
@@ -192,7 +191,7 @@ public void testLayoutWithoutDataPattern() {
@Test
public void testLayoutWithDatePatternJvmElapseTime() {
- final HtmlLayout layout = HtmlLayout.newBuilder().setDatePattern("JVM_ELAPSE_TIME").build();
+ final HtmlLayout layout = HtmlLayout.newBuilder().setConfiguration(new DefaultConfiguration()).setDatePattern("JVM_ELAPSE_TIME").build();
final MyLogEvent event = new MyLogEvent();
final String actual = getDateLine(layout.toSerializable(event));
@@ -203,7 +202,7 @@ public void testLayoutWithDatePatternJvmElapseTime() {
@Test
public void testLayoutWithDatePatternUnix() {
- final HtmlLayout layout = HtmlLayout.newBuilder().setDatePattern("UNIX").build();
+ final HtmlLayout layout = HtmlLayout.newBuilder().setConfiguration(new DefaultConfiguration()).setDatePattern("UNIX").build();
final MyLogEvent event = new MyLogEvent();
final String actual = getDateLine(layout.toSerializable(event));
@@ -213,7 +212,7 @@ public void testLayoutWithDatePatternUnix() {
@Test
public void testLayoutWithDatePatternUnixMillis() {
- final HtmlLayout layout = HtmlLayout.newBuilder().setDatePattern("UNIX_MILLIS").build();
+ final HtmlLayout layout = HtmlLayout.newBuilder().setConfiguration(new DefaultConfiguration()).setDatePattern("UNIX_MILLIS").build();
final MyLogEvent event = new MyLogEvent();
final String actual = getDateLine(layout.toSerializable(event));
@@ -235,7 +234,7 @@ private String getDateLine(final String logEventString) {
}
private void testLayoutWithDatePatternFixedFormat(final FixedFormat format, final String timezone) {
- final HtmlLayout layout = HtmlLayout.newBuilder().setDatePattern(format.name()).setTimezone(timezone).build();
+ final HtmlLayout layout = HtmlLayout.newBuilder().setConfiguration(new DefaultConfiguration()).setDatePattern(format.name()).setTimezone(timezone).build();
final LogEvent event = new MyLogEvent();
final String actual = getDateLine(layout.toSerializable(event));
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
index 861a1f0e778..93017b3d597 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/Rfc5424LayoutTest.java
@@ -17,19 +17,17 @@
package org.apache.logging.log4j.core.layout;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.Core;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationProcessor;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.net.Facility;
import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
@@ -37,6 +35,7 @@
import org.apache.logging.log4j.core.util.Integers;
import org.apache.logging.log4j.core.util.KeyValuePair;
import org.apache.logging.log4j.core.util.ProcessIdUtil;
+import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.message.StructuredDataCollectionMessage;
import org.apache.logging.log4j.message.StructuredDataMessage;
import org.apache.logging.log4j.plugins.Node;
@@ -88,7 +87,7 @@ public void testLayout() throws Exception {
}
// set up appender
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, null, "ATM", null, "key1, key2, locale", null, "loginId", null, true, null, null);
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, "loginId", null, true, null, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -164,7 +163,7 @@ public void testCollection() throws Exception {
}
// set up appender
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, null, "ATM", null, "key1, key2, locale", null, "loginId", null, true, null, null);
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, "loginId", null, true, null, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -235,7 +234,7 @@ public void testEscape() throws Exception {
}
// set up layout/appender
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, "#012", "ATM", null, "key1, key2, locale", null, "loginId", null, true, null, null);
+ null, null, true, "#012", "ATM", null, "key1, key2, locale", null, "loginId", null, true, null, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -297,7 +296,7 @@ public void testException() throws Exception {
}
// set up layout/appender
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, null, "ATM", null, "key1, key2, locale", null, "loginId", "%xEx", true, null, null);
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, "loginId", "%xEx", true, null, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -329,11 +328,7 @@ public void testException() throws Exception {
* Test case for MDC logger field inclusion.
*/
@Test
- public void testMDCLoggerFields() throws Exception {
- for (final Appender appender : root.getAppenders().values()) {
- root.removeAppender(appender);
- }
-
+ public void testMDCLoggerFields() {
final LoggerFields[] loggerFields = new LoggerFields[] {
LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("source", "%C.%M")}, null, null, false),
LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("source2", "%C.%M")}, null, null, false)
@@ -341,42 +336,24 @@ public void testMDCLoggerFields() throws Exception {
// set up layout/appender
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, true, loggerFields, null);
- final ListAppender appender = new ListAppender("List", null, layout, true, false);
- appender.start();
-
- // set appender on root and set level to debug
- root.addAppender(appender);
- root.setLevel(Level.DEBUG);
-
- // output starting message
- root.info("starting logger fields test");
-
- try {
-
- final List list = appender.getMessages();
- assertTrue(list.size() > 0, "Not enough list entries");
- assertTrue(list.get(0).contains("Rfc5424LayoutTest.testMDCLoggerFields"), "No class/method");
-
- appender.clear();
- } finally {
- root.removeAppender(appender);
- appender.stop();
- }
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, true, loggerFields, new DefaultConfiguration());
+ final LogEvent event = Log4jLogEvent
+ .newBuilder()
+ .setLevel(Level.INFO)
+ .setMessage(new SimpleMessage("starting logger fields test"))
+ .setSource(new RuntimeException().getStackTrace()[0])
+ .build();
+ final String serializedEvent = layout.toSerializable(event);
+ assertTrue(serializedEvent.contains("Rfc5424LayoutTest.testMDCLoggerFields"), "No class/method");
}
@Test
public void testLoggerFields() {
- final String[] fields = new String[] {
+ final String[] expectedToContain = new String[] {
"[BAZ@32473 baz=\"org.apache.logging.log4j.core.layout.Rfc5424LayoutTest.testLoggerFields\"]",
"[RequestContext@3692 bar=\"org.apache.logging.log4j.core.layout.Rfc5424LayoutTest.testLoggerFields\"]",
"[SD-ID@32473 source=\"org.apache.logging.log4j.core.layout.Rfc5424LayoutTest.testLoggerFields\"]"
};
- final List expectedToContain = Arrays.asList(fields);
-
- for (final Appender appender : root.getAppenders().values()) {
- root.removeAppender(appender);
- }
final LoggerFields[] loggerFields = new LoggerFields[] {
LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("source", "%C.%M")}, "SD-ID",
@@ -386,30 +363,20 @@ public void testLoggerFields() {
LoggerFields.createLoggerFields(new KeyValuePair[] { new KeyValuePair("bar", "%C.%M")}, null, null, false)
};
- final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, false, loggerFields, null);
- final ListAppender appender = new ListAppender("List", null, layout, true, false);
- appender.start();
-
- root.addAppender(appender);
- root.setLevel(Level.DEBUG);
-
- root.info("starting logger fields test");
-
- try {
-
- final List list = appender.getMessages();
- assertTrue(list.size() > 0, "Not enough list entries");
- final String message = list.get(0);
- assertTrue(message.contains("Rfc5424LayoutTest.testLoggerFields"), "No class/method");
- for (final String value : expectedToContain) {
- assertTrue(message.contains(value), "Message expected to contain " + value + " but did not");
- }
- appender.clear();
- } finally {
- root.removeAppender(appender);
- appender.stop();
+ final StringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, false, loggerFields, new DefaultConfiguration());
+ final LogEvent event = Log4jLogEvent
+ .newBuilder()
+ .setLevel(Level.INFO)
+ .setMessage(new SimpleMessage("starting logger fields test"))
+ .setSource(new RuntimeException().getStackTrace()[0])
+ .build();
+ final String serializedEvent = layout.toSerializable(event);
+ assertTrue(serializedEvent.contains("Rfc5424LayoutTest.testLoggerFields"), "No class/method");
+ for (final String value : expectedToContain) {
+ assertTrue(serializedEvent.contains(value), "Message expected to contain " + value + " but did not");
}
+
}
@Test
@@ -429,7 +396,7 @@ public void testDiscardEmptyLoggerFields() {
};
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, mdcId,
- null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, false, loggerFields, null);
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, false, loggerFields, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -464,7 +431,7 @@ public void testSubstituteStructuredData() {
}
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, false, mdcId,
- null, null, true, null, "ATM", "MSG-ID", "key1, key2, locale", null, null, null, false, null, null);
+ null, null, true, null, "ATM", "MSG-ID", "key1, key2, locale", null, null, null, false, null, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -492,7 +459,7 @@ public void testParameterizedMessage() {
}
// set up appender
final AbstractStringLayout layout = Rfc5424Layout.createLayout(Facility.LOCAL0, "Event", 3692, true, "RequestContext",
- null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, true, null, null);
+ null, null, true, null, "ATM", null, "key1, key2, locale", null, null, null, true, null, new DefaultConfiguration());
final ListAppender appender = new ListAppender("List", null, layout, true, false);
appender.start();
@@ -520,6 +487,7 @@ void testLayoutBuilder() {
}
final AbstractStringLayout layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+ .setConfig(new DefaultConfiguration())
.setFacility(Facility.LOCAL0)
.setId("Event")
.setEin("1234.56.7")
@@ -551,7 +519,8 @@ void testLayoutBuilder() {
@Test
public void testLayoutBuilderDefaultValues() {
- final Rfc5424Layout layout = new Rfc5424Layout.Rfc5424LayoutBuilder().build();
+ final Configuration configuration = ctx.getConfiguration();
+ final Rfc5424Layout layout = new Rfc5424Layout.Rfc5424LayoutBuilder().setConfig(configuration).build();
checkDefaultValues(layout);
final PluginNamespace corePlugins = ctx.getInstanceFactory().getInstance(Core.PLUGIN_NAMESPACE_KEY);
@@ -561,7 +530,7 @@ public void testLayoutBuilderDefaultValues() {
node.getAttributes().put("name", "Rfc5242Layout");
final ConfigurableInstanceFactory factory = DI.createInitializedFactory();
- factory.registerBinding(Binding.from(Configuration.KEY).toInstance(ctx.getConfiguration()));
+ factory.registerBinding(Binding.from(Configuration.KEY).toInstance(configuration));
final ConfigurationProcessor processor = new ConfigurationProcessor(factory);
final Rfc5424Layout object = processor.processNodeTree(node);
assertNotNull(object);
@@ -581,6 +550,7 @@ private void checkDefaultValues(final Rfc5424Layout layout) {
@ValueSource(strings = { "123456789", "0", "2147483647", "123.45.6.78.9", "0.0.0.0.0.0.0.0.0.0.0.0.0.0" })
void testLayoutBuilderValidEids(final String eid) {
final AbstractStringLayout layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+ .setConfig(new DefaultConfiguration())
.setEin(eid)
.build();
@@ -591,6 +561,7 @@ void testLayoutBuilderValidEids(final String eid) {
@ValueSource(strings = { "abc", "someEid", "-1" })
void testLayoutBuilderInvalidEids(final String eid) {
final AbstractStringLayout layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+ .setConfig(new DefaultConfiguration())
.setEin(eid)
.build();
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SpyByteBufferDestination.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SpyByteBufferDestination.java
index 4c235a41efd..1147f0a6b5c 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SpyByteBufferDestination.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SpyByteBufferDestination.java
@@ -63,11 +63,11 @@ public ByteBuffer drain(final ByteBuffer buf) {
@Override
public void writeBytes(final ByteBuffer data) {
- unsynchronizedWrite(data);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
}
@Override
public void writeBytes(final byte[] data, final int offset, final int length) {
- unsynchronizedWrite(data, offset, length);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, offset, length, this);
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SyslogLayoutTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SyslogLayoutTest.java
index ef2da1c9b76..a319b7b2d15 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SyslogLayoutTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/layout/SyslogLayoutTest.java
@@ -25,6 +25,7 @@
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.net.Facility;
import org.apache.logging.log4j.core.test.BasicConfigurationFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
@@ -59,6 +60,7 @@ public void testLayout() throws Exception {
// set up appender
// @formatter:off
final SyslogLayout layout = SyslogLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setFacility(Facility.LOCAL0)
.setIncludeNewLine(true)
.build();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/ReusableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/ReusableLogEvent.java
new file mode 100644
index 00000000000..12e591aba04
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ReusableLogEvent.java
@@ -0,0 +1,71 @@
+/*
+ * 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.core;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.time.Instant;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.util.StringMap;
+
+public interface ReusableLogEvent extends LogEvent {
+ /**
+ * Clears all references this event has to other objects.
+ */
+ void clear();
+
+ void setLoggerFqcn(final String loggerFqcn);
+
+ void setMarker(final Marker marker);
+
+ void setLevel(final Level level);
+
+ void setLoggerName(final String loggerName);
+
+ void setMessage(final Message message);
+
+ void setThrown(final Throwable thrown);
+
+ void setTimeMillis(final long timeMillis);
+
+ void setInstant(final Instant instant);
+
+ void setSource(final StackTraceElement source);
+
+ @Override
+ StringMap getContextData();
+
+ void setContextData(final StringMap mutableContextData);
+
+ void setContextStack(final ThreadContext.ContextStack contextStack);
+
+ void setThreadId(final long threadId);
+
+ void setThreadName(final String threadName);
+
+ void setThreadPriority(final int threadPriority);
+
+ void setNanoTime(final long nanoTime);
+
+ /**
+ * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code ReusableLogEvent}.
+ * @param builder the builder whose fields to populate
+ */
+ void initializeBuilder(final Log4jLogEvent.Builder builder);
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
index 23e6f2378a6..3cfe2297ed6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
@@ -75,9 +75,9 @@ public final class AsyncAppender extends AbstractAppender {
private AsyncQueueFullPolicy asyncQueueFullPolicy;
private AsyncAppender(final String name, final Filter filter, final AppenderRef[] appenderRefs,
- final String errorRef, final int queueSize, final boolean blocking, final boolean ignoreExceptions,
- final long shutdownTimeout, final Configuration config, final boolean includeLocation,
- final BlockingQueueFactory blockingQueueFactory, final Property[] properties) {
+ final String errorRef, final int queueSize, final boolean blocking, final boolean ignoreExceptions,
+ final long shutdownTimeout, final Configuration config, final boolean includeLocation,
+ final BlockingQueueFactory blockingQueueFactory, final Property[] properties) {
super(name, filter, null, ignoreExceptions, properties);
this.queue = blockingQueueFactory.create(queueSize);
this.queueSize = queueSize;
@@ -273,7 +273,7 @@ public static class Builder> extends AbstractFilterable.Bui
private boolean ignoreExceptions = true;
@PluginElement(BlockingQueueFactory.ELEMENT_TYPE)
- private BlockingQueueFactory blockingQueueFactory = new ArrayBlockingQueueFactory<>();
+ private BlockingQueueFactory blockingQueueFactory = new ArrayBlockingQueueFactory();
public Builder setAppenderRefs(final AppenderRef[] appenderRefs) {
this.appenderRefs = appenderRefs;
@@ -320,7 +320,7 @@ public Builder setIgnoreExceptions(final boolean ignoreExceptions) {
return this;
}
- public Builder setBlockingQueueFactory(final BlockingQueueFactory blockingQueueFactory) {
+ public Builder setBlockingQueueFactory(final BlockingQueueFactory blockingQueueFactory) {
this.blockingQueueFactory = blockingQueueFactory;
return this;
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
index 1bdc922f709..47934be03b1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
@@ -18,14 +18,15 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
import org.apache.logging.log4j.core.util.Constants;
/**
@@ -177,26 +178,6 @@ public void writeBytes(final byte[] data, final int offset, final int length) {
write(data, offset, length, false);
}
- @Override
- public void withLock(final Runnable action) {
- writeLock.lock();
- try {
- action.run();
- } finally {
- writeLock.unlock();
- }
- }
-
- @Override
- public T withLock(final Supplier supplier) {
- writeLock.lock();
- try {
- return supplier.get();
- } finally {
- writeLock.unlock();
- }
- }
-
/**
* Some output streams synchronize writes while others do not. Synchronizing here insures that
* log events won't be intertwined.
@@ -291,9 +272,10 @@ protected void flushDestination() {
* @since 2.6
*/
protected void flushBuffer(final ByteBuffer buf) {
+ ((Buffer) buf).flip();
writeLock.lock();
try {
- if (buf.flip().hasRemaining()) {
+ if (buf.hasRemaining()) {
writeToDestination(buf.array(), buf.arrayOffset() + buf.position(), buf.remaining());
}
} finally {
@@ -376,7 +358,7 @@ public void writeBytes(final ByteBuffer data) {
}
writeLock.lock();
try {
- unsynchronizedWrite(data);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
} finally {
writeLock.unlock();
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
index 3569099cbbf..64c737bfc14 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java
@@ -23,6 +23,7 @@
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.LoggerFields;
import org.apache.logging.log4j.core.layout.Rfc5424Layout;
import org.apache.logging.log4j.core.layout.SyslogLayout;
@@ -113,6 +114,7 @@ public SyslogAppender build() {
if (layout == null) {
layout = RFC5424.equalsIgnoreCase(format)
? new Rfc5424Layout.Rfc5424LayoutBuilder()
+ .setConfig(new DefaultConfiguration())
.setFacility(facility)
.setId(id)
.setEin(enterpriseNumber)
@@ -134,6 +136,7 @@ public SyslogAppender build() {
.build() :
// @formatter:off
SyslogLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setFacility(facility)
.setIncludeNewLine(newLine)
.setEscapeNL(escapeNL)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ArrayBlockingQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ArrayBlockingQueueFactory.java
index 08eceedaa86..c45f438fb00 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ArrayBlockingQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/ArrayBlockingQueueFactory.java
@@ -30,14 +30,14 @@
*/
@Configurable(elementType = BlockingQueueFactory.ELEMENT_TYPE)
@Plugin("ArrayBlockingQueue")
-public class ArrayBlockingQueueFactory implements BlockingQueueFactory {
+public class ArrayBlockingQueueFactory implements BlockingQueueFactory {
@Override
- public BlockingQueue create(final int capacity) {
+ public BlockingQueue create(final int capacity) {
return new ArrayBlockingQueue<>(capacity);
}
@PluginFactory
- public static ArrayBlockingQueueFactory createFactory() {
- return new ArrayBlockingQueueFactory<>();
+ public static ArrayBlockingQueueFactory createFactory() {
+ return new ArrayBlockingQueueFactory();
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
index 636330cf539..fabd4642330 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
@@ -34,6 +34,7 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.AbstractLifeCycle;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.ReusableLogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
import org.apache.logging.log4j.core.impl.LogEventFactory;
@@ -81,8 +82,8 @@ public Log4jEventWrapper(final MutableLogEvent mutableLogEvent) {
*/
public void clear() {
loggerConfig = null;
- if (event instanceof MutableLogEvent) {
- ((MutableLogEvent) event).clear();
+ if (event instanceof ReusableLogEvent) {
+ ((ReusableLogEvent) event).clear();
} else {
event = null;
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BlockingQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BlockingQueueFactory.java
index 75ca65affd3..2a0e473cf9b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BlockingQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BlockingQueueFactory.java
@@ -23,7 +23,7 @@
*
* @since 2.7
*/
-public interface BlockingQueueFactory {
+public interface BlockingQueueFactory {
/**
* The {@link org.apache.logging.log4j.plugins.Configurable#elementType() element type} to use for plugins
@@ -38,5 +38,5 @@ public interface BlockingQueueFactory {
* @param capacity maximum size of the queue if supported
* @return a new BlockingQueue
*/
- BlockingQueue create(int capacity);
+ BlockingQueue create(int capacity);
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
index 269d47cbb74..9e511b79954 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
@@ -32,7 +32,7 @@
*/
@Configurable(elementType = BlockingQueueFactory.ELEMENT_TYPE, printObject = true)
@Plugin("DisruptorBlockingQueue")
-public class DisruptorBlockingQueueFactory implements BlockingQueueFactory {
+public class DisruptorBlockingQueueFactory implements BlockingQueueFactory {
private final SpinPolicy spinPolicy;
@@ -41,14 +41,14 @@ private DisruptorBlockingQueueFactory(final SpinPolicy spinPolicy) {
}
@Override
- public BlockingQueue create(final int capacity) {
+ public BlockingQueue create(final int capacity) {
return new DisruptorBlockingQueue<>(capacity, spinPolicy);
}
@PluginFactory
- public static DisruptorBlockingQueueFactory createFactory(
+ public static DisruptorBlockingQueueFactory createFactory(
@PluginAttribute(defaultString = "WAITING") final SpinPolicy spinPolicy
) {
- return new DisruptorBlockingQueueFactory<>(spinPolicy);
+ return new DisruptorBlockingQueueFactory(spinPolicy);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java
index 22e51625cbb..5cd5c551fe1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/JCToolsBlockingQueueFactory.java
@@ -34,7 +34,7 @@
*/
@Configurable(elementType = BlockingQueueFactory.ELEMENT_TYPE, printObject = true)
@Plugin("JCToolsBlockingQueue")
-public class JCToolsBlockingQueueFactory implements BlockingQueueFactory {
+public class JCToolsBlockingQueueFactory implements BlockingQueueFactory {
private final WaitStrategy waitStrategy;
@@ -43,14 +43,14 @@ private JCToolsBlockingQueueFactory(final WaitStrategy waitStrategy) {
}
@Override
- public BlockingQueue create(final int capacity) {
+ public BlockingQueue create(final int capacity) {
return new MpscBlockingQueue<>(capacity, waitStrategy);
}
@PluginFactory
- public static JCToolsBlockingQueueFactory createFactory(
+ public static JCToolsBlockingQueueFactory createFactory(
@PluginAttribute(defaultString = "PARK") final WaitStrategy waitStrategy) {
- return new JCToolsBlockingQueueFactory<>(waitStrategy);
+ return new JCToolsBlockingQueueFactory(waitStrategy);
}
/**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/LinkedTransferQueueFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/LinkedTransferQueueFactory.java
index 32f54913293..40c73929e6d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/LinkedTransferQueueFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/LinkedTransferQueueFactory.java
@@ -30,14 +30,14 @@
*/
@Configurable(elementType = BlockingQueueFactory.ELEMENT_TYPE, printObject = true)
@Plugin("LinkedTransferQueue")
-public class LinkedTransferQueueFactory implements BlockingQueueFactory {
+public class LinkedTransferQueueFactory implements BlockingQueueFactory {
@Override
- public BlockingQueue create(final int capacity) {
+ public BlockingQueue create(final int capacity) {
return new LinkedTransferQueue<>();
}
@PluginFactory
- public static LinkedTransferQueueFactory createFactory() {
- return new LinkedTransferQueueFactory<>();
+ public static LinkedTransferQueueFactory createFactory() {
+ return new LinkedTransferQueueFactory();
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index eb22159d52a..df1165e7acb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -23,6 +23,7 @@
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.ReusableLogEvent;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.MementoMessage;
@@ -38,7 +39,6 @@
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.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.StringBuilders;
import org.apache.logging.log4j.util.StringMap;
import org.apache.logging.log4j.util.Strings;
@@ -49,7 +49,7 @@
* When the Disruptor is started, the RingBuffer is populated with event objects. These objects are then re-used during
* the life of the RingBuffer.
*/
-public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequence, ParameterVisitable {
+public class RingBufferLogEvent implements ReusableLogEvent, ReusableMessage, CharSequence, ParameterVisitable {
/** The {@code EventFactory} for {@code RingBufferLogEvent}s. */
public static final EventFactory FACTORY = new Factory();
@@ -82,7 +82,7 @@ public RingBufferLogEvent newInstance() {
private String messageFormat;
private StringBuilder messageText;
private Object[] parameters;
- private transient Throwable thrown;
+ private Throwable thrown;
private ThrowableProxy thrownProxy;
private StringMap contextData = ContextDataFactory.createContextData();
private Marker marker;
@@ -90,7 +90,7 @@ public RingBufferLogEvent newInstance() {
private StackTraceElement location;
private ContextStack contextStack;
- private transient AsyncLogger asyncLogger;
+ private AsyncLogger asyncLogger;
public void setValues(final AsyncLogger anAsyncLogger, final String aLoggerName, final Marker aMarker,
final String theFqcn, final Level aLevel, final Message msg, final Throwable aThrowable,
@@ -129,7 +129,8 @@ public LogEvent toImmutable() {
return toMemento();
}
- private void setMessage(final Message msg) {
+ @Override
+ public void setMessage(final Message msg) {
if (msg instanceof ReusableMessage) {
final ReusableMessage reusable = (ReusableMessage) msg;
reusable.formatTo(getMessageTextForWriting());
@@ -198,16 +199,31 @@ public String getLoggerName() {
return loggerName;
}
+ @Override
+ public void setLoggerName(final String loggerName) {
+ this.loggerName = loggerName;
+ }
+
@Override
public Marker getMarker() {
return marker;
}
+ @Override
+ public void setMarker(final Marker marker) {
+ this.marker = marker;
+ }
+
@Override
public String getLoggerFqcn() {
return fqcn;
}
+ @Override
+ public void setLoggerFqcn(final String loggerFqcn) {
+ fqcn = loggerFqcn;
+ }
+
@Override
public Level getLevel() {
if (level == null) {
@@ -216,6 +232,11 @@ public Level getLevel() {
return level;
}
+ @Override
+ public void setLevel(final Level level) {
+ this.level = level;
+ }
+
@Override
public Message getMessage() {
if (message == null) {
@@ -332,6 +353,11 @@ public Throwable getThrown() {
return thrown;
}
+ @Override
+ public void setThrown(final Throwable thrown) {
+ this.thrown = thrown;
+ }
+
@Override
public ThrowableProxy getThrownProxy() {
// lazily instantiate the (expensive) ThrowableProxy
@@ -344,11 +370,12 @@ public ThrowableProxy getThrownProxy() {
}
@Override
- public ReadOnlyStringMap getContextData() {
+ public StringMap getContextData() {
return contextData;
}
- void setContextData(final StringMap contextData) {
+ @Override
+ public void setContextData(final StringMap contextData) {
this.contextData = contextData;
}
@@ -357,44 +384,85 @@ public ContextStack getContextStack() {
return contextStack;
}
+ @Override
+ public void setContextStack(final ContextStack contextStack) {
+ this.contextStack = contextStack;
+ }
+
@Override
public long getThreadId() {
return threadId;
}
+ @Override
+ public void setThreadId(final long threadId) {
+ this.threadId = threadId;
+ }
+
@Override
public String getThreadName() {
return threadName;
}
+ @Override
+ public void setThreadName(final String threadName) {
+ this.threadName = threadName;
+ }
+
@Override
public int getThreadPriority() {
return threadPriority;
}
+ @Override
+ public void setThreadPriority(final int threadPriority) {
+ this.threadPriority = threadPriority;
+ }
+
@Override
public StackTraceElement getSource() {
return location;
}
+ @Override
+ public void setSource(final StackTraceElement source) {
+ location = source;
+ }
+
@Override
public long getTimeMillis() {
return message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : instant.getEpochMillisecond();
}
+ @Override
+ public void setTimeMillis(final long timeMillis) {
+ instant.initFromEpochMilli(timeMillis, 0);
+ }
+
@Override
public Instant getInstant() {
return instant;
}
+ @Override
+ public void setInstant(final Instant instant) {
+ this.instant.initFrom(instant);
+ }
+
@Override
public long getNanoTime() {
return nanoTime;
}
+ @Override
+ public void setNanoTime(final long nanoTime) {
+ this.nanoTime = nanoTime;
+ }
+
/**
* Release references held by ring buffer to allow objects to be garbage-collected.
*/
+ @Override
public void clear() {
this.populated = false;
@@ -437,6 +505,7 @@ public void clear() {
* Initializes the specified {@code Log4jLogEvent.Builder} from this {@code RingBufferLogEvent}.
* @param builder the builder whose fields to populate
*/
+ @Override
public void initializeBuilder(final Log4jLogEvent.Builder builder) {
// If the data is not frozen, make a copy of it.
// TODO: merge with MementoLogEvent#memento
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
index a849c57e37a..2fda0b6b7a1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
@@ -30,6 +30,7 @@
import org.apache.logging.log4j.core.async.AsyncLoggerConfigDelegate;
import org.apache.logging.log4j.core.async.AsyncWaitStrategyFactory;
import org.apache.logging.log4j.core.filter.Filterable;
+import org.apache.logging.log4j.core.impl.LogEventFactory;
import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.core.net.Advertiser;
@@ -39,6 +40,7 @@
import org.apache.logging.log4j.core.util.WatchManager;
import org.apache.logging.log4j.plugins.Node;
import org.apache.logging.log4j.plugins.di.Key;
+import org.apache.logging.log4j.spi.RecyclerFactory;
import org.apache.logging.log4j.util.PropertyEnvironment;
/**
@@ -247,4 +249,13 @@ default T getComponent(Key key) {
* @return the logger context.
*/
LoggerContext getLoggerContext();
+
+ default LogEventFactory getLogEventFactory() {
+ return getComponent(LogEventFactory.KEY);
+ }
+
+ default RecyclerFactory getRecyclerFactory() {
+ return getComponent(Key.forClass(RecyclerFactory.class));
+ }
+
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
index a86f0470fee..13424c6cc35 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/LoggerConfig.java
@@ -37,7 +37,6 @@
import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.LogEventFactory;
-import org.apache.logging.log4j.core.impl.ReusableLogEventFactory;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.plugins.Configurable;
@@ -252,7 +251,8 @@ protected LoggerConfig(
this.includeLocation = includeLocation;
this.config = config;
if (properties != null && properties.length > 0) {
- this.properties = List.of(properties.clone());
+ // don't use List.of() here as that will create temporary iterators downstream
+ this.properties = Arrays.asList(properties.clone());
} else {
this.properties = null;
}
@@ -477,7 +477,7 @@ public void log(final String loggerName, final String fqcn, final Marker marker,
log(logEvent, LoggerConfigPredicate.ALL);
} finally {
// LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString())
- ReusableLogEventFactory.release(logEvent);
+ logEventFactory.recycle(logEvent);
}
}
@@ -506,7 +506,7 @@ public void log(final String loggerName, final String fqcn, final StackTraceElem
log(logEvent, LoggerConfigPredicate.ALL);
} finally {
// LOG4J2-1583 prevent scrambled logs when logging calls are nested (logging in toString())
- ReusableLogEventFactory.release(logEvent);
+ logEventFactory.recycle(logEvent);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java
index 8420c1f3be6..acd2f6fb2f6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/DefaultBundle.java
@@ -43,9 +43,7 @@
import org.apache.logging.log4j.plugins.SingletonFactory;
import org.apache.logging.log4j.plugins.condition.ConditionalOnMissingBinding;
import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.spi.CopyOnWrite;
-import org.apache.logging.log4j.spi.DefaultThreadContextMap;
-import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
+import org.apache.logging.log4j.spi.*;
import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled;
@@ -64,6 +62,11 @@
*/
public class DefaultBundle {
+ @SingletonFactory
+ public RecyclerFactory defaultRecyclerFactory() {
+ return LoggingSystem.getRecyclerFactory();
+ }
+
@SingletonFactory
@ConditionalOnMissingBinding
public ContextSelector defaultContextSelector(final ConfigurableInstanceFactory instanceFactory) {
@@ -101,8 +104,8 @@ public ContextDataInjector defaultContextDataInjector() {
@SingletonFactory
@ConditionalOnMissingBinding
public LogEventFactory defaultLogEventFactory(
- final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock) {
- return isThreadLocalsEnabled() ? new ReusableLogEventFactory(injector, clock, nanoClock) :
+ final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock, final RecyclerFactory recyclerFactory) {
+ return isThreadLocalsEnabled() ? new ReusableLogEventFactory(injector, clock, nanoClock, recyclerFactory) :
new DefaultLogEventFactory(injector, clock, nanoClock);
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 777a9dfdfc0..40bdb57849d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -23,7 +23,7 @@
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.ContextDataInjector;
import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.async.RingBufferLogEvent;
+import org.apache.logging.log4j.core.ReusableLogEvent;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.time.Clock;
import org.apache.logging.log4j.core.time.ClockFactory;
@@ -91,12 +91,8 @@ public Builder() {
public Builder(final LogEvent other) {
Objects.requireNonNull(other);
- if (other instanceof RingBufferLogEvent) {
- ((RingBufferLogEvent) other).initializeBuilder(this);
- return;
- }
- if (other instanceof MutableLogEvent) {
- ((MutableLogEvent) other).initializeBuilder(this);
+ if (other instanceof ReusableLogEvent) {
+ ((ReusableLogEvent) other).initializeBuilder(this);
return;
}
this.loggerFqcn = other.getLoggerFqcn();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
index 28d7baf5734..7913e71f34e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/LogEventFactory.java
@@ -45,4 +45,6 @@ default LogEvent createEvent(
Throwable t) {
return createEvent(loggerName, marker, fqcn, level, data, properties, t);
}
+
+ default void recycle(final LogEvent event) {}
}
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 039de1232b0..73fa72eb90c 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
@@ -22,6 +22,7 @@
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.ReusableLogEvent;
import org.apache.logging.log4j.core.async.InternalAsyncUtil;
import org.apache.logging.log4j.core.time.Clock;
import org.apache.logging.log4j.core.time.Instant;
@@ -34,17 +35,18 @@
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.util.ReadOnlyStringMap;
+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;
import org.apache.logging.log4j.util.Strings;
/**
- * Mutable implementation of the {@code LogEvent} interface.
+ * Mutable implementation of the {@code ReusableLogEvent} interface.
* @since 2.6
+ * @see Recycler
*/
-public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisitable {
+public class MutableLogEvent implements ReusableLogEvent, ReusableMessage, ParameterVisitable {
private static final Message EMPTY = new SimpleMessage(Strings.EMPTY);
private int threadPriority;
@@ -68,7 +70,6 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
private String loggerFqcn;
private StackTraceElement source;
private ThreadContext.ContextStack contextStack;
- transient boolean reserved = false;
public MutableLogEvent() {
// messageText and the parameter array are lazily initialized
@@ -86,9 +87,9 @@ public LogEvent toImmutable() {
}
/**
- * Initialize the fields of this {@code MutableLogEvent} from another event.
+ * Initialize the fields of this {@code ReusableLogEvent} from another event.
*
- * This method is used on async logger ringbuffer slots holding MutableLogEvent objects in each slot.
+ * This method is used on async logger ringbuffer slots holding ReusableLogEvent objects in each slot.
*
*
* @param event the event to copy data from
@@ -119,9 +120,7 @@ public void initFrom(final LogEvent event) {
setMessage(event.getMessage());
}
- /**
- * Clears all references this event has to other objects.
- */
+ @Override
public void clear() {
loggerFqcn = null;
marker = null;
@@ -166,6 +165,7 @@ public String getLoggerFqcn() {
return loggerFqcn;
}
+ @Override
public void setLoggerFqcn(final String loggerFqcn) {
this.loggerFqcn = loggerFqcn;
}
@@ -175,6 +175,7 @@ public Marker getMarker() {
return marker;
}
+ @Override
public void setMarker(final Marker marker) {
this.marker = marker;
}
@@ -187,6 +188,7 @@ public Level getLevel() {
return level;
}
+ @Override
public void setLevel(final Level level) {
this.level = level;
}
@@ -196,6 +198,7 @@ public String getLoggerName() {
return loggerName;
}
+ @Override
public void setLoggerName(final String loggerName) {
this.loggerName = loggerName;
}
@@ -208,6 +211,7 @@ public Message getMessage() {
return message;
}
+ @Override
public void setMessage(final Message msg) {
if (msg instanceof ReusableMessage) {
final ReusableMessage reusable = (ReusableMessage) msg;
@@ -312,6 +316,7 @@ public Throwable getThrown() {
return thrown;
}
+ @Override
public void setThrown(final Throwable thrown) {
this.thrown = thrown;
}
@@ -330,6 +335,7 @@ public long getTimeMillis() {
return instant.getEpochMillisecond();
}
+ @Override
public void setTimeMillis(final long timeMillis) {
this.instant.initFromEpochMilli(timeMillis, 0);
}
@@ -339,6 +345,11 @@ public Instant getInstant() {
return instant;
}
+ @Override
+ public void setInstant(final Instant instant) {
+ this.instant.initFrom(instant);
+ }
+
/**
* Returns the ThrowableProxy associated with the event, or null.
* @return The ThrowableProxy associated with the event.
@@ -351,6 +362,7 @@ public ThrowableProxy getThrownProxy() {
return thrownProxy;
}
+ @Override
public void setSource(final StackTraceElement source) {
this.source = source;
}
@@ -373,10 +385,11 @@ public StackTraceElement getSource() {
}
@Override
- public ReadOnlyStringMap getContextData() {
+ public StringMap getContextData() {
return contextData;
}
+ @Override
public void setContextData(final StringMap mutableContextData) {
this.contextData = mutableContextData;
}
@@ -386,6 +399,7 @@ public ThreadContext.ContextStack getContextStack() {
return contextStack;
}
+ @Override
public void setContextStack(final ThreadContext.ContextStack contextStack) {
this.contextStack = contextStack;
}
@@ -395,6 +409,7 @@ public long getThreadId() {
return threadId;
}
+ @Override
public void setThreadId(final long threadId) {
this.threadId = threadId;
}
@@ -404,6 +419,7 @@ public String getThreadName() {
return threadName;
}
+ @Override
public void setThreadName(final String threadName) {
this.threadName = threadName;
}
@@ -413,6 +429,7 @@ public int getThreadPriority() {
return threadPriority;
}
+ @Override
public void setThreadPriority(final int threadPriority) {
this.threadPriority = threadPriority;
}
@@ -442,14 +459,12 @@ public long getNanoTime() {
return nanoTime;
}
+ @Override
public void setNanoTime(final long nanoTime) {
this.nanoTime = nanoTime;
}
- /**
- * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code MutableLogEvent}.
- * @param builder the builder whose fields to populate
- */
+ @Override
public void initializeBuilder(final Log4jLogEvent.Builder builder) {
builder.setContextData(contextData) //
.setContextStack(contextStack) //
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
index d47e1c765b5..834c0d9c847 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
@@ -23,32 +23,43 @@
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.ContextDataInjector;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.ReusableLogEvent;
import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.time.Clock;
import org.apache.logging.log4j.core.time.NanoClock;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.plugins.Inject;
-import org.apache.logging.log4j.util.StringMap;
+import org.apache.logging.log4j.spi.Recycler;
+import org.apache.logging.log4j.spi.RecyclerFactory;
/**
- * Garbage-free LogEventFactory that reuses a single mutable log event.
+ * Garbage-free LogEventFactory that recycles mutable {@link LogEvent} instances.
* @since 2.6
+ * @see Recycler
*/
public class ReusableLogEventFactory implements LogEventFactory {
private static final ThreadNameCachingStrategy THREAD_NAME_CACHING_STRATEGY = ThreadNameCachingStrategy.create();
- private static final ThreadLocal mutableLogEventThreadLocal = new ThreadLocal<>();
-
private final ContextDataInjector injector;
private final Clock clock;
private final NanoClock nanoClock;
+ private final Recycler recycler;
@Inject
- public ReusableLogEventFactory(final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock) {
+ public ReusableLogEventFactory(final ContextDataInjector injector, final Clock clock, final NanoClock nanoClock,
+ final RecyclerFactory recyclerFactory) {
this.injector = injector;
this.clock = clock;
this.nanoClock = nanoClock;
+ this.recycler = recyclerFactory.create(() -> {
+ final MutableLogEvent event = new MutableLogEvent();
+ final Thread currentThread = Thread.currentThread();
+ event.setThreadId(currentThread.getId());
+ event.setThreadName(currentThread.getName());
+ event.setThreadPriority(currentThread.getPriority());
+ return event;
+ });
}
/**
@@ -86,8 +97,7 @@ public LogEvent createEvent(final String loggerName, final Marker marker,
public LogEvent createEvent(final String loggerName, final Marker marker,
final String fqcn, final StackTraceElement location, final Level level, final Message message,
final List properties, final Throwable t) {
- final MutableLogEvent result = getOrCreateMutableLogEvent();
- result.reserved = true;
+ MutableLogEvent result = recycler.acquire();
// No need to clear here, values are cleared in release when reserved is set to false.
// If the event was dirty we'd create a new one.
@@ -99,7 +109,7 @@ public LogEvent createEvent(final String loggerName, final Marker marker,
result.initTime(clock, nanoClock);
result.setThrown(t);
result.setSource(location);
- result.setContextData(injector.injectContextData(properties, (StringMap) result.getContextData()));
+ result.setContextData(injector.injectContextData(properties, result.getContextData()));
result.setContextStack(ThreadContext.getDepth() == 0 ? ThreadContext.EMPTY_STACK : ThreadContext.cloneStack());// mutable copy
if (THREAD_NAME_CACHING_STRATEGY == ThreadNameCachingStrategy.UNCACHED) {
@@ -109,22 +119,14 @@ public LogEvent createEvent(final String loggerName, final Marker marker,
return result;
}
- private static MutableLogEvent getOrCreateMutableLogEvent() {
- final MutableLogEvent result = mutableLogEventThreadLocal.get();
- return result == null || result.reserved ? createInstance(result) : result;
- }
-
- private static MutableLogEvent createInstance(final MutableLogEvent existing) {
- final MutableLogEvent result = new MutableLogEvent();
-
- // usually no need to re-initialize thread-specific fields since the event is stored in a ThreadLocal
- result.setThreadId(Thread.currentThread().getId());
- result.setThreadName(Thread.currentThread().getName()); // Thread.getName() allocates Objects on each call
- result.setThreadPriority(Thread.currentThread().getPriority());
- if (existing == null) {
- mutableLogEventThreadLocal.set(result);
+ @Override
+ public void recycle(final LogEvent event) {
+ if (event instanceof ReusableLogEvent) {
+ ((ReusableLogEvent) event).clear();
+ if (event instanceof MutableLogEvent) {
+ recycler.release((MutableLogEvent) event);
+ }
}
- return result;
}
/**
@@ -132,12 +134,12 @@ private static MutableLogEvent createInstance(final MutableLogEvent existing) {
* This flag is used internally to verify that a reusable log event is no longer in use and can be reused.
* @param logEvent the log event to make available again
* @since 2.7
+ * @deprecated use {@link #recycle(LogEvent)}
*/
+ @Deprecated(since = "3.0.0")
public static void release(final LogEvent logEvent) { // LOG4J2-1583
- if (logEvent instanceof MutableLogEvent) {
- final MutableLogEvent mutableLogEvent = (MutableLogEvent) logEvent;
- mutableLogEvent.clear();
- mutableLogEvent.reserved = false;
+ if (logEvent instanceof ReusableLogEvent) {
+ ((ReusableLogEvent) logEvent).clear();
}
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
index 6871137bc7f..ee7f2ed920b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/AbstractLayout.java
@@ -16,14 +16,17 @@
*/
package org.apache.logging.log4j.core.layout;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.Map;
+import java.util.Objects;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.StringLayout;
import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.plugins.Inject;
-import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
+import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Cast;
@@ -32,6 +35,8 @@
*/
public abstract class AbstractLayout implements StringLayout {
+ private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
+
/**
* Subclasses can extend this abstract Builder.
*
@@ -39,8 +44,16 @@ public abstract class AbstractLayout implements StringLayout {
*/
public abstract static class Builder> {
+ @PluginConfiguration
private Configuration configuration;
+
+ @PluginBuilderAttribute
+ private Charset charset;
+
+ @PluginBuilderAttribute
private byte[] footer;
+
+ @PluginBuilderAttribute
private byte[] header;
public B asBuilder() {
@@ -51,6 +64,10 @@ public Configuration getConfiguration() {
return configuration;
}
+ public Charset getCharset() {
+ return charset;
+ }
+
public byte[] getFooter() {
return footer;
}
@@ -59,18 +76,22 @@ public byte[] getHeader() {
return header;
}
- @Inject
public B setConfiguration(final Configuration configuration) {
this.configuration = configuration;
return asBuilder();
}
- public B setFooter(@PluginAttribute final byte[] footer) {
+ public B setCharset(final Charset charset) {
+ this.charset = charset;
+ return asBuilder();
+ }
+
+ public B setFooter(final byte[] footer) {
this.footer = footer;
return asBuilder();
}
- public B setHeader(@PluginAttribute final byte[] header) {
+ public B setHeader(final byte[] header) {
this.header = header;
return asBuilder();
}
@@ -87,6 +108,11 @@ public B setHeader(@PluginAttribute final byte[] header) {
*/
protected final Configuration configuration;
+ /**
+ * The character set used for encoding log events.
+ */
+ protected final Charset charset;
+
/**
* The number of events successfully processed by this layout.
*/
@@ -105,16 +131,19 @@ public B setHeader(@PluginAttribute final byte[] header) {
/**
* Constructs a layout with an optional header and footer.
*
- * @param configuration
- * The configuration
- * @param header
- * The header to include when the stream is opened. May be null.
- * @param footer
- * The footer to add when the stream is closed. May be null.
+ * @param configuration a configuration
+ * @param charset a character set used for encoding log events; if null, UTF-8 will be used
+ * @param header a header to include when the stream is opened, may be null
+ * @param footer the footer to add when the stream is closed, may be null
*/
- public AbstractLayout(final Configuration configuration, final byte[] header, final byte[] footer) {
+ public AbstractLayout(
+ final Configuration configuration,
+ final Charset charset,
+ final byte[] header,
+ final byte[] footer) {
super();
- this.configuration = configuration;
+ this.configuration = Objects.requireNonNull(configuration, "configuration");
+ this.charset = charset != null ? charset : DEFAULT_CHARSET;
this.header = header;
this.footer = footer;
}
@@ -123,6 +152,11 @@ public Configuration getConfiguration() {
return configuration;
}
+ @Override
+ public Charset getCharset() {
+ return charset;
+ }
+
@Override
public Map getContentFormat() {
return Map.of();
@@ -162,30 +196,39 @@ protected void markEvent() {
* Subclasses can override this method to provide a garbage-free implementation. For text-based layouts,
* {@code AbstractStringLayout} provides various convenience methods to help with this:
*
");
+ appendLs(sbuf, " ");
+ appendLs(sbuf, "");
+ return getBytes(sbuf.toString());
+ } finally {
+ stringBuilderRecycler.release(sbuf);
+ }
}
/**
@@ -350,7 +371,7 @@ public byte[] getFooter() {
* @return an HTML Layout.
*/
public static HtmlLayout createDefaultLayout() {
- return newBuilder().build();
+ return newBuilder().setConfiguration(new DefaultConfiguration()).build();
}
@PluginFactory
@@ -360,6 +381,9 @@ public static Builder newBuilder() {
public static class Builder implements org.apache.logging.log4j.plugins.util.Builder {
+ @PluginConfiguration
+ private Configuration configuration;
+
@PluginBuilderAttribute
private boolean locationInfo = false;
@@ -387,6 +411,11 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui
private Builder() {
}
+ public Builder setConfiguration(final Configuration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
public Builder setLocationInfo(final boolean locationInfo) {
this.locationInfo = locationInfo;
return this;
@@ -433,8 +462,9 @@ public HtmlLayout build() {
if (contentType == null) {
contentType = DEFAULT_CONTENT_TYPE + "; charset=" + charset;
}
- return new HtmlLayout(locationInfo, title, contentType, charset, fontName, fontSize.getFontSize(),
- fontSize.larger().getFontSize(), datePattern, timezone);
+ return new HtmlLayout(
+ configuration, locationInfo, title, contentType, charset, fontName, fontSize.getFontSize(),
+ fontSize.larger().getFontSize(), datePattern, timezone);
}
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java
index 6bfb9bdafca..7d6e5064548 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/LockingStringBuilderEncoder.java
@@ -23,7 +23,6 @@
import java.util.Objects;
import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.status.StatusLogger;
/**
* Encoder for StringBuilders that locks on the ByteBufferDestination.
@@ -53,17 +52,14 @@ private CharBuffer getCharBuffer() {
public void encode(final StringBuilder source, final ByteBufferDestination destination) {
try {
// This synchronized is needed to be able to call destination.getByteBuffer()
- destination.withLock(() -> TextEncoderHelper.encodeText(
- charsetEncoder, cachedCharBuffer, destination.getByteBuffer(), source, destination));
- } catch (final Exception ex) {
- logEncodeTextException(ex, source, destination);
- TextEncoderHelper.encodeTextFallBack(charset, source, destination);
+ synchronized (destination) {
+ TextEncoderHelper.encodeText(charsetEncoder, cachedCharBuffer, destination.getByteBuffer(), source,
+ destination);
+ }
+ } catch (final Exception error) {
+ TextEncoderHelper.encodeTextFallback(charset, source, destination, error);
}
}
- private void logEncodeTextException(final Exception ex, final StringBuilder text,
- final ByteBufferDestination destination) {
- StatusLogger.getLogger().error("Recovering from LockingStringBuilderEncoder.encode('{}') error", text, ex);
- }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
index 8f97c5c0cb1..e0dfdad4fdb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java
@@ -37,6 +37,7 @@
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginElement;
import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.spi.Recycler;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.PropertyEnvironment;
import org.apache.logging.log4j.util.Strings;
@@ -193,22 +194,19 @@ public void serialize(final LogEvent event, final StringBuilder stringBuilder) {
@Override
public void encode(final LogEvent event, final ByteBufferDestination destination) {
- final StringBuilder text = toText(eventSerializer, event, getStringBuilder());
- final Encoder encoder = getStringBuilderEncoder();
- encoder.encode(text, destination);
- trimToMaxSize(text);
- }
-
- /**
- * Creates a text representation of the specified log event
- * and writes it into the specified StringBuilder.
- *
- * Implementations are free to return a new StringBuilder if they can
- * detect in advance that the specified StringBuilder is too small.
- */
- private StringBuilder toText(final Serializer2 serializer, final LogEvent event,
- final StringBuilder destination) {
- return serializer.toSerializable(event, destination);
+ final StringBuilder builder = stringBuilderRecycler.acquire();
+ StringBuilder text = builder;
+ try {
+ text = eventSerializer.toSerializable(event, builder);
+ final Encoder encoder = stringBuilderEncoderRecycler.acquire();
+ try {
+ encoder.encode(text, destination);
+ } finally {
+ stringBuilderEncoderRecycler.release(encoder);
+ }
+ } finally {
+ stringBuilderRecycler.release(text);
+ }
}
/**
@@ -239,21 +237,23 @@ private interface PatternSerializer extends Serializer, Serializer2 {}
private static final class NoFormatPatternSerializer implements PatternSerializer {
private final LogEventPatternConverter[] converters;
+ private final Recycler recycler;
- private NoFormatPatternSerializer(final PatternFormatter[] formatters) {
+ private NoFormatPatternSerializer(final PatternFormatter[] formatters, final Recycler recycler) {
this.converters = new LogEventPatternConverter[formatters.length];
for (int i = 0; i < formatters.length; i++) {
converters[i] = formatters[i].getConverter();
}
+ this.recycler = recycler;
}
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder sb = getStringBuilder();
+ final StringBuilder sb = recycler.acquire();
try {
return toSerializable(event, sb).toString();
} finally {
- trimToMaxSize(sb);
+ recycler.release(sb);
}
}
@@ -284,18 +284,20 @@ public String toString() {
private static final class PatternFormatterPatternSerializer implements PatternSerializer {
private final PatternFormatter[] formatters;
+ private final Recycler recycler;
- private PatternFormatterPatternSerializer(final PatternFormatter[] formatters) {
+ private PatternFormatterPatternSerializer(final PatternFormatter[] formatters, final Recycler recycler) {
this.formatters = formatters;
+ this.recycler = recycler;
}
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder sb = getStringBuilder();
+ final StringBuilder sb = recycler.acquire();
try {
return toSerializable(event, sb).toString();
} finally {
- trimToMaxSize(sb);
+ recycler.release(sb);
}
}
@@ -320,19 +322,22 @@ private static final class PatternSerializerWithReplacement implements Serialize
private final PatternSerializer delegate;
private final RegexReplacement replace;
+ private final Recycler recycler;
- private PatternSerializerWithReplacement(final PatternSerializer delegate, final RegexReplacement replace) {
+ private PatternSerializerWithReplacement(final PatternSerializer delegate, final RegexReplacement replace,
+ final Recycler recycler) {
this.delegate = delegate;
this.replace = replace;
+ this.recycler = recycler;
}
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder sb = getStringBuilder();
+ final StringBuilder sb = recycler.acquire();
try {
return toSerializable(event, sb).toString();
} finally {
- trimToMaxSize(sb);
+ recycler.release(sb);
}
}
@@ -380,6 +385,7 @@ public Serializer build() {
if (Strings.isEmpty(pattern) && Strings.isEmpty(defaultPattern)) {
return null;
}
+ final Recycler recycler = createStringBuilderRecycler(configuration.getRecyclerFactory());
if (patternSelector == null) {
try {
final PatternParser parser = createPatternParser(configuration);
@@ -395,14 +401,14 @@ public Serializer build() {
}
}
final PatternSerializer serializer = hasFormattingInfo
- ? new PatternFormatterPatternSerializer(formatters)
- : new NoFormatPatternSerializer(formatters);
- return replace == null ? serializer : new PatternSerializerWithReplacement(serializer, replace);
+ ? new PatternFormatterPatternSerializer(formatters, recycler)
+ : new NoFormatPatternSerializer(formatters, recycler);
+ return replace == null ? serializer : new PatternSerializerWithReplacement(serializer, replace, recycler);
} catch (final RuntimeException ex) {
throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
}
}
- return new PatternSelectorSerializer(patternSelector, replace);
+ return new PatternSelectorSerializer(patternSelector, replace, recycler);
}
public SerializerBuilder setConfiguration(final Configuration configuration) {
@@ -451,20 +457,23 @@ private static final class PatternSelectorSerializer implements Serializer, Seri
private final PatternSelector patternSelector;
private final RegexReplacement replace;
+ private final Recycler recycler;
- private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace) {
+ private PatternSelectorSerializer(final PatternSelector patternSelector, final RegexReplacement replace,
+ final Recycler recycler) {
super();
this.patternSelector = patternSelector;
this.replace = replace;
+ this.recycler = recycler;
}
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder sb = getStringBuilder();
+ final StringBuilder sb = recycler.acquire();
try {
return toSerializable(event, sb).toString();
} finally {
- trimToMaxSize(sb);
+ recycler.release(sb);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
index 56aea3e7275..b3cf2756ad7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/Rfc5424Layout.java
@@ -140,7 +140,7 @@ private Rfc5424Layout(final Configuration config, final Facility facility, final
final String mdcPrefix, final String eventPrefix, final String appName, final String messageId,
final String excludes, final String includes, final String required, final Charset charset,
final String exceptionPattern, final boolean useTLSMessageFormat, final LoggerFields[] loggerFields) {
- super(charset);
+ super(config, charset);
final PatternParser exceptionParser = createPatternParser(config, ThrowablePatternConverter.class);
exceptionFormatters = exceptionPattern == null ? null : exceptionParser.parse(exceptionPattern);
this.facility = facility;
@@ -245,7 +245,7 @@ private static PatternParser createPatternParser(final Configuration config,
}
PatternParser parser = config.getComponent(COMPONENT_KEY);
if (parser == null) {
- parser = new PatternParser(config, PatternLayout.KEY, ThrowablePatternConverter.class);
+ parser = new PatternParser(config, PatternLayout.KEY, LogEventPatternConverter.class);
config.addComponent(COMPONENT_KEY, parser);
parser = config.getComponent(COMPONENT_KEY);
}
@@ -277,24 +277,28 @@ public Map getContentFormat() {
*/
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder buf = getStringBuilder();
- appendPriority(buf, event.getLevel());
- appendTimestamp(buf, event.getTimeMillis());
- appendSpace(buf);
- appendHostName(buf);
- appendSpace(buf);
- appendAppName(buf);
- appendSpace(buf);
- appendProcessId(buf);
- appendSpace(buf);
- appendMessageId(buf, event.getMessage());
- appendSpace(buf);
- appendStructuredElements(buf, event);
- appendMessage(buf, event);
- if (useTlsMessageFormat) {
- return new TlsSyslogFrame(buf.toString()).toString();
- }
- return buf.toString();
+ final StringBuilder buf = stringBuilderRecycler.acquire();
+ try {
+ appendPriority(buf, event.getLevel());
+ appendTimestamp(buf, event.getTimeMillis());
+ appendSpace(buf);
+ appendHostName(buf);
+ appendSpace(buf);
+ appendAppName(buf);
+ appendSpace(buf);
+ appendProcessId(buf);
+ appendSpace(buf);
+ appendMessageId(buf, event.getMessage());
+ appendSpace(buf);
+ appendStructuredElements(buf, event);
+ appendMessage(buf, event);
+ if (useTlsMessageFormat) {
+ return new TlsSyslogFrame(buf.toString()).toString();
+ }
+ return buf.toString();
+ } finally {
+ stringBuilderRecycler.release(buf);
+ }
}
private void appendPriority(final StringBuilder buffer, final Level logLevel) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java
index 8c58a1e5153..759943708b7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/StringBuilderEncoder.java
@@ -24,73 +24,60 @@
import java.util.Objects;
import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.spi.RecyclerFactory;
/**
- * Encoder for StringBuilders that uses ThreadLocals to avoid locking as much as possible.
+ * {@link Encoder} for {@link StringBuilder}s.
+ *
+ * {@link StringBuilderEncoder#encode(StringBuilder, ByteBufferDestination) encode()} is not thread-safe!
+ * Users are expected to recycle {@link StringBuilderEncoder} instances, e.g., using a {@link RecyclerFactory}.
+ *
*/
public class StringBuilderEncoder implements Encoder {
- /**
- * This ThreadLocal uses raw and inconvenient Object[] to store three heterogeneous objects (CharEncoder, CharBuffer
- * and ByteBuffer) instead of a custom class, because it needs to contain JDK classes, no custom (Log4j) classes.
- * Where possible putting only JDK classes in ThreadLocals is preferable to avoid memory leaks in web containers:
- * the Log4j classes may be loaded by a separate class loader which cannot be garbage collected if a thread pool
- * threadlocal still has a reference to it.
- *
- * Using just one ThreadLocal instead of three separate ones is an optimization: {@link ThreadLocal.ThreadLocalMap}
- * is polluted less, {@link ThreadLocal.ThreadLocalMap#get()} is called only once on each call to {@link #encode}
- * instead of three times.
- */
- private final ThreadLocal threadLocal = new ThreadLocal<>();
+ private final CharsetEncoder charsetEncoder;
+
+ private final CharBuffer charBuffer;
+
+ private final ByteBuffer byteBuffer;
+
private final Charset charset;
- private final int charBufferSize;
- private final int byteBufferSize;
public StringBuilderEncoder(final Charset charset) {
this(charset, Constants.ENCODER_CHAR_BUFFER_SIZE, Constants.ENCODER_BYTE_BUFFER_SIZE);
}
public StringBuilderEncoder(final Charset charset, final int charBufferSize, final int byteBufferSize) {
- this.charBufferSize = charBufferSize;
- this.byteBufferSize = byteBufferSize;
this.charset = Objects.requireNonNull(charset, "charset");
+ this.charsetEncoder = charset
+ .newEncoder()
+ .onMalformedInput(CodingErrorAction.REPLACE)
+ .onUnmappableCharacter(CodingErrorAction.REPLACE);
+ this.charBuffer = CharBuffer.allocate(charBufferSize);
+ this.byteBuffer = ByteBuffer.allocate(byteBufferSize);
}
+ /**
+ * Encodes the given source to the given destination.
+ *
+ * This method is not thread-safe!
+ * Users are expected to recycle {@link StringBuilderEncoder} instances, e.g., using a {@link RecyclerFactory}.
+ *
+ *
+ * @param source a source
+ * @param destination a destination
+ */
@Override
public void encode(final StringBuilder source, final ByteBufferDestination destination) {
try {
- final Object[] threadLocalState = getThreadLocalState();
- final CharsetEncoder charsetEncoder = (CharsetEncoder) threadLocalState[0];
- final CharBuffer charBuffer = (CharBuffer) threadLocalState[1];
- final ByteBuffer byteBuffer = (ByteBuffer) threadLocalState[2];
TextEncoderHelper.encodeText(charsetEncoder, charBuffer, byteBuffer, source, destination);
- } catch (final Exception ex) {
- logEncodeTextException(ex, source);
- TextEncoderHelper.encodeTextFallBack(charset, source, destination);
+ } catch (final Exception error) {
+ TextEncoderHelper.encodeTextFallback(charset, source, destination, error);
+ } finally {
+ charsetEncoder.reset();
+ charBuffer.clear();
+ byteBuffer.clear();
}
}
- private Object[] getThreadLocalState() {
- Object[] threadLocalState = threadLocal.get();
- if (threadLocalState == null) {
- threadLocalState = new Object[] {
- charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE),
- CharBuffer.allocate(charBufferSize),
- ByteBuffer.allocate(byteBufferSize)
- };
- threadLocal.set(threadLocalState);
- } else {
- ((CharsetEncoder) threadLocalState[0]).reset();
- ((CharBuffer) threadLocalState[1]).clear();
- ((ByteBuffer) threadLocalState[2]).clear();
- }
- return threadLocalState;
- }
-
- private static void logEncodeTextException(final Exception ex, final StringBuilder text) {
- StatusLogger.getLogger().error("Recovering from StringBuilderEncoder.encode('{}') error: {}", text, ex, ex);
- }
-
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java
index b44f793a42d..ae736e88771 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java
@@ -30,6 +30,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.net.Facility;
import org.apache.logging.log4j.core.net.Priority;
import org.apache.logging.log4j.core.util.NetUtils;
@@ -76,7 +77,7 @@ public Builder() {
@Override
public SyslogLayout build() {
- return new SyslogLayout(facility, includeNewLine, escapeNL, getCharset());
+ return new SyslogLayout(getConfiguration(), facility, includeNewLine, escapeNL, getCharset());
}
public Facility getFacility() {
@@ -133,8 +134,13 @@ public static > B newBuilder() {
*/
private final String localHostname = NetUtils.getLocalHostname();
- protected SyslogLayout(final Facility facility, final boolean includeNL, final String escapeNL, final Charset charset) {
- super(charset);
+ private SyslogLayout(
+ final Configuration configuration,
+ final Facility facility,
+ final boolean includeNL,
+ final String escapeNL,
+ final Charset charset) {
+ super(configuration, charset);
this.facility = facility;
this.includeNewLine = includeNL;
this.escapeNewLine = escapeNL == null ? null : Matcher.quoteReplacement(escapeNL);
@@ -148,26 +154,30 @@ protected SyslogLayout(final Facility facility, final boolean includeNL, final S
*/
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder buf = getStringBuilder();
-
- buf.append('<');
- buf.append(Priority.getPriority(facility, event.getLevel()));
- buf.append('>');
- addDate(event.getTimeMillis(), buf);
- buf.append(Chars.SPACE);
- buf.append(localHostname);
- buf.append(Chars.SPACE);
-
- String message = event.getMessage().getFormattedMessage();
- if (null != escapeNewLine) {
- message = NEWLINE_PATTERN.matcher(message).replaceAll(escapeNewLine);
- }
- buf.append(message);
+ final StringBuilder buf = stringBuilderRecycler.acquire();
+
+ try {
+ buf.append('<');
+ buf.append(Priority.getPriority(facility, event.getLevel()));
+ buf.append('>');
+ addDate(event.getTimeMillis(), buf);
+ buf.append(Chars.SPACE);
+ buf.append(localHostname);
+ buf.append(Chars.SPACE);
+
+ String message = event.getMessage().getFormattedMessage();
+ if (null != escapeNewLine) {
+ message = NEWLINE_PATTERN.matcher(message).replaceAll(escapeNewLine);
+ }
+ buf.append(message);
- if (includeNewLine) {
- buf.append('\n');
+ if (includeNewLine) {
+ buf.append('\n');
+ }
+ return buf.toString();
+ } finally {
+ stringBuilderRecycler.release(buf);
}
- return buf.toString();
}
private void addDate(final long timestamp, final StringBuilder buf) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
index 3785e71fc27..71a7fa7a1c9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/layout/TextEncoderHelper.java
@@ -23,6 +23,8 @@
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
+import org.apache.logging.log4j.status.StatusLogger;
+
/**
* Helper class to encode text to binary data without allocating temporary objects.
*
@@ -33,9 +35,15 @@ public class TextEncoderHelper {
private TextEncoderHelper() {
}
- static void encodeTextFallBack(final Charset charset, final StringBuilder text,
- final ByteBufferDestination destination) {
- final byte[] bytes = text.toString().getBytes(charset);
+ /* for JIT-ergonomics: */ static void encodeTextFallback(
+ final Charset charset,
+ final StringBuilder source,
+ final ByteBufferDestination destination,
+ final Exception error) {
+ StatusLogger
+ .getLogger()
+ .error("`TextEncoderHelper.encodeText()` failure, falling back to `String#getBytes(Charset)`", error);
+ final byte[] bytes = source.toString().getBytes(charset);
destination.writeBytes(bytes, 0, bytes.length);
}
@@ -79,7 +87,9 @@ private static void writeEncodedText(final CharsetEncoder charsetEncoder, final
}
result = charsetEncoder.flush(byteBuf);
if (!result.isUnderflow()) {
- destination.withLock(() -> flushRemainingBytes(charsetEncoder, destination, byteBuf));
+ synchronized (destination) {
+ flushRemainingBytes(charsetEncoder, destination, byteBuf);
+ }
return;
}
// Thread-safety note: no explicit synchronization on ByteBufferDestination below. This is safe, because
@@ -103,9 +113,12 @@ private static void writeEncodedText(final CharsetEncoder charsetEncoder, final
* @since 2.9
*/
private static void writeChunkedEncodedText(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
- final ByteBufferDestination destination, final ByteBuffer byteBuf, final CoderResult result) {
- destination.withLock(() -> flushRemainingBytes(charsetEncoder, destination,
- writeAndEncodeAsMuchAsPossible(charsetEncoder, charBuf, true, destination, byteBuf, result)));
+ final ByteBufferDestination destination, ByteBuffer byteBuf, final CoderResult result) {
+ synchronized (destination) {
+ byteBuf = writeAndEncodeAsMuchAsPossible(charsetEncoder, charBuf, true, destination, byteBuf,
+ result);
+ flushRemainingBytes(charsetEncoder, destination, byteBuf);
+ }
}
/**
@@ -117,7 +130,7 @@ private static void writeChunkedEncodedText(final CharsetEncoder charsetEncoder,
* @since 2.9
*/
private static void encodeChunkedText(final CharsetEncoder charsetEncoder, final CharBuffer charBuf,
- final ByteBuffer byteBuf, final StringBuilder text, final ByteBufferDestination destination) {
+ ByteBuffer byteBuf, final StringBuilder text, final ByteBufferDestination destination) {
// LOG4J2-1874 ByteBuffer, CharBuffer and CharsetEncoder are thread-local, so no need to synchronize while
// modifying these objects. Postpone synchronization until accessing the ByteBufferDestination.
@@ -136,27 +149,24 @@ private static void encodeChunkedText(final CharsetEncoder charsetEncoder, final
writeEncodedText(charsetEncoder, charBuf, byteBuf, destination, result);
return;
}
- final CoderResult intermediateResult = result;
- final int intermediatePosition = start;
- destination.withLock(() -> {
- var buf = writeAndEncodeAsMuchAsPossible(
- charsetEncoder, charBuf, false, destination, byteBuf, intermediateResult);
- boolean end = false;
- int position = intermediatePosition;
- while (!end) {
- CoderResult coderResult = CoderResult.UNDERFLOW;
- while (!end && coderResult.isUnderflow()) {
+ synchronized (destination) {
+ byteBuf = writeAndEncodeAsMuchAsPossible(charsetEncoder, charBuf, endOfInput, destination, byteBuf,
+ result);
+ while (!endOfInput) {
+ result = CoderResult.UNDERFLOW;
+ while (!endOfInput && result.isUnderflow()) {
charBuf.clear();
- final int copied = copy(text, position, charBuf);
- position += copied;
- end = position >= text.length();
+ final int copied = copy(text, start, charBuf);
+ start += copied;
+ endOfInput = start >= text.length();
charBuf.flip();
- coderResult = charsetEncoder.encode(charBuf, buf, end);
+ result = charsetEncoder.encode(charBuf, byteBuf, endOfInput);
}
- buf = writeAndEncodeAsMuchAsPossible(charsetEncoder, charBuf, end, destination, buf, coderResult);
+ byteBuf = writeAndEncodeAsMuchAsPossible(charsetEncoder, charBuf, endOfInput, destination, byteBuf,
+ result);
}
- flushRemainingBytes(charsetEncoder, destination, buf);
- });
+ flushRemainingBytes(charsetEncoder, destination, byteBuf);
+ }
}
/**
@@ -218,17 +228,17 @@ private static ByteBuffer drainIfByteBufferFull(final ByteBufferDestination dest
if (result.isOverflow()) { // byte buffer full
// all callers already synchronize on destination but for safety ensure we are synchronized because
// below calls to drain() may cause destination to swap in a new ByteBuffer object
- return destination.withLock(() -> {
+ synchronized (destination) {
final ByteBuffer destinationBuffer = destination.getByteBuffer();
if (destinationBuffer != temp) {
temp.flip();
- destination.unsynchronizedWrite(temp);
+ ByteBufferDestinationHelper.writeToUnsynchronized(temp, destination);
temp.clear();
return destination.getByteBuffer();
} else {
return destination.drain(destinationBuffer);
}
- });
+ }
} else {
return temp;
}
@@ -247,7 +257,7 @@ private static void flushRemainingBytes(final CharsetEncoder charsetEncoder,
}
if (temp.remaining() > 0 && temp != destination.getByteBuffer()) {
temp.flip();
- destination.unsynchronizedWrite(temp);
+ ByteBufferDestinationHelper.writeToUnsynchronized(temp, destination);
temp.clear();
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
index ca1f9fb6c59..b26b89720d8 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/TcpSocketManager.java
@@ -314,13 +314,16 @@ private void connect(final InetSocketAddress socketAddress) throws IOException {
final OutputStream newOS = sock.getOutputStream();
final InetAddress prev = socket != null ? socket.getInetAddress() : null;
final OutputStream oldOS = getOutputStream();
- owner.withLock(() -> {
+ writeLock.lock();
+ try {
Closer.closeSilently(oldOS);
setOutputStream(newOS);
socket = sock;
reconnector = null;
shutdown = true;
- });
+ } finally {
+ writeLock.unlock();
+ }
final String type = prev != null && prev.getHostAddress().equals(socketAddress.getAddress().getHostAddress()) ?
"reestablished" : "established";
LOGGER.debug("Connection to {}:{} {}: {}", host, port, type, socket);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverter.java
index 56cc1bea959..972be86cfb2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/RepeatPatternConverter.java
@@ -21,7 +21,6 @@
import org.apache.logging.log4j.plugins.Namespace;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.util.PerformanceSensitive;
-import org.apache.logging.log4j.util.Strings;
/**
* Equals pattern converter.
@@ -58,7 +57,7 @@ public static RepeatPatternConverter newInstance(final Configuration config, fin
String result = options[0];
try {
count = Integer.parseInt(options[1].trim());
- result = Strings.repeat(options[0], count);
+ result = options[0].repeat(count);
} catch (final Exception ex) {
LOGGER.error("The repeat count is not an integer: {}", options[1].trim());
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonUtils.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonUtils.java
index 9e39a941579..d3353ccbc2f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonUtils.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/JsonUtils.java
@@ -16,6 +16,8 @@
*/
package org.apache.logging.log4j.core.util;
+import org.apache.logging.log4j.spi.LoggingSystem;
+import org.apache.logging.log4j.spi.Recycler;
import org.apache.logging.log4j.util.Lazy;
/**
@@ -55,52 +57,49 @@ public final class JsonUtils {
/**
* Temporary buffer used for composing quote/escape sequences
*/
- private final static ThreadLocal _qbufLocal = new ThreadLocal<>();
-
- private static char[] getQBuf() {
- char[] _qbuf = _qbufLocal.get();
- if (_qbuf == null) {
- _qbuf = new char[6];
- _qbuf[0] = '\\';
- _qbuf[2] = '0';
- _qbuf[3] = '0';
-
- _qbufLocal.set(_qbuf);
- }
- return _qbuf;
- }
+ private final static Recycler qbufRecycler = LoggingSystem.getRecyclerFactory().create(() -> {
+ char[] qbuf = new char[6];
+ qbuf[0] = '\\';
+ qbuf[2] = '0';
+ qbuf[3] = '0';
+ return qbuf;
+ });
/**
* Quote text contents using JSON standard quoting, and append results to a supplied {@link StringBuilder}.
*/
public static void quoteAsString(final CharSequence input, final StringBuilder output) {
- final char[] qbuf = getQBuf();
- final int[] escCodes = ESC_CODES.value();
- final int escCodeCount = escCodes.length;
- int inPtr = 0;
- final int inputLen = input.length();
+ final char[] qbuf = qbufRecycler.acquire();
+ try {
+ final int[] escCodes = ESC_CODES.value();
+ final int escCodeCount = escCodes.length;
+ int inPtr = 0;
+ final int inputLen = input.length();
- outer:
- while (inPtr < inputLen) {
- tight_loop:
- while (true) {
- final char c = input.charAt(inPtr);
- if (c < escCodeCount && escCodes[c] != 0) {
- break tight_loop;
- }
- output.append(c);
- if (++inPtr >= inputLen) {
- break outer;
+ outer:
+ while (inPtr < inputLen) {
+ tight_loop:
+ while (true) {
+ final char c = input.charAt(inPtr);
+ if (c < escCodeCount && escCodes[c] != 0) {
+ break tight_loop;
+ }
+ output.append(c);
+ if (++inPtr >= inputLen) {
+ break outer;
+ }
}
- }
- // something to escape; 2 or 6-char variant?
- final char d = input.charAt(inPtr++);
- final int escCode = escCodes[d];
- final int length = (escCode < 0)
- ? _appendNumeric(d, qbuf)
- : _appendNamed(escCode, qbuf);
+ // something to escape; 2 or 6-char variant?
+ final char d = input.charAt(inPtr++);
+ final int escCode = escCodes[d];
+ final int length = (escCode < 0)
+ ? _appendNumeric(d, qbuf)
+ : _appendNamed(escCode, qbuf);
- output.append(qbuf, 0, length);
+ output.append(qbuf, 0, length);
+ }
+ } finally {
+ qbufRecycler.release(qbuf);
}
}
diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
index 0402931198a..cffc94f9a69 100644
--- a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
+++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayout.java
@@ -24,6 +24,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.plugins.Configurable;
import org.apache.logging.log4j.plugins.Plugin;
@@ -43,11 +44,11 @@
public class CsvLogEventLayout extends AbstractCsvLayout {
public static CsvLogEventLayout createDefaultLayout() {
- return new CsvLogEventLayout(null, Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
+ return new CsvLogEventLayout(new DefaultConfiguration(), Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
}
public static CsvLogEventLayout createLayout(final CSVFormat format) {
- return new CsvLogEventLayout(null, Charset.forName(DEFAULT_CHARSET), format, null, null);
+ return new CsvLogEventLayout(new DefaultConfiguration(), Charset.forName(DEFAULT_CHARSET), format, null, null);
}
@PluginFactory
@@ -77,7 +78,7 @@ protected CsvLogEventLayout(final Configuration config, final Charset charset, f
@Override
public String toSerializable(final LogEvent event) {
- final StringBuilder buffer = getStringBuilder();
+ final StringBuilder buffer = stringBuilderRecycler.acquire();
final CSVFormat format = getFormat();
try {
format.print(event.getNanoTime(), buffer, true);
@@ -99,6 +100,8 @@ public String toSerializable(final LogEvent event) {
} catch (final IOException e) {
StatusLogger.getLogger().error(event.toString(), e);
return format.getCommentMarker() + " " + e;
+ } finally {
+ stringBuilderRecycler.release(buffer);
}
}
diff --git a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
index 0bdc7aee00e..bee6e547fb5 100644
--- a/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
+++ b/log4j-csv/src/main/java/org/apache/logging/log4j/csv/layout/CsvParameterLayout.java
@@ -24,6 +24,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.plugins.Configurable;
@@ -52,11 +53,11 @@
public class CsvParameterLayout extends AbstractCsvLayout {
public static AbstractCsvLayout createDefaultLayout() {
- return new CsvParameterLayout(null, Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
+ return new CsvParameterLayout(new DefaultConfiguration(), Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
}
public static AbstractCsvLayout createLayout(final CSVFormat format) {
- return new CsvParameterLayout(null, Charset.forName(DEFAULT_CHARSET), format, null, null);
+ return new CsvParameterLayout(new DefaultConfiguration(), Charset.forName(DEFAULT_CHARSET), format, null, null);
}
@PluginFactory
@@ -88,13 +89,15 @@ public CsvParameterLayout(final Configuration config, final Charset charset, fin
public String toSerializable(final LogEvent event) {
final Message message = event.getMessage();
final Object[] parameters = message.getParameters();
- final StringBuilder buffer = getStringBuilder();
+ final StringBuilder buffer = stringBuilderRecycler.acquire();
try {
getFormat().printRecord(buffer, parameters);
return buffer.toString();
} catch (final IOException e) {
StatusLogger.getLogger().error(message, e);
return getFormat().getCommentMarker() + " " + e;
+ } finally {
+ stringBuilderRecycler.release(buffer);
}
}
diff --git a/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java
index b5c530f10c3..94d650d017e 100644
--- a/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java
+++ b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvLogEventLayoutTest.java
@@ -48,7 +48,7 @@ public class CsvLogEventLayoutTest {
@Test
public void testCustomCharset() {
- final AbstractCsvLayout layout = CsvLogEventLayout.createLayout(null, "Excel", null, null, null, null, null,
+ final AbstractCsvLayout layout = CsvLogEventLayout.createLayout(ctx.getConfiguration(), "Excel", null, null, null, null, null,
null, StandardCharsets.UTF_16, null, null);
assertEquals("text/csv; charset=UTF-16", layout.getContentType());
}
diff --git a/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java
index 415eebe5730..a29eb8c2727 100644
--- a/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java
+++ b/log4j-csv/src/test/java/org/apache/logging/log4j/csv/layout/CsvParameterLayoutTest.java
@@ -29,6 +29,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.categories.Layouts;
import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
@@ -69,7 +70,7 @@ public CsvParameterLayoutTest(final LoggerContextRule contextRule) {
@Test
public void testCustomCharset() {
- final AbstractCsvLayout layout = CsvParameterLayout.createLayout(null, "Excel", null, null, null, null, null,
+ final AbstractCsvLayout layout = CsvParameterLayout.createLayout(new DefaultConfiguration(), "Excel", null, null, null, null, null,
null, StandardCharsets.UTF_16, null, null);
assertEquals("text/csv; charset=UTF-16", layout.getContentType());
}
diff --git a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
index 05d30c9fe82..63a1bff6cd9 100644
--- a/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
+++ b/log4j-flume-ng/src/main/java/org/apache/logging/log4j/flume/appender/FlumeAppender.java
@@ -23,6 +23,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.layout.Rfc5424Layout;
import org.apache.logging.log4j.core.net.Facility;
@@ -255,6 +256,7 @@ public static FlumeAppender createAppender(
if (layout == null) {
final int enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
layout = new Rfc5424Layout.Rfc5424LayoutBuilder()
+ .setConfig(new DefaultConfiguration())
.setFacility(Facility.LOCAL0)
.setEin(String.valueOf(enterpriseNumber))
.setIncludeMDC(true)
diff --git a/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java
index 636e55629ab..d653c9e6f63 100644
--- a/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java
+++ b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java
@@ -29,6 +29,7 @@
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.test.AvailablePortFinder;
import org.apache.logging.log4j.core.test.categories.Appenders;
import org.apache.logging.log4j.smtp.MimeMessageBuilder;
@@ -115,6 +116,7 @@ public void testDelivery() {
ThreadContext.put(subjectKey, subjectValue);
final int smtpPort = AvailablePortFinder.getNextAvailable();
final SmtpAppender appender = SmtpAppender.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setName("Test")
.setTo("to@example.com")
.setCc("cc@example.com")
diff --git a/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java
index 9779480b171..65ceccc1f33 100644
--- a/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java
+++ b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java
@@ -18,6 +18,7 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.async.RingBufferLogEvent;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.MementoMessage;
import org.apache.logging.log4j.core.impl.MutableLogEvent;
@@ -45,7 +46,7 @@ void testCreateManagerName() {
}
private void testAdd(final LogEvent event) {
- final SmtpManager smtpManager = SmtpManager.getSmtpManager(null, "to", "cc", "bcc", "from", "replyTo", "subject", "protocol", "host", 0, "username", "password", false, "filterName", 10, null);
+ final SmtpManager smtpManager = SmtpManager.getSmtpManager(new DefaultConfiguration(), "to", "cc", "bcc", "from", "replyTo", "subject", "protocol", "host", 0, "username", "password", false, "filterName", 10, null);
smtpManager.removeAllBufferedEvents(); // in case this smtpManager is reused
smtpManager.add(event);
diff --git a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
index af252875fc8..06b4c230580 100644
--- a/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
+++ b/log4j-layout-jackson-json/src/test/java/org/apache/logging/log4j/jackson/json/layout/JsonLayoutTest.java
@@ -43,11 +43,7 @@
import org.apache.logging.log4j.core.util.KeyValuePair;
import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.ObjectMessage;
-import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.logging.log4j.message.ReusableMessageFactory;
-import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.message.*;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.test.junit.UsingAnyThreadContext;
import org.apache.logging.log4j.util.SortedArrayStringMap;
@@ -142,6 +138,7 @@ private String prepareJsonForObjectMessageAsJsonObjectTests(final int value, fin
.setTimeMillis(1).build();
// @formatter:off
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setCompact(true)
.setObjectMessageAsJsonObject(objectMessageAsJsonObject)
.build();
@@ -153,6 +150,7 @@ private String prepareJsonForStacktraceTests(final boolean stacktraceAsString) {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
// @formatter:off
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setCompact(true)
.setIncludeStacktrace(true)
.setStacktraceAsString(stacktraceAsString)
@@ -162,8 +160,9 @@ private String prepareJsonForStacktraceTests(final boolean stacktraceAsString) {
}
@Test
- public void testAdditionalFields() throws Exception {
+ public void testAdditionalFields() {
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setComplete(false)
@@ -182,8 +181,9 @@ public void testAdditionalFields() throws Exception {
}
@Test
- public void testMutableLogEvent() throws Exception {
+ public void testMutableLogEvent() {
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setComplete(false)
@@ -210,6 +210,7 @@ private void testAllFeatures(final boolean locationInfo, final boolean compact,
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
// @formatter:off
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(locationInfo)
.setProperties(includeContext)
.setPropertiesAsList(contextMapAslist)
@@ -353,8 +354,9 @@ public void testLocationOnCustomEndOfLine() throws Exception {
}
@Test
- public void testIncludeNullDelimiterFalse() throws Exception {
+ public void testIncludeNullDelimiterFalse() {
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setCompact(true)
.setIncludeNullDelimiter(false)
.build();
@@ -363,8 +365,9 @@ public void testIncludeNullDelimiterFalse() throws Exception {
}
@Test
- public void testIncludeNullDelimiterTrue() throws Exception {
+ public void testIncludeNullDelimiterTrue() {
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setCompact(true)
.setIncludeNullDelimiter(true)
.build();
@@ -376,7 +379,7 @@ public void testIncludeNullDelimiterTrue() throws Exception {
* Test case for MDC conversion pattern.
*/
@Test
- public void testLayout() throws Exception {
+ public void testLayout() {
final Map appenders = this.rootLogger.getAppenders();
for (final Appender appender : appenders.values()) {
this.rootLogger.removeAppender(appender);
@@ -440,6 +443,7 @@ public void testLayoutLoggerName() throws Exception {
final boolean propertiesAsList = false;
// @formatter:off
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setPropertiesAsList(propertiesAsList)
@@ -470,6 +474,7 @@ public void testLayoutLoggerName() throws Exception {
public void testLayoutMessageWithCurlyBraces() throws Exception {
final boolean propertiesAsList = false;
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setPropertiesAsList(propertiesAsList)
@@ -498,6 +503,7 @@ public void testLayoutMessageWithCurlyBraces() throws Exception {
public void testReusableLayoutMessageWithCurlyBraces() throws Exception {
final boolean propertiesAsList = false;
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setPropertiesAsList(propertiesAsList)
@@ -507,7 +513,8 @@ public void testReusableLayoutMessageWithCurlyBraces() throws Exception {
.setCharset(StandardCharsets.UTF_8)
.setIncludeStacktrace(true)
.build();
- final Message message = ReusableMessageFactory.INSTANCE.newMessage("Testing {}", new TestObj());
+ final ReusableMessageFactory factory = ReusableMessageFactory.INSTANCE;
+ final Message message = factory.newMessage("Testing {}", new TestObj());
try {
final Log4jLogEvent expected = Log4jLogEvent.newBuilder()
.setLoggerName("a.B")
@@ -524,7 +531,7 @@ public void testReusableLayoutMessageWithCurlyBraces() throws Exception {
final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class);
assertEquals(expectedMessage, actual.getMessage().getFormattedMessage());
} finally {
- ReusableMessageFactory.release(message);
+ factory.recycle(message);
}
}
@@ -533,6 +540,7 @@ public void testReusableLayoutMessageWithCurlyBraces() throws Exception {
public void testLayoutRingBufferEventReusableMessageWithCurlyBraces() throws Exception {
final boolean propertiesAsList = false;
final AbstractJacksonLayout layout = JsonLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setPropertiesAsList(propertiesAsList)
@@ -542,7 +550,8 @@ public void testLayoutRingBufferEventReusableMessageWithCurlyBraces() throws Exc
.setCharset(StandardCharsets.UTF_8)
.setIncludeStacktrace(true)
.build();
- final Message message = ReusableMessageFactory.INSTANCE.newMessage("Testing {}", new TestObj());
+ final ReusableMessageFactory factory = ReusableMessageFactory.INSTANCE;
+ final Message message = factory.newMessage("Testing {}", new TestObj());
try {
final RingBufferLogEvent ringBufferEvent = new RingBufferLogEvent();
ringBufferEvent.setValues(
@@ -555,7 +564,7 @@ null, new SortedArrayStringMap(), ThreadContext.EMPTY_STACK, 1L,
final Log4jLogEvent actual = new Log4jJsonObjectMapper(propertiesAsList, true, false, false).readValue(str, Log4jLogEvent.class);
assertEquals(expectedMessage, actual.getMessage().getFormattedMessage());
} finally {
- ReusableMessageFactory.release(message);
+ factory.recycle(message);
}
}
diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java
index 0d90e165bdb..7e37e94923a 100644
--- a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java
+++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java
@@ -26,6 +26,7 @@
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.util.KeyValuePair;
import org.apache.logging.log4j.jackson.AbstractJacksonLayout;
import org.apache.logging.log4j.jackson.XmlConstants;
@@ -107,7 +108,7 @@ public LogEvent getLogEvent() {
* @return an XML Layout.
*/
public static XmlLayout createDefaultLayout() {
- return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, false, null);
+ return new XmlLayout(new DefaultConfiguration(), false, false, false, false, StandardCharsets.UTF_8, true, false, false, false, null);
}
@PluginFactory
diff --git a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
index 061a9ee2bb3..67c984812d1 100644
--- a/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
+++ b/log4j-layout-jackson-xml/src/test/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayoutTest.java
@@ -16,14 +16,11 @@
*/
package org.apache.logging.log4j.jackson.xml.layout;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.databind.JsonMappingException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
@@ -31,6 +28,7 @@
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.MutableLogEvent;
import org.apache.logging.log4j.core.lookup.JavaLookup;
@@ -69,11 +67,11 @@ public static void cleanupClass() {
Logger rootLogger = this.ctx.getRootLogger();
- private void checkAttribute(final String name, final String value, final boolean compact, final String str) {
+ private void checkAttribute(final String name, final String value, final String str) {
assertTrue(str.contains(name + "=\"" + value + "\""), str);
}
- private void checkAttributeName(final String name, final boolean compact, final String str) {
+ private void checkAttributeName(final String name, final String str) {
assertTrue(str.contains(name + "=\""), str);
}
@@ -87,7 +85,7 @@ private void checkContains(final String expected, final List list) {
fail("Cannot find " + expected + " in " + list);
}
- private void checkContextMapElement(final String key, final String value, final boolean compact, final String str) {
+ private void checkContextMapElement(final String key, final String value, final String str) {
//
assertTrue(str.contains(String.format("", key, value)), str);
}
@@ -97,8 +95,8 @@ private void checkContextStackElement(final String value, final boolean compact,
assertTrue(str.contains(String.format("%s", value)), str);
}
- private void checkElementName(final String name, final boolean compact, final String str,
- final boolean withAttributes, final boolean withChildren) {
+ private void checkElementName(final String name, final String str,
+ final boolean withAttributes, final boolean withChildren) {
// simple checks, don't try to be too smart here, we're just looking for the names and basic shape.
// start
final String startStr = withAttributes ? "<" + name + " " : "<" + name + ">";
@@ -154,6 +152,7 @@ private String prepareXMLForStacktraceTests(final boolean stacktraceAsString) {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
// @formatter:off
final AbstractJacksonLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setCompact(true)
.setIncludeStacktrace(true)
.setStacktraceAsString(stacktraceAsString)
@@ -163,8 +162,11 @@ private String prepareXMLForStacktraceTests(final boolean stacktraceAsString) {
}
@Test
- public void testAdditionalFields() throws Exception {
- final AbstractJacksonLayout layout = XmlLayout.newBuilder().setLocationInfo(false).setProperties(false)
+ public void testAdditionalFields() {
+ final AbstractJacksonLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
+ .setLocationInfo(false)
+ .setProperties(false)
.setIncludeStacktrace(false)
.setAdditionalFields(new KeyValuePair[] { new KeyValuePair("KEY1", "VALUE1"),
new KeyValuePair("KEY2", "${java:runtime}"), })
@@ -175,8 +177,10 @@ public void testAdditionalFields() throws Exception {
}
@Test
- public void testMutableLogEvent() throws Exception {
- final AbstractJacksonLayout layout = XmlLayout.newBuilder().setLocationInfo(false).setProperties(false)
+ public void testMutableLogEvent() {
+ final AbstractJacksonLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
+ .setLocationInfo(false).setProperties(false)
.setIncludeStacktrace(false)
.setAdditionalFields(new KeyValuePair[] { new KeyValuePair("KEY1", "VALUE1"),
new KeyValuePair("KEY2", "${java:runtime}"), })
@@ -188,24 +192,14 @@ public void testMutableLogEvent() throws Exception {
final String strMutableEvent = layout.toSerializable(mutableEvent);
assertEquals(strLogEvent, strMutableEvent, strMutableEvent);
}
- /**
- * @param includeLocationInfo
- * TODO
- * @param compact
- * @param includeContextMap
- * TODO
- * @param includeContextStack
- * TODO
- * @throws IOException
- * @throws JsonParseException
- * @throws JsonMappingException
- */
+
private void testAllFeatures(final boolean includeLocationInfo, final boolean compact,
final boolean includeContextMap, final boolean includeContextStack, final boolean includeStacktrace)
- throws IOException, JsonParseException, JsonMappingException {
+ throws Exception {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
// @formatter:off
final XmlLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setLocationInfo(includeLocationInfo)
.setProperties(includeContextMap)
.setComplete(false)
@@ -223,8 +217,8 @@ private void testAllFeatures(final boolean includeLocationInfo, final boolean co
LogEventFixtures.assertEqualLogEvents(expected, actual, includeLocationInfo, includeContextMap,
includeStacktrace);
if (includeContextMap) {
- this.checkContextMapElement("MDC.A", "A_Value", compact, str);
- this.checkContextMapElement("MDC.B", "B_Value", compact, str);
+ this.checkContextMapElement("MDC.A", "A_Value", str);
+ this.checkContextMapElement("MDC.B", "B_Value", str);
}
if (includeContextStack) {
this.checkContextStackElement("stack_msg1", compact, str);
@@ -247,50 +241,50 @@ private void testAllFeatures(final boolean includeLocationInfo, final boolean co
//
// make sure the names we want are used
// this.checkAttributeName("timeMillis", compact, str);
- this.checkElementName("Instant", compact, str, true, false);
- this.checkAttributeName("epochSecond", compact, str);
- this.checkAttributeName("nanoOfSecond", compact, str);
- this.checkAttributeName("thread", compact, str); // and not threadName
- this.checkAttributeName("level", compact, str);
- this.checkAttributeName("loggerName", compact, str);
- this.checkElementName("Marker", compact, str, true, true);
- this.checkAttributeName("name", compact, str);
- this.checkElementName("Parents", compact, str, false, true);
- this.checkElementName("Message", compact, str, false, true);
- this.checkElementName("Thrown", compact, str, true, true);
- this.checkElementName("Cause", compact, str, true, includeStacktrace);
- this.checkAttributeName("commonElementCount", compact, str);
- this.checkAttributeName("message", compact, str);
- this.checkAttributeName("localizedMessage", compact, str);
+ this.checkElementName("Instant", str, true, false);
+ this.checkAttributeName("epochSecond", str);
+ this.checkAttributeName("nanoOfSecond", str);
+ this.checkAttributeName("thread", str); // and not threadName
+ this.checkAttributeName("level", str);
+ this.checkAttributeName("loggerName", str);
+ this.checkElementName("Marker", str, true, true);
+ this.checkAttributeName("name", str);
+ this.checkElementName("Parents", str, false, true);
+ this.checkElementName("Message", str, false, true);
+ this.checkElementName("Thrown", str, true, true);
+ this.checkElementName("Cause", str, true, includeStacktrace);
+ this.checkAttributeName("commonElementCount", str);
+ this.checkAttributeName("message", str);
+ this.checkAttributeName("localizedMessage", str);
if (includeStacktrace) {
- this.checkElementName("ExtendedStackTrace", compact, str, false, true);
- this.checkAttributeName("class", compact, str);
- this.checkAttributeName("method", compact, str);
- this.checkAttributeName("file", compact, str);
- this.checkAttributeName("line", compact, str);
- this.checkAttributeName("exact", compact, str);
- this.checkAttributeName("location", compact, str);
- this.checkAttributeName("version", compact, str);
+ this.checkElementName("ExtendedStackTrace", str, false, true);
+ this.checkAttributeName("class", str);
+ this.checkAttributeName("method", str);
+ this.checkAttributeName("file", str);
+ this.checkAttributeName("line", str);
+ this.checkAttributeName("exact", str);
+ this.checkAttributeName("location", str);
+ this.checkAttributeName("version", str);
} else {
this.checkElementNameAbsent("ExtendedStackTrace", compact, str);
}
- this.checkElementName("Suppressed", compact, str, false, true);
- this.checkAttributeName("loggerFqcn", compact, str);
- this.checkAttributeName("endOfBatch", compact, str);
+ this.checkElementName("Suppressed", str, false, true);
+ this.checkAttributeName("loggerFqcn", str);
+ this.checkAttributeName("endOfBatch", str);
if (includeContextMap) {
- this.checkElementName("ContextMap", compact, str, false, true);
+ this.checkElementName("ContextMap", str, false, true);
} else {
this.checkElementNameAbsent("ContextMap", compact, str);
}
- this.checkElementName("ContextStack", compact, str, false, true);
+ this.checkElementName("ContextStack", str, false, true);
if (includeLocationInfo) {
- this.checkElementName("Source", compact, str, true, false);
+ this.checkElementName("Source", str, true, false);
} else {
this.checkElementNameAbsent("Source", compact, str);
}
// check some attrs
- this.checkAttribute("loggerFqcn", "f.q.c.n", compact, str);
- this.checkAttribute("loggerName", "a.B", compact, str);
+ this.checkAttribute("loggerFqcn", "f.q.c.n", str);
+ this.checkAttribute("loggerName", "a.B", str);
this.checkJsonPropertyOrder(includeContextStack, includeContextMap, includeStacktrace, str);
}
@@ -312,16 +306,20 @@ public void testExcludeStacktrace() throws Exception {
}
@Test
- public void testIncludeNullDelimiterFalse() throws Exception {
- final AbstractJacksonLayout layout = XmlLayout.newBuilder().setCompact(true).setIncludeNullDelimiter(false)
+ public void testIncludeNullDelimiterFalse() {
+ final AbstractJacksonLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
+ .setCompact(true).setIncludeNullDelimiter(false)
.build();
final String str = layout.toSerializable(LogEventFixtures.createLogEvent());
assertFalse(str.endsWith("\0"));
}
@Test
- public void testIncludeNullDelimiterTrue() throws Exception {
- final AbstractJacksonLayout layout = XmlLayout.newBuilder().setCompact(true).setIncludeNullDelimiter(true)
+ public void testIncludeNullDelimiterTrue() {
+ final AbstractJacksonLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
+ .setCompact(true).setIncludeNullDelimiter(true)
.build();
final String str = layout.toSerializable(LogEventFixtures.createLogEvent());
assertTrue(str.endsWith("\0"));
@@ -331,13 +329,15 @@ public void testIncludeNullDelimiterTrue() throws Exception {
* Test case for MDC conversion pattern.
*/
@Test
- public void testLayout() throws Exception {
+ public void testLayout() {
final Map appenders = this.rootLogger.getAppenders();
for (final Appender appender : appenders.values()) {
this.rootLogger.removeAppender(appender);
}
// set up appender
- final XmlLayout layout = XmlLayout.newBuilder().setLocationInfo(true).setProperties(true).setComplete(true)
+ final XmlLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
+ .setLocationInfo(true).setProperties(true).setComplete(true)
.setCompact(false).setIncludeStacktrace(true).build();
final ListAppender appender = new ListAppender("List", null, layout, true, false);
@@ -388,7 +388,9 @@ public void testLayout() throws Exception {
@Test
public void testLayoutLoggerName() {
- final XmlLayout layout = XmlLayout.newBuilder().setLocationInfo(false).setProperties(true).setComplete(true)
+ final XmlLayout layout = XmlLayout.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
+ .setLocationInfo(false).setProperties(true).setComplete(true)
.setCompact(false).setIncludeStacktrace(true).build();
final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
@@ -418,13 +420,13 @@ public void testLocationOnCompactOnNdcOn() throws Exception {
}
@Test
- public void testStacktraceAsNonString() throws Exception {
+ public void testStacktraceAsNonString() {
final String str = prepareXMLForStacktraceTests(false);
assertTrue(str.contains("java.lang.NullPointerException"), str);
}
diff --git a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
index bcaa55df3bf..2fa54b4a644 100644
--- a/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
+++ b/log4j-layout-jackson-yaml/src/test/java/org/apache/logging/log4j/jackson/yaml/layout/YamlLayoutTest.java
@@ -101,6 +101,7 @@ private String prepareYAMLForStacktraceTests(final boolean stacktraceAsString) {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
// @formatter:off
final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+ .setConfiguration(ctx.getConfiguration())
.setIncludeStacktrace(true)
.setStacktraceAsString(stacktraceAsString)
.build();
@@ -149,6 +150,7 @@ private void testAllFeatures(final boolean includeSource, final boolean compact,
final boolean includeContext, final boolean contextMapAslist, final boolean includeStacktrace) throws Exception {
final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+ .setConfiguration(ctx.getConfiguration())
.setLocationInfo(includeSource)
.setProperties(includeContext)
.setIncludeStacktrace(includeStacktrace)
@@ -270,6 +272,7 @@ public void testExcludeStacktrace() throws Exception {
@Test
public void testIncludeNullDelimiterFalse() throws Exception {
final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+ .setConfiguration(ctx.getConfiguration())
.setIncludeNullDelimiter(false)
.build();
final String str = layout.toSerializable(LogEventFixtures.createLogEvent());
@@ -279,6 +282,7 @@ public void testIncludeNullDelimiterFalse() throws Exception {
@Test
public void testIncludeNullDelimiterTrue() throws Exception {
final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+ .setConfiguration(ctx.getConfiguration())
.setIncludeNullDelimiter(true)
.build();
final String str = layout.toSerializable(LogEventFixtures.createLogEvent());
@@ -338,6 +342,7 @@ public void testLayout() throws Exception {
@Test
public void testLayoutLoggerName() throws Exception {
final AbstractJacksonLayout layout = YamlLayout.newBuilder()
+ .setConfiguration(ctx.getConfiguration())
.setLocationInfo(false)
.setProperties(false)
.setIncludeStacktrace(true)
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutConcurrentEncodeTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutConcurrentEncodeTest.java
index aae0b565991..75952fc34a4 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutConcurrentEncodeTest.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutConcurrentEncodeTest.java
@@ -35,7 +35,6 @@
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
import org.apache.logging.log4j.core.layout.StringBuilderEncoder;
-import org.apache.logging.log4j.util.Strings;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.jupiter.params.ParameterizedTest;
@@ -177,7 +176,7 @@ private static Thread createWorker(
// Determine the message to be logged.
final String messageLetter = String.valueOf((char) ('A' + threadIndex));
- final String message = Strings.repeat(messageLetter, messageLength);
+ final String message = messageLetter.repeat(messageLength);
// Create the worker thread.
final String threadName = String.format("Worker-%d", threadIndex);
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java
index 156d02697ee..a7e095b9e58 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutTest.java
@@ -16,12 +16,7 @@
*/
package org.apache.logging.log4j.layout.template.json;
-import java.io.ByteArrayOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
+import java.io.*;
import java.math.BigDecimal;
import java.net.ServerSocket;
import java.net.Socket;
@@ -30,11 +25,7 @@
import java.time.Instant;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -59,24 +50,12 @@
import org.apache.logging.log4j.core.test.AvailablePortFinder;
import org.apache.logging.log4j.core.time.MutableInstant;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField;
-import org.apache.logging.log4j.layout.template.json.resolver.EventResolver;
-import org.apache.logging.log4j.layout.template.json.resolver.EventResolverContext;
-import org.apache.logging.log4j.layout.template.json.resolver.EventResolverFactory;
-import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolver;
-import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverConfig;
-import org.apache.logging.log4j.layout.template.json.resolver.TemplateResolverFactory;
+import org.apache.logging.log4j.layout.template.json.resolver.*;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.message.ObjectMessage;
-import org.apache.logging.log4j.message.ParameterizedMessageFactory;
-import org.apache.logging.log4j.message.ReusableMessageFactory;
-import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.message.StringMapMessage;
+import org.apache.logging.log4j.message.*;
import org.apache.logging.log4j.plugins.Namespace;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginFactory;
-import org.apache.logging.log4j.util.Strings;
import org.junit.jupiter.api.Test;
import static org.apache.logging.log4j.layout.template.json.TestHelpers.*;
@@ -720,7 +699,7 @@ void test_maxStringLength() {
// Create the log event.
final int maxStringLength = 30;
- final String excessiveMessageString = Strings.repeat("m", maxStringLength) + 'M';
+ final String excessiveMessageString = "m".repeat(maxStringLength) + 'M';
final SimpleMessage message = new SimpleMessage(excessiveMessageString);
final Throwable thrown = new RuntimeException();
final LogEvent logEvent = Log4jLogEvent
@@ -733,8 +712,8 @@ void test_maxStringLength() {
// Create the event template node with map values.
final String messageKey = "message";
- final String excessiveKey = Strings.repeat("k", maxStringLength) + 'K';
- final String excessiveValue = Strings.repeat("v", maxStringLength) + 'V';
+ final String excessiveKey = "k".repeat(maxStringLength) + 'K';
+ final String excessiveValue = "v".repeat(maxStringLength) + 'V';
final String nullValueKey = "nullValueKey";
final String eventTemplate = writeJson(asMap(
messageKey, asMap("$resolver", "message"),
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java
index 7486e9b5b3d..c1e0f9e90b9 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java
@@ -45,7 +45,6 @@
import org.apache.logging.log4j.core.layout.GelfLayout;
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField;
-import org.apache.logging.log4j.layout.template.json.util.ThreadLocalRecyclerFactory;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.status.StatusLogger;
import org.assertj.core.api.Assertions;
@@ -123,7 +122,6 @@ class LogstashIT {
.setConfiguration(CONFIGURATION)
.setCharset(CHARSET)
.setEventTemplateUri("classpath:EcsLayout.json")
- .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance())
.setEventTemplateAdditionalFields(
new EventTemplateAdditionalField[]{
EventTemplateAdditionalField
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java
index 64850f4f707..6c3bd7e1633 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/ThreadLocalRecyclerNestedLoggingTest.java
@@ -26,12 +26,12 @@
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.util.ThreadLocalRecycler;
+import org.apache.logging.log4j.spi.ThreadLocalRecyclerFactory;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
/**
- * Tests if logging while trying to encode an event causes {@link ThreadLocalRecycler} to incorrectly share buffers and end up overriding layout's earlier encoding work.
+ * Tests if logging while trying to encode an event causes {@link ThreadLocalRecyclerFactory.ThreadLocalRecycler} to incorrectly share buffers and end up overriding layout's earlier encoding work.
*
* @see LOG4J2-2368
*/
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
index 888b9a5e204..a76a4d33227 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
@@ -20,13 +20,7 @@
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
+import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -37,7 +31,6 @@
import org.apache.logging.log4j.util.SortedArrayStringMap;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.logging.log4j.util.StringMap;
-import org.apache.logging.log4j.util.Strings;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
@@ -89,7 +82,7 @@ void test_close() {
@Test
void test_close_after_excessive_write() {
withLockedWriter(writer -> {
- final String text = Strings.repeat("x", writer.getMaxStringLength());
+ final String text = "x".repeat(writer.getMaxStringLength());
writer.writeString(text);
writer.writeString(text);
writer.close();
@@ -472,7 +465,7 @@ void test_writeString_emitter() {
void test_writeString_emitter_excessive_string() {
withLockedWriter(writer -> {
final int maxStringLength = writer.getMaxStringLength();
- final String excessiveString = Strings.repeat("x", maxStringLength) + 'y';
+ final String excessiveString = "x".repeat(maxStringLength) + 'y';
final String expectedJson = '"' +
excessiveString.substring(0, maxStringLength) +
writer.getTruncatedStringSuffix() +
@@ -491,12 +484,12 @@ void test_writeString_emitter_excessive_string_ending_with_high_surrogate() {
final int maxStringLength = writer.getMaxStringLength();
@SuppressWarnings("StringBufferReplaceableByString")
final String excessiveString = new StringBuilder()
- .append(Strings.repeat("x", maxStringLength - 1))
+ .append("x".repeat(maxStringLength - 1))
.append(HI_SURROGATE)
.append(LO_SURROGATE)
.toString();
final String expectedJson = "\"" +
- Strings.repeat("x", maxStringLength - 1) +
+ "x".repeat(maxStringLength - 1) +
writer.getTruncatedStringSuffix() +
'"';
final BiConsumer emitter = StringBuilder::append;
@@ -526,7 +519,7 @@ void test_writeString_formattable() {
void test_writeString_formattable_excessive_string() {
withLockedWriter(writer -> {
final int maxStringLength = writer.getMaxStringLength();
- final String excessiveString = Strings.repeat("x", maxStringLength) + 'y';
+ final String excessiveString = "x".repeat(maxStringLength) + 'y';
final String expectedJson = '"' +
excessiveString.substring(0, maxStringLength) +
writer.getTruncatedStringSuffix() +
@@ -545,12 +538,12 @@ void test_writeString_formattable_excessive_string_ending_with_high_surrogate()
final int maxStringLength = writer.getMaxStringLength();
@SuppressWarnings("StringBufferReplaceableByString")
final String excessiveString = new StringBuilder()
- .append(Strings.repeat("x", maxStringLength - 1))
+ .append("x".repeat(maxStringLength - 1))
.append(HI_SURROGATE)
.append(LO_SURROGATE)
.toString();
final String expectedJson = "\"" +
- Strings.repeat("x", maxStringLength - 1) +
+ "x".repeat(maxStringLength - 1) +
writer.getTruncatedStringSuffix() +
'"';
final String actualJson = writer.use(() ->
@@ -612,9 +605,9 @@ void test_writeString_seq_negative_length() {
@Test
void test_writeString_excessive_seq() {
withLockedWriter(writer -> {
- final CharSequence seq = Strings.repeat("x", writer.getMaxStringLength()) + 'y';
+ final CharSequence seq = "x".repeat(writer.getMaxStringLength()) + 'y';
final String expectedJson = "\"" +
- Strings.repeat("x", writer.getMaxStringLength()) +
+ "x".repeat(writer.getMaxStringLength()) +
writer.getTruncatedStringSuffix() +
'"';
final String actualJson = writer.use(() -> writer.writeString(seq));
@@ -628,12 +621,12 @@ void test_writeString_excessive_seq_ending_with_high_surrogate() {
final int maxStringLength = writer.getMaxStringLength();
@SuppressWarnings("StringBufferReplaceableByString")
final CharSequence seq = new StringBuilder()
- .append(Strings.repeat("x", maxStringLength - 1))
+ .append("x".repeat(maxStringLength - 1))
.append(HI_SURROGATE)
.append(LO_SURROGATE)
.toString();
final String expectedJson = "\"" +
- Strings.repeat("x", maxStringLength - 1) +
+ "x".repeat(maxStringLength - 1) +
writer.getTruncatedStringSuffix() +
'"';
final String actualJson = writer.use(() -> writer.writeString(seq));
@@ -685,10 +678,10 @@ void test_writeString_buffer_negative_length() {
void test_writeString_excessive_buffer() {
withLockedWriter(writer -> {
final char[] buffer =
- (Strings.repeat("x", writer.getMaxStringLength()) + 'y')
+ ("x".repeat(writer.getMaxStringLength()) + 'y')
.toCharArray();
final String expectedJson = "\"" +
- Strings.repeat("x", writer.getMaxStringLength()) +
+ "x".repeat(writer.getMaxStringLength()) +
writer.getTruncatedStringSuffix() +
'"';
final String actualJson = writer.use(() -> writer.writeString(buffer));
@@ -702,13 +695,13 @@ void test_writerString_excessive_buffer_ending_with_high_surrogate() {
final int maxStringLength = writer.getMaxStringLength();
@SuppressWarnings("StringBufferReplaceableByString")
final char[] buffer = new StringBuilder()
- .append(Strings.repeat("x", maxStringLength - 1))
+ .append("x".repeat(maxStringLength - 1))
.append(HI_SURROGATE)
.append(LO_SURROGATE)
.toString()
.toCharArray();
final String expectedJson = "\"" +
- Strings.repeat("x", maxStringLength - 1) +
+ "x".repeat(maxStringLength - 1) +
writer.getTruncatedStringSuffix() +
'"';
final String actualJson = writer.use(() -> writer.writeString(buffer));
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java
deleted file mode 100644
index 606790d380d..00000000000
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactoriesTest.java
+++ /dev/null
@@ -1,139 +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.layout.template.json.util;
-
-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.ConfigurableInstanceFactory;
-import org.apache.logging.log4j.plugins.di.DI;
-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 ConfigurableInstanceFactory instanceFactory = DI.createInitializedFactory();
- // Check if the type converter is registered.
- final TypeConverter> converter = instanceFactory.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 recycler =
- queueingRecyclerFactory.create(Object::new);
- Assertions
- .assertThat(recycler)
- .isInstanceOf(QueueingRecycler.class);
- final QueueingRecycler queueingRecycler =
- (QueueingRecycler) 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 recycler =
- queueingRecyclerFactory.create(Object::new);
- Assertions
- .assertThat(recycler)
- .isInstanceOf(QueueingRecycler.class);
- final QueueingRecycler queueingRecycler =
- (QueueingRecycler) recycler;
- Assertions
- .assertThat(queueingRecycler.getQueue())
- .isInstanceOf(ArrayBlockingQueue.class);
- final ArrayBlockingQueue queue =
- (ArrayBlockingQueue) 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 QueueingRecycler> contextRecycler = (QueueingRecycler>) field.get(layout);
- final MpmcArrayQueue> queue = (MpmcArrayQueue>) contextRecycler.getQueue();
- Assertions.assertThat(queue.capacity()).isEqualTo(512);
- }
-
-}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
index 059c18da35f..4a5f448fe3a 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayout.java
@@ -16,11 +16,7 @@
*/
package org.apache.logging.log4j.layout.template.json;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
import java.nio.charset.Charset;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CodingErrorAction;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -33,16 +29,13 @@
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
import org.apache.logging.log4j.core.layout.Encoder;
-import org.apache.logging.log4j.core.layout.TextEncoderHelper;
-import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.layout.StringBuilderEncoder;
import org.apache.logging.log4j.layout.template.json.resolver.*;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.layout.template.json.util.Recycler;
-import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory;
import org.apache.logging.log4j.layout.template.json.util.Uris;
import org.apache.logging.log4j.plugins.*;
import org.apache.logging.log4j.plugins.di.Key;
-import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.spi.Recycler;
import org.apache.logging.log4j.util.Strings;
@Configurable(elementType = Layout.ELEMENT_TYPE)
@@ -93,11 +86,7 @@ private JsonTemplateLayout(final Builder builder) {
.setMaxStringLength(builder.maxStringLength)
.setTruncatedStringSuffix(builder.truncatedStringSuffix)
.build();
- this.eventResolver = createEventResolver(
- builder,
- configuration,
- charset,
- jsonWriter);
+ this.eventResolver = createEventResolver(builder, configuration, charset, jsonWriter);
this.contextRecycler = createContextRecycler(builder, jsonWriter);
}
@@ -148,7 +137,6 @@ private TemplateResolver createEventResolver(
.setSubstitutor(substitutor)
.setCharset(charset)
.setJsonWriter(jsonWriter)
- .setRecyclerFactory(builder.recyclerFactory)
.setMaxStringByteCount(maxStringByteCount)
.setTruncatedStringSuffix(builder.truncatedStringSuffix)
.setLocationInfoEnabled(builder.locationInfoEnabled)
@@ -186,14 +174,9 @@ private static String readTemplate(
: template;
}
- private static Recycler createContextRecycler(
- final Builder builder,
- final JsonWriter jsonWriter) {
- final Supplier supplier =
- createContextSupplier(builder.charset, jsonWriter);
- return builder
- .recyclerFactory
- .create(supplier, Context::close);
+ private static Recycler createContextRecycler(final Builder builder, final JsonWriter jsonWriter) {
+ final Supplier supplier = createContextSupplier(builder.charset, jsonWriter);
+ return builder.configuration.getRecyclerFactory().create(supplier, Context::close);
}
private static Supplier createContextSupplier(
@@ -206,54 +189,6 @@ private static Supplier createContextSupplier(
};
}
- /**
- * {@link org.apache.logging.log4j.core.layout.StringBuilderEncoder} clone replacing thread-local allocations with instance fields.
- */
- private static final class StringBuilderEncoder implements Encoder {
-
- private final Charset charset;
-
- private final CharsetEncoder charsetEncoder;
-
- private final CharBuffer charBuffer;
-
- private final ByteBuffer byteBuffer;
-
- private StringBuilderEncoder(final Charset charset) {
- this.charset = charset;
- this.charsetEncoder = charset
- .newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE);
- this.charBuffer = CharBuffer.allocate(Constants.ENCODER_CHAR_BUFFER_SIZE);
- this.byteBuffer = ByteBuffer.allocate(Constants.ENCODER_BYTE_BUFFER_SIZE);
- }
-
- @Override
- public void encode(
- final StringBuilder source,
- final ByteBufferDestination destination) {
- try {
- TextEncoderHelper.encodeText(charsetEncoder, charBuffer, byteBuffer, source, destination);
- } catch (final Exception error) {
- fallbackEncode(charset, source, destination, error);
- }
- }
-
- private /* for JIT-ergonomics: */ static void fallbackEncode(
- final Charset charset,
- final StringBuilder source,
- final ByteBufferDestination destination,
- final Exception error) {
- StatusLogger
- .getLogger()
- .error("TextEncoderHelper.encodeText() failure", error);
- final byte[] bytes = source.toString().getBytes(charset);
- destination.writeBytes(bytes, 0, bytes.length);
- }
-
- }
-
@Override
public byte[] toByteArray(final LogEvent event) {
final String eventJson = toSerializable(event);
@@ -395,10 +330,6 @@ public static final class Builder
private String truncatedStringSuffix =
JsonTemplateLayoutDefaults.getTruncatedStringSuffix();
- @PluginBuilderAttribute
- private RecyclerFactory recyclerFactory =
- JsonTemplateLayoutDefaults.getRecyclerFactory();
-
private Builder() {
// Do nothing.
}
@@ -533,15 +464,6 @@ public Builder setTruncatedStringSuffix(final String truncatedStringSuffix) {
return this;
}
- public RecyclerFactory getRecyclerFactory() {
- return recyclerFactory;
- }
-
- public Builder setRecyclerFactory(final RecyclerFactory recyclerFactory) {
- this.recyclerFactory = recyclerFactory;
- return this;
- }
-
@Override
public JsonTemplateLayout build() {
validate();
@@ -549,7 +471,7 @@ public JsonTemplateLayout build() {
}
private void validate() {
- Objects.requireNonNull(configuration, "config");
+ Objects.requireNonNull(configuration, "configuration");
if (Strings.isBlank(eventTemplate) && Strings.isBlank(eventTemplateUri)) {
throw new IllegalArgumentException(
"both eventTemplate and eventTemplateUri are blank");
@@ -566,7 +488,6 @@ private void validate() {
maxStringLength);
}
Objects.requireNonNull(truncatedStringSuffix, "truncatedStringSuffix");
- Objects.requireNonNull(recyclerFactory, "recyclerFactory");
}
}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java
index b8a9add7134..230da760521 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutDefaults.java
@@ -21,8 +21,6 @@
import java.util.Locale;
import java.util.TimeZone;
-import org.apache.logging.log4j.layout.template.json.util.RecyclerFactories;
-import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.PropertyEnvironment;
@@ -138,10 +136,4 @@ public static String getTruncatedStringSuffix() {
"…");
}
- public static RecyclerFactory getRecyclerFactory() {
- final String recyclerFactorySpec = PROPERTIES.getStringProperty(
- "log4j.layout.jsonTemplate.recyclerFactory");
- return RecyclerFactories.ofSpec(recyclerFactorySpec);
- }
-
}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java
index db0d25cbe15..7d51ef7b1d3 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/CounterResolver.java
@@ -24,7 +24,7 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.layout.template.json.util.Recycler;
+import org.apache.logging.log4j.spi.Recycler;
/**
* Resolves a number from an internal counter.
@@ -145,6 +145,7 @@ private static Consumer createBigIntegerResolver(final BigInteger st
private static Recycler createStringBuilderRecycler(
final EventResolverContext context) {
return context
+ .getConfiguration()
.getRecyclerFactory()
.create(
StringBuilder::new,
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java
index b0fa83509e9..b2783d65585 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/EventResolverContext.java
@@ -25,7 +25,6 @@
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory;
import org.apache.logging.log4j.util.Strings;
/**
@@ -48,8 +47,6 @@ public final class EventResolverContext implements TemplateResolverContext 0: " +
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
index 0af62b2c4f9..3d5ab759f85 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MessageParameterResolver.java
@@ -18,10 +18,10 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.layout.template.json.util.Recycler;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ParameterConsumer;
import org.apache.logging.log4j.message.ParameterVisitable;
+import org.apache.logging.log4j.spi.Recycler;
/**
* {@link Message} parameter (i.e., {@link Message#getParameters()}) resolver.
@@ -83,6 +83,7 @@ public final class MessageParameterResolver implements EventResolver {
final EventResolverContext context,
final TemplateResolverConfig config) {
this.parameterConsumerStateRecycler = context
+ .getConfiguration()
.getRecyclerFactory()
.create(ParameterConsumerState::new);
this.stringified = config.getBoolean("stringified", false);
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java
index 84ef13183f5..618f030ca90 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/ReadOnlyStringMapResolver.java
@@ -23,8 +23,8 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
-import org.apache.logging.log4j.layout.template.json.util.Recycler;
-import org.apache.logging.log4j.layout.template.json.util.RecyclerFactory;
+import org.apache.logging.log4j.spi.Recycler;
+import org.apache.logging.log4j.spi.RecyclerFactory;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.TriConsumer;
@@ -212,7 +212,7 @@ private static EventResolver createResolver(
if (key != null) {
return createKeyResolver(key, stringified, mapAccessor);
} else {
- final RecyclerFactory recyclerFactory = context.getRecyclerFactory();
+ final RecyclerFactory recyclerFactory = context.getConfiguration().getRecyclerFactory();
return createResolver(
recyclerFactory,
flatten,
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java
index 6feace011d0..c51e5232f7c 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/StackTraceStringResolver.java
@@ -23,7 +23,11 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import org.apache.logging.log4j.layout.template.json.util.*;
+import org.apache.logging.log4j.layout.template.json.util.CharSequencePointer;
+import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
+import org.apache.logging.log4j.layout.template.json.util.TruncatingBufferedPrintWriter;
+import org.apache.logging.log4j.spi.Recycler;
+import org.apache.logging.log4j.spi.RecyclerFactory;
/**
* Exception stack trace to JSON string resolver used by {@link ExceptionResolver}.
@@ -52,7 +56,7 @@ final class StackTraceStringResolver implements StackTraceResolver {
final Supplier writerSupplier =
() -> TruncatingBufferedPrintWriter.ofCapacity(
context.getMaxStringByteCount());
- final RecyclerFactory recyclerFactory = context.getRecyclerFactory();
+ final RecyclerFactory recyclerFactory = context.getConfiguration().getRecyclerFactory();
this.srcWriterRecycler =
recyclerFactory.create(
writerSupplier, TruncatingBufferedPrintWriter::close);
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java
deleted file mode 100644
index bdc73d0d0df..00000000000
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java
+++ /dev/null
@@ -1,61 +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.layout.template.json.util;
-
-import java.util.Queue;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-public class QueueingRecycler implements Recycler {
-
- private final Supplier supplier;
-
- private final Consumer cleaner;
-
- private final Queue queue;
-
- public QueueingRecycler(
- final Supplier supplier,
- final Consumer cleaner,
- final Queue queue) {
- this.supplier = supplier;
- this.cleaner = cleaner;
- this.queue = queue;
- }
-
- // Visible for tests.
- Queue getQueue() {
- return queue;
- }
-
- @Override
- public V acquire() {
- final V value = queue.poll();
- if (value == null) {
- return supplier.get();
- } else {
- cleaner.accept(value);
- return value;
- }
- }
-
- @Override
- public void release(final V value) {
- queue.offer(value);
- }
-
-}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java
deleted file mode 100644
index 99cce75cb1d..00000000000
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java
+++ /dev/null
@@ -1,40 +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.layout.template.json.util;
-
-import java.util.Queue;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-public class QueueingRecyclerFactory implements RecyclerFactory {
-
- private final Supplier> queueSupplier;
-
- public QueueingRecyclerFactory(final Supplier> queueSupplier) {
- this.queueSupplier = queueSupplier;
- }
-
- @Override
- public Recycler create(
- final Supplier supplier,
- final Consumer cleaner) {
- @SuppressWarnings("unchecked")
- final Queue queue = (Queue) queueSupplier.get();
- return new QueueingRecycler<>(supplier, cleaner, queue);
- }
-
-}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java
deleted file mode 100644
index d5041a5dce1..00000000000
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java
+++ /dev/null
@@ -1,197 +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.layout.template.json.util;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.function.Supplier;
-
-import org.apache.logging.log4j.util.LoaderUtil;
-import org.jctools.queues.MpmcArrayQueue;
-
-import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled;
-
-public final class RecyclerFactories {
-
- private RecyclerFactories() {}
-
- private static final String JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH =
- "org.jctools.queues.MpmcArrayQueue.new";
-
- private static final boolean JCTOOLS_QUEUE_CLASS_AVAILABLE =
- isJctoolsQueueClassAvailable();
-
- private static boolean isJctoolsQueueClassAvailable() {
- try {
- final String className = JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH
- .replaceAll("\\.new$", "");
- LoaderUtil.loadClass(className);
- return true;
- } catch (final ClassNotFoundException ignored) {
- return false;
- }
- }
-
- public static RecyclerFactory ofSpec(final String recyclerFactorySpec) {
-
- // Determine the default capacity.
- final int defaultCapacity = Math.max(
- 2 * Runtime.getRuntime().availableProcessors() + 1,
- 8);
-
- // TLA-, MPMC-, or ABQ-based queueing factory -- if nothing is specified.
- if (recyclerFactorySpec == null) {
- if (isThreadLocalsEnabled()) {
- return ThreadLocalRecyclerFactory.getInstance();
- } else {
- final Supplier> queueSupplier =
- JCTOOLS_QUEUE_CLASS_AVAILABLE
- ? () -> new MpmcArrayQueue<>(defaultCapacity)
- : () -> new ArrayBlockingQueue<>(defaultCapacity);
- return new QueueingRecyclerFactory(queueSupplier);
- }
- }
-
- // Is a dummy factory requested?
- else if (recyclerFactorySpec.equals("dummy")) {
- return DummyRecyclerFactory.getInstance();
- }
-
- // Is a TLA factory requested?
- else if (recyclerFactorySpec.equals("threadLocal")) {
- return ThreadLocalRecyclerFactory.getInstance();
- }
-
- // Is a queueing factory requested?
- else if (recyclerFactorySpec.startsWith("queue")) {
- return readQueueingRecyclerFactory(recyclerFactorySpec, defaultCapacity);
- }
-
- // Bogus input, bail out.
- else {
- throw new IllegalArgumentException(
- "invalid recycler factory: " + recyclerFactorySpec);
- }
-
- }
-
- private static RecyclerFactory readQueueingRecyclerFactory(
- final String recyclerFactorySpec,
- final int defaultCapacity) {
-
- // Parse the spec.
- final String queueFactorySpec = recyclerFactorySpec.substring(
- "queue".length() +
- (recyclerFactorySpec.startsWith("queue:")
- ? 1
- : 0));
- final Map parsedValues =
- StringParameterParser.parse(
- queueFactorySpec,
- new LinkedHashSet<>(Arrays.asList("supplier", "capacity")));
-
- // Read the supplier path.
- final StringParameterParser.Value supplierValue = parsedValues.get("supplier");
- final String supplierPath;
- if (supplierValue == null || supplierValue instanceof StringParameterParser.NullValue) {
- supplierPath = JCTOOLS_QUEUE_CLASS_AVAILABLE
- ? JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH
- : "java.util.concurrent.ArrayBlockingQueue.new";
- } else {
- supplierPath = supplierValue.toString();
- }
-
- // Read the capacity.
- final StringParameterParser.Value capacityValue = parsedValues.get("capacity");
- final int capacity;
- if (capacityValue == null || capacityValue instanceof StringParameterParser.NullValue) {
- capacity = defaultCapacity;
- } else {
- try {
- capacity = Integer.parseInt(capacityValue.toString());
- } catch (final NumberFormatException error) {
- throw new IllegalArgumentException(
- "failed reading capacity in queueing recycler " +
- "factory: " + queueFactorySpec, error);
- }
- }
-
- // Execute the read spec.
- return createRecyclerFactory(queueFactorySpec, supplierPath, capacity);
-
- }
-
- private static RecyclerFactory createRecyclerFactory(
- final String queueFactorySpec,
- final String supplierPath,
- final int capacity) {
- final int supplierPathSplitterIndex = supplierPath.lastIndexOf('.');
- if (supplierPathSplitterIndex < 0) {
- throw new IllegalArgumentException(
- "invalid supplier in queueing recycler factory: " +
- queueFactorySpec);
- }
- final String supplierClassName = supplierPath.substring(0, supplierPathSplitterIndex);
- final String supplierMethodName = supplierPath.substring(supplierPathSplitterIndex + 1);
- try {
- final Class> supplierClass = LoaderUtil.loadClass(supplierClassName);
- final Supplier> queueSupplier;
- if ("new".equals(supplierMethodName)) {
- final Constructor> supplierCtor =
- supplierClass.getDeclaredConstructor(int.class);
- queueSupplier = () -> {
- try {
- @SuppressWarnings("unchecked")
- final Queue typedQueue =
- (Queue) supplierCtor.newInstance(capacity);
- return typedQueue;
- } catch (final Exception error) {
- throw new RuntimeException(
- "recycler queue construction failed for factory: " +
- queueFactorySpec, error);
- }
- };
- } else {
- final Method supplierMethod =
- supplierClass.getMethod(supplierMethodName, int.class);
- queueSupplier = () -> {
- try {
- @SuppressWarnings("unchecked")
- final Queue typedQueue =
- (Queue) supplierMethod.invoke(null, capacity);
- return typedQueue;
- } catch (final Exception error) {
- throw new RuntimeException(
- "recycler queue construction failed for factory: " +
- queueFactorySpec, error);
- }
- };
- }
- return new QueueingRecyclerFactory(queueSupplier);
- } catch (final Exception error) {
- throw new RuntimeException(
- "failed executing queueing recycler factory: " +
- queueFactorySpec, error);
- }
- }
-
-}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecycler.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecycler.java
deleted file mode 100644
index 35990d499bf..00000000000
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecycler.java
+++ /dev/null
@@ -1,45 +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.layout.template.json.util;
-
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-public class ThreadLocalRecycler implements Recycler {
-
- private final Consumer cleaner;
-
- private final ThreadLocal holder;
-
- public ThreadLocalRecycler(
- final Supplier supplier,
- final Consumer cleaner) {
- this.cleaner = cleaner;
- this.holder = ThreadLocal.withInitial(supplier);
- }
-
- @Override
- public V acquire() {
- final V value = holder.get();
- cleaner.accept(value);
- return value;
- }
-
- @Override
- public void release(final V value) {}
-
-}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java
deleted file mode 100644
index b85b42c7efb..00000000000
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java
+++ /dev/null
@@ -1,40 +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.layout.template.json.util;
-
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-
-public final class ThreadLocalRecyclerFactory implements RecyclerFactory {
-
- private static final ThreadLocalRecyclerFactory INSTANCE =
- new ThreadLocalRecyclerFactory();
-
- private ThreadLocalRecyclerFactory() {}
-
- public static ThreadLocalRecyclerFactory getInstance() {
- return INSTANCE;
- }
-
- @Override
- public Recycler create(
- final Supplier supplier,
- final Consumer cleaner) {
- return new ThreadLocalRecycler<>(supplier, cleaner);
- }
-
-}
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
index 9775b8db514..23e17fcd603 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/BlackHoleByteBufferDestination.java
@@ -19,6 +19,7 @@
import java.nio.ByteBuffer;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
class BlackHoleByteBufferDestination implements ByteBufferDestination {
@@ -46,12 +47,12 @@ public ByteBuffer drain(final ByteBuffer byteBuffer) {
@Override
public void writeBytes(final ByteBuffer byteBuffer) {
- unsynchronizedWrite(byteBuffer);
+ ByteBufferDestinationHelper.writeToUnsynchronized(byteBuffer, this);
}
@Override
public void writeBytes(final byte[] buffer, final int offset, final int length) {
- unsynchronizedWrite(buffer, offset, length);
+ ByteBufferDestinationHelper.writeToUnsynchronized(buffer, offset, length, this);
}
}
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java
index 1cfb2444a53..caa21adc2c6 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkReport.java
@@ -38,7 +38,6 @@
import java.util.stream.Collectors;
import org.apache.logging.log4j.util.JsonReader;
-import org.apache.logging.log4j.util.Strings;
/**
* Utility class to summarize {@link JsonTemplateLayoutBenchmark} results in Asciidoctor.
@@ -362,7 +361,7 @@ private static void dumpJmhSummary(
.toBigInteger()
.add(BigInteger.ONE)
.intValueExact();
- final String opRateBar = Strings.repeat("▉", opRateBarLength);
+ final String opRateBar = "▉".repeat(opRateBarLength);
final int opRatePercent = normalizedOpRate
.multiply(BigDecimal.valueOf(100))
.toBigInteger()
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
index c167a95c046..f9620d8387e 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/layout/template/json/JsonTemplateLayoutBenchmarkState.java
@@ -31,7 +31,6 @@
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField;
-import org.apache.logging.log4j.layout.template.json.util.ThreadLocalRecyclerFactory;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
@@ -85,7 +84,6 @@ private static JsonTemplateLayout createJtl4JsonLayout() {
.setConfiguration(CONFIGURATION)
.setCharset(CHARSET)
.setEventTemplateUri("classpath:JsonLayout.json")
- .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance())
.build();
}
@@ -103,7 +101,6 @@ private static JsonTemplateLayout createJtl4EcsLayout() {
.setConfiguration(CONFIGURATION)
.setCharset(CHARSET)
.setEventTemplateUri("classpath:EcsLayout.json")
- .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance())
.setEventTemplateAdditionalFields(additionalFields)
.build();
}
@@ -114,7 +111,6 @@ private static JsonTemplateLayout createJtl4GelfLayout() {
.setConfiguration(CONFIGURATION)
.setCharset(CHARSET)
.setEventTemplateUri("classpath:GelfLayout.json")
- .setRecyclerFactory(ThreadLocalRecyclerFactory.getInstance())
.setEventTemplateAdditionalFields(
new EventTemplateAdditionalField[]{
// Adding "host" as a constant rather than using
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java
index 128e0ac1ba5..8e64e67ee50 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/AbstractStringLayoutStringEncodingBenchmark.java
@@ -24,9 +24,11 @@
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.StringLayout;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
import org.apache.logging.log4j.core.layout.Encoder;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.SimpleMessage;
@@ -203,7 +205,7 @@ private static long consume(final byte[] bytes, final int offset, final int limi
private static class GetBytesLayout extends AbstractStringLayout {
public GetBytesLayout(final Charset charset) {
- super(charset);
+ super(new DefaultConfiguration(), charset);
}
@Override
@@ -213,15 +215,19 @@ public String toSerializable(final LogEvent event) {
@Override
public byte[] toByteArray(final LogEvent event) {
- final StringBuilder sb = getStringBuilder();
- ((StringBuilderFormattable) event.getMessage()).formatTo(sb);
- return getBytes(sb.toString());
+ final StringBuilder sb = stringBuilderRecycler.acquire();
+ try {
+ ((StringBuilderFormattable) event.getMessage()).formatTo(sb);
+ return getBytes(sb.toString());
+ } finally {
+ stringBuilderRecycler.release(sb);
+ }
}
}
private static class EncodeLayout extends AbstractStringLayout {
public EncodeLayout(final Charset charset) {
- super(charset);
+ super(new DefaultConfiguration(), charset);
}
@Override
@@ -236,10 +242,18 @@ public byte[] toByteArray(final LogEvent event) {
@Override
public void encode(final LogEvent event, final ByteBufferDestination destination) {
- final StringBuilder sb = getStringBuilder();
- ((StringBuilderFormattable) event.getMessage()).formatTo(sb);
- final Encoder helper = getStringBuilderEncoder();
- helper.encode(sb, destination);
+ final StringBuilder sb = stringBuilderRecycler.acquire();
+ try {
+ ((StringBuilderFormattable) event.getMessage()).formatTo(sb);
+ final Encoder helper = stringBuilderEncoderRecycler.acquire();
+ try {
+ helper.encode(sb, destination);
+ } finally {
+ stringBuilderEncoderRecycler.release(helper);
+ }
+ } finally {
+ stringBuilderRecycler.release(sb);
+ }
}
}
@@ -261,12 +275,12 @@ public ByteBuffer drain(final ByteBuffer buf) {
@Override
public void writeBytes(final ByteBuffer data) {
- unsynchronizedWrite(data);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
}
@Override
public void writeBytes(final byte[] data, final int offset, final int length) {
- unsynchronizedWrite(data, offset, length);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, offset, length, this);
}
public void reset() {
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
index 74b49fd72b0..3c192a3996a 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TextEncoderHelperBenchmark.java
@@ -27,6 +27,7 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.layout.StringBuilderEncoder;
import org.apache.logging.log4j.message.Message;
@@ -95,12 +96,12 @@ public ByteBuffer drain(final ByteBuffer buf) {
@Override
public void writeBytes(final ByteBuffer data) {
- unsynchronizedWrite(data);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
}
@Override
public void writeBytes(final byte[] data, final int offset, final int length) {
- unsynchronizedWrite(data, offset, length);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, offset, length, this);
}
}
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/DemoAppender.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/DemoAppender.java
index 851bc56f4e2..6a7e6ff5a0b 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/DemoAppender.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/DemoAppender.java
@@ -23,6 +23,7 @@
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
/**
* Demo Appender that does not do any I/O.
@@ -72,11 +73,11 @@ public ByteBuffer drain(final ByteBuffer buf) {
@Override
public void writeBytes(final ByteBuffer data) {
- unsynchronizedWrite(data);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
}
@Override
public void writeBytes(final byte[] data, final int offset, final int length) {
- unsynchronizedWrite(data, offset, length);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, offset, length, this);
}
}
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/util/DemoAppender.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/util/DemoAppender.java
index 6efab887070..1e7e5850a68 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/util/DemoAppender.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/util/DemoAppender.java
@@ -23,6 +23,7 @@
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.core.layout.ByteBufferDestinationHelper;
import org.apache.logging.log4j.core.util.Constants;
/**
@@ -63,12 +64,12 @@ public ByteBuffer drain(final ByteBuffer buf) {
@Override
public void writeBytes(final ByteBuffer data) {
- unsynchronizedWrite(data);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, this);
}
@Override
public void writeBytes(final byte[] data, final int offset, final int length) {
- unsynchronizedWrite(data, offset, length);
+ ByteBufferDestinationHelper.writeToUnsynchronized(data, offset, length, this);
}
private void consume(final byte[] data, final int offset, final int length) {
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterFactory.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterFactory.java
index c8850c0b826..4afac1be145 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterFactory.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterFactory.java
@@ -27,6 +27,8 @@
import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Singleton;
import org.apache.logging.log4j.plugins.util.TypeUtil;
+import org.apache.logging.log4j.spi.RecyclerFactories;
+import org.apache.logging.log4j.spi.RecyclerFactory;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Cast;
import org.apache.logging.log4j.util.EnglishEnums;
@@ -58,6 +60,7 @@ public TypeConverterFactory(@TypeConverters final List> typeCon
registerTypeAlias(Integer.class, Integer.TYPE);
registerTypeConverter(Long.class, Long::valueOf);
registerTypeAlias(Long.class, Long.TYPE);
+ registerTypeConverter(RecyclerFactory.class, RecyclerFactories::ofSpec);
registerTypeConverter(Short.class, Short::valueOf);
registerTypeAlias(Short.class, Short.TYPE);
registerTypeConverter(String.class, s -> s);
diff --git a/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java
index 2c9d8dfcfe8..7caf33f305c 100644
--- a/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java
+++ b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpAppenderTest.java
@@ -29,6 +29,7 @@
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.test.AvailablePortFinder;
import org.apache.logging.log4j.core.test.categories.Appenders;
import org.apache.logging.log4j.smtp.MimeMessageBuilder;
@@ -115,6 +116,7 @@ public void testDelivery() {
ThreadContext.put(subjectKey, subjectValue);
final int smtpPort = AvailablePortFinder.getNextAvailable();
final SmtpAppender appender = SmtpAppender.newBuilder()
+ .setConfiguration(new DefaultConfiguration())
.setName("Test")
.setTo("to@example.com")
.setCc("cc@example.com")
diff --git a/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java
index 9779480b171..65ceccc1f33 100644
--- a/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java
+++ b/log4j-smtp/src/test/java/org/apache/logging/log4j/smtp/appender/SmtpManagerTest.java
@@ -18,6 +18,7 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.async.RingBufferLogEvent;
+import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.MementoMessage;
import org.apache.logging.log4j.core.impl.MutableLogEvent;
@@ -45,7 +46,7 @@ void testCreateManagerName() {
}
private void testAdd(final LogEvent event) {
- final SmtpManager smtpManager = SmtpManager.getSmtpManager(null, "to", "cc", "bcc", "from", "replyTo", "subject", "protocol", "host", 0, "username", "password", false, "filterName", 10, null);
+ final SmtpManager smtpManager = SmtpManager.getSmtpManager(new DefaultConfiguration(), "to", "cc", "bcc", "from", "replyTo", "subject", "protocol", "host", 0, "username", "password", false, "filterName", 10, null);
smtpManager.removeAllBufferedEvents(); // in case this smtpManager is reused
smtpManager.add(event);
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 c34c2f281f1..acf77d6c0c9 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
@@ -23,7 +23,8 @@
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.spi.AbstractLogger;
-import org.apache.logging.log4j.util.Constants;
+import org.apache.logging.log4j.spi.LoggingSystem;
+import org.apache.logging.log4j.spi.Recycler;
import org.slf4j.LoggerFactory;
import org.slf4j.MarkerFactory;
import org.slf4j.spi.LocationAwareLogger;
@@ -33,16 +34,18 @@
*/
public class SLF4JLogger extends AbstractLogger {
- private static final long serialVersionUID = 1L;
/**
* Logback supports turbo filters, that can override the logger's level.
* Therefore we can never return a no-op builder.
*/
private static final boolean LAZY_LEVEL_CHECK = "ch.qos.logback.classic.LoggerContext"
.equals(LoggerFactory.getILoggerFactory().getClass().getName());
- private static final ThreadLocal logBuilder = ThreadLocal.withInitial(SLF4JLogBuilder::new);
+
+ private static final Recycler 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) {
@@ -307,9 +310,8 @@ public LogBuilder atFatal() {
@Override
protected LogBuilder getLogBuilder(final Level level) {
- final SLF4JLogBuilder builder = logBuilder.get();
- return Constants.isThreadLocalsEnabled() && !builder.isInUse() ? builder.reset(this, level)
- : new SLF4JLogBuilder(this, level);
+ final SLF4JLogBuilder builder = LOG_BUILDER_RECYCLER.acquire();
+ return builder.reset(this, level);
}
@Override
@@ -320,4 +322,5 @@ public LogBuilder atLevel(final Level level) {
}
return super.atLevel(level);
}
+
}