You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by vy...@apache.org on 2023/03/29 13:14:17 UTC
[logging-log4j2] 08/20: Merge changes from `main`
This is an automated email from the ASF dual-hosted git repository.
vy pushed a commit to branch recycler-api-3.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit baf4a9bcb29b41422237495bcf7c1ab2db459520
Author: Volkan Yazıcı <vo...@yazi.ci>
AuthorDate: Thu Mar 23 18:14:19 2023 +0100
Merge changes from `main`
---
.../logging/log4j/message/MapMessageTest.java | 9 +
.../apache/logging/log4j/util/StringBuilders.java | 33 ++-
.../log4j/core/filter/CompositeFilterTest.java | 97 ++++---
.../pattern/SimpleLiteralPatternConverterTest.java | 93 ++++---
.../logging/log4j/core/appender/WriterManager.java | 298 ++++++++++-----------
.../appender/rolling/action/DeletingVisitor.java | 219 ++++++++-------
.../core/appender/rolling/action/PathSorter.java | 53 ++--
.../rolling/action/PathWithAttributes.java | 117 ++++----
.../appender/rolling/action/SortingVisitor.java | 149 +++++------
.../core/async/AsyncLoggerConfigDelegate.java | 131 +++++----
.../async/BasicAsyncLoggerContextSelector.java | 88 +++---
.../log4j/core/config/ReliabilityStrategy.java | 189 +++++++------
.../DefaultComponentAndConfigurationBuilder.java | 94 +++----
.../log4j/core/selector/CoreContextSelectors.java | 62 ++---
.../log4j/core/util/CloseShieldOutputStream.java | 118 ++++----
.../logging/log4j/core/util/CloseShieldWriter.java | 92 +++----
.../apache/logging/log4j/core/util/IOUtils.java | 260 +++++++++---------
.../log4j/jeromq/appender/JeroMqAppender.java | 5 +
.../log4j/jeromq/appender/JeroMqManager.java | 16 +-
.../log4j/jeromq/appender/JeroMqAppenderTest.java | 21 +-
.../log4j/layout/template/json/TestHelpers.java | 9 +-
.../template/json/resolver/MarkerResolverTest.java | 94 +++++++
.../template/json/resolver/MarkerResolver.java | 41 ++-
.../internal/util/HierarchicalCollections.java | 7 +-
log4j-to-slf4j/pom.xml | 2 +
pom.xml | 9 +-
.../.2.x.x/1232_log4j-to-sfl4j-2-OSGiMetadata.xml | 29 ++
src/changelog/.2.x.x/1366_fix_java_sql_date.xml | 28 ++
.../asciidoc/manual/json-template-layout.adoc.vm | 54 ++++
29 files changed, 1356 insertions(+), 1061 deletions(-)
diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
index 106cce2c97..b4e67f3bc2 100644
--- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
+++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
@@ -17,6 +17,7 @@
package org.apache.logging.log4j.message;
import java.math.BigDecimal;
+import java.sql.Date;
import java.sql.Time;
import java.util.Arrays;
import java.util.Collections;
@@ -320,6 +321,14 @@ public class MapMessageTest {
message.getFormattedMessage(), "Incorrect time format");
}
+ @Test
+ public void testDate() {
+ final Date date = new Date(System.currentTimeMillis());
+ final ObjectMapMessage message = new ObjectMapMessage().with("date", date);
+ assertEquals("date=\"" + date + "\"",
+ message.getFormattedMessage(), "Incorrect date format");
+ }
+
private static final class FormattableTestType implements StringBuilderFormattable {
@Override
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java
index d0c931d039..cc81a66105 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java
@@ -16,8 +16,6 @@
*/
package org.apache.logging.log4j.util;
-import java.lang.reflect.Array;
-import java.util.Collections;
import java.util.Map.Entry;
import static java.lang.Character.toLowerCase;
@@ -28,18 +26,28 @@ import static java.lang.Character.toLowerCase;
@InternalApi
public final class StringBuilders {
- private static final Object timeClass;
+ private static final Object timeObj;
+ private static final Object dateObj;
static {
+ Class<?> clazz;
Object obj;
+ final long current = System.currentTimeMillis();
try {
- Class<?> clazz = Class.forName("java.sql.Time");
- long current = System.currentTimeMillis();
+ clazz = Class.forName("java.sql.Time");
obj = clazz.getDeclaredConstructor(Long.TYPE).newInstance(current);
} catch(Exception ex) {
obj = null;
}
- timeClass = obj;
+ timeObj = obj;
+
+ try {
+ clazz = Class.forName("java.sql.Date");
+ obj = clazz.getDeclaredConstructor(Long.TYPE).newInstance(current);
+ } catch(Exception ex) {
+ obj = null;
+ }
+ dateObj = obj;
}
private StringBuilders() {
@@ -135,7 +143,7 @@ public final class StringBuilders {
stringBuilder.append(((Float) obj).floatValue());
} else if (obj instanceof Byte) {
stringBuilder.append(((Byte) obj).byteValue());
- } else if (isTime(obj) || obj instanceof java.time.temporal.Temporal) {
+ } else if (isTime(obj) || isDate(obj) || obj instanceof java.time.temporal.Temporal) {
stringBuilder.append(obj);
} else {
return false;
@@ -144,10 +152,17 @@ public final class StringBuilders {
}
/*
- Check to see if obj is an instance of java.sql.time without requiring the java.sql module.
+ Check to see if obj is an instance of java.sql.Time without requiring the java.sql module.
*/
private static boolean isTime(final Object obj) {
- return obj.getClass().isInstance(timeClass);
+ return obj.getClass().isInstance(timeObj);
+ }
+
+ /*
+ Check to see if obj is an instance of java.sql.Date without requiring the java.sql module.
+ */
+ private static boolean isDate(final Object obj) {
+ return obj.getClass().isInstance(dateObj);
}
/**
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
index 0a5698b607..14d7f16d76 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/CompositeFilterTest.java
@@ -1,49 +1,48 @@
-/* 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.filter;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-
-import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.Filter.Result;
-import org.junit.jupiter.api.Test;
-
-public class CompositeFilterTest {
-
- @Test
- public void testConcatenation() {
- final Filter a = DenyAllFilter.newBuilder().setOnMatch(Result.ACCEPT).build();
- final Filter b = DenyAllFilter.newBuilder().setOnMatch(Result.NEUTRAL).build();
- final Filter c = DenyAllFilter.newBuilder().setOnMatch(Result.DENY).build();
- // The three values need to be distinguishable
- assertNotEquals(a, b);
- assertNotEquals(a, c);
- assertNotEquals(b, c);
- final Filter[] expected = new Filter[] {a, b, c};
- final CompositeFilter singleA = CompositeFilter.createFilters(new Filter[] {a});
- final CompositeFilter singleB = CompositeFilter.createFilters(new Filter[] {b});
- final CompositeFilter singleC = CompositeFilter.createFilters(new Filter[] {c});
- // Concatenating one at a time
- final CompositeFilter concat1 = singleA.addFilter(b).addFilter(c);
- assertArrayEquals(expected, concat1.getFiltersArray());
- // In reverse order
- final CompositeFilter concat2 = singleA.addFilter(singleB.addFilter(singleC));
- assertArrayEquals(expected, concat2.getFiltersArray());
- }
-}
+/*
+ * 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.filter;
+
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Filter.Result;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+public class CompositeFilterTest {
+
+ @Test
+ public void testConcatenation() {
+ final Filter a = DenyAllFilter.newBuilder().setOnMatch(Result.ACCEPT).build();
+ final Filter b = DenyAllFilter.newBuilder().setOnMatch(Result.NEUTRAL).build();
+ final Filter c = DenyAllFilter.newBuilder().setOnMatch(Result.DENY).build();
+ // The three values need to be distinguishable
+ assertNotEquals(a, b);
+ assertNotEquals(a, c);
+ assertNotEquals(b, c);
+ final Filter[] expected = new Filter[] {a, b, c};
+ final CompositeFilter singleA = CompositeFilter.createFilters(new Filter[] {a});
+ final CompositeFilter singleB = CompositeFilter.createFilters(new Filter[] {b});
+ final CompositeFilter singleC = CompositeFilter.createFilters(new Filter[] {c});
+ // Concatenating one at a time
+ final CompositeFilter concat1 = singleA.addFilter(b).addFilter(c);
+ assertArrayEquals(expected, concat1.getFiltersArray());
+ // In reverse order
+ final CompositeFilter concat2 = singleA.addFilter(singleB.addFilter(singleC));
+ assertArrayEquals(expected, concat2.getFiltersArray());
+ }
+}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SimpleLiteralPatternConverterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SimpleLiteralPatternConverterTest.java
index ba6b402447..4b46e42b32 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SimpleLiteralPatternConverterTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/SimpleLiteralPatternConverterTest.java
@@ -1,47 +1,46 @@
-/*
- * 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.pattern;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class SimpleLiteralPatternConverterTest {
-
- @Test
- public void testConvertBackslashes() {
- String literal = "ABC\\tDEF\\nGHI\\rJKL\\'MNO\\f \\b \\\\DROPPED:\\x";
- LogEventPatternConverter converter = SimpleLiteralPatternConverter.of(literal, true);
- String actual = literal(converter);
- assertEquals("ABC\tDEF\nGHI\rJKL\'MNO\f \b \\DROPPED:x", actual);
- }
-
- @Test
- public void testDontConvertBackslashes() {
- String literal = "ABC\\tDEF\\nGHI\\rJKL\\'MNO\\f \\b \\\\DROPPED:\\x";
- LogEventPatternConverter converter = SimpleLiteralPatternConverter.of(literal, false);
- String actual = literal(converter);
- assertEquals(literal, actual);
- }
-
- private static String literal(LogEventPatternConverter converter) {
- StringBuilder buffer = new StringBuilder();
- converter.format(null, buffer);
- return buffer.toString();
- }
-}
+/*
+ * 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.pattern;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class SimpleLiteralPatternConverterTest {
+
+ @Test
+ public void testConvertBackslashes() {
+ String literal = "ABC\\tDEF\\nGHI\\rJKL\\'MNO\\f \\b \\\\DROPPED:\\x";
+ LogEventPatternConverter converter = SimpleLiteralPatternConverter.of(literal, true);
+ String actual = literal(converter);
+ assertEquals("ABC\tDEF\nGHI\rJKL\'MNO\f \b \\DROPPED:x", actual);
+ }
+
+ @Test
+ public void testDontConvertBackslashes() {
+ String literal = "ABC\\tDEF\\nGHI\\rJKL\\'MNO\\f \\b \\\\DROPPED:\\x";
+ LogEventPatternConverter converter = SimpleLiteralPatternConverter.of(literal, false);
+ String actual = literal(converter);
+ assertEquals(literal, actual);
+ }
+
+ private static String literal(LogEventPatternConverter converter) {
+ StringBuilder buffer = new StringBuilder();
+ converter.format(null, buffer);
+ return buffer.toString();
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterManager.java
index bf76e47b25..32c024fb0f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/WriterManager.java
@@ -1,149 +1,149 @@
-/*
- * 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.appender;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.logging.log4j.core.StringLayout;
-
-/**
- * Manages a Writer so that it can be shared by multiple Appenders and will
- * allow appenders to reconfigure without requiring a new writer.
- */
-public class WriterManager extends AbstractManager {
-
- /**
- * Creates a Manager.
- *
- * @param name The name of the stream to manage.
- * @param data The data to pass to the Manager.
- * @param factory The factory to use to create the Manager.
- * @param <T> The type of the WriterManager.
- * @return A WriterManager.
- */
- public static <T> WriterManager getManager(final String name, final T data,
- final ManagerFactory<? extends WriterManager, T> factory) {
- return AbstractManager.getManager(name, factory, data);
- }
- protected final StringLayout layout;
-
- private volatile Writer writer;
-
- public WriterManager(final Writer writer, final String streamName, final StringLayout layout,
- final boolean writeHeader) {
- super(null, streamName);
- this.writer = writer;
- this.layout = layout;
- if (writeHeader && layout != null) {
- final byte[] header = layout.getHeader();
- if (header != null) {
- try {
- this.writer.write(new String(header, layout.getCharset()));
- } catch (final IOException e) {
- logError("Unable to write header", e);
- }
- }
- }
- }
-
- protected synchronized void closeWriter() {
- final Writer w = writer; // access volatile field only once per method
- try {
- w.close();
- } catch (final IOException ex) {
- logError("Unable to close stream", ex);
- }
- }
-
- /**
- * Flushes any buffers.
- */
- public synchronized void flush() {
- try {
- writer.flush();
- } catch (final IOException ex) {
- final String msg = "Error flushing stream " + getName();
- throw new AppenderLoggingException(msg, ex);
- }
- }
-
- protected Writer getWriter() {
- return writer;
- }
-
- /**
- * Returns the status of the stream.
- * @return true if the stream is open, false if it is not.
- */
- public boolean isOpen() {
- return getCount() > 0;
- }
-
- /**
- * Default hook to write footer during close.
- */
- @Override
- public boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
- writeFooter();
- closeWriter();
- return true;
- }
-
- protected void setWriter(final Writer writer) {
- final byte[] header = layout.getHeader();
- if (header != null) {
- try {
- writer.write(new String(header, layout.getCharset()));
- this.writer = writer; // only update field if writer.write() succeeded
- } catch (final IOException ioe) {
- logError("Unable to write header", ioe);
- }
- } else {
- this.writer = writer;
- }
- }
-
- /**
- * Some output streams synchronize writes while others do not. Synchronizing here insures that
- * log events won't be intertwined.
- * @param str the string to write
- * @throws AppenderLoggingException if an error occurs.
- */
- protected synchronized void write(final String str) {
- try {
- writer.write(str);
- } catch (final IOException ex) {
- final String msg = "Error writing to stream " + getName();
- throw new AppenderLoggingException(msg, ex);
- }
- }
-
- /**
- * Writes the footer.
- */
- protected void writeFooter() {
- if (layout == null) {
- return;
- }
- final byte[] footer = layout.getFooter();
- if (footer != null && footer.length > 0) {
- write(new String(footer, layout.getCharset()));
- }
- }
-}
+/*
+ * 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.appender;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.core.StringLayout;
+
+/**
+ * Manages a Writer so that it can be shared by multiple Appenders and will
+ * allow appenders to reconfigure without requiring a new writer.
+ */
+public class WriterManager extends AbstractManager {
+
+ /**
+ * Creates a Manager.
+ *
+ * @param name The name of the stream to manage.
+ * @param data The data to pass to the Manager.
+ * @param factory The factory to use to create the Manager.
+ * @param <T> The type of the WriterManager.
+ * @return A WriterManager.
+ */
+ public static <T> WriterManager getManager(final String name, final T data,
+ final ManagerFactory<? extends WriterManager, T> factory) {
+ return AbstractManager.getManager(name, factory, data);
+ }
+ protected final StringLayout layout;
+
+ private volatile Writer writer;
+
+ public WriterManager(final Writer writer, final String streamName, final StringLayout layout,
+ final boolean writeHeader) {
+ super(null, streamName);
+ this.writer = writer;
+ this.layout = layout;
+ if (writeHeader && layout != null) {
+ final byte[] header = layout.getHeader();
+ if (header != null) {
+ try {
+ this.writer.write(new String(header, layout.getCharset()));
+ } catch (final IOException e) {
+ logError("Unable to write header", e);
+ }
+ }
+ }
+ }
+
+ protected synchronized void closeWriter() {
+ final Writer w = writer; // access volatile field only once per method
+ try {
+ w.close();
+ } catch (final IOException ex) {
+ logError("Unable to close stream", ex);
+ }
+ }
+
+ /**
+ * Flushes any buffers.
+ */
+ public synchronized void flush() {
+ try {
+ writer.flush();
+ } catch (final IOException ex) {
+ final String msg = "Error flushing stream " + getName();
+ throw new AppenderLoggingException(msg, ex);
+ }
+ }
+
+ protected Writer getWriter() {
+ return writer;
+ }
+
+ /**
+ * Returns the status of the stream.
+ * @return true if the stream is open, false if it is not.
+ */
+ public boolean isOpen() {
+ return getCount() > 0;
+ }
+
+ /**
+ * Default hook to write footer during close.
+ */
+ @Override
+ public boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
+ writeFooter();
+ closeWriter();
+ return true;
+ }
+
+ protected void setWriter(final Writer writer) {
+ final byte[] header = layout.getHeader();
+ if (header != null) {
+ try {
+ writer.write(new String(header, layout.getCharset()));
+ this.writer = writer; // only update field if writer.write() succeeded
+ } catch (final IOException ioe) {
+ logError("Unable to write header", ioe);
+ }
+ } else {
+ this.writer = writer;
+ }
+ }
+
+ /**
+ * Some output streams synchronize writes while others do not. Synchronizing here insures that
+ * log events won't be intertwined.
+ * @param str the string to write
+ * @throws AppenderLoggingException if an error occurs.
+ */
+ protected synchronized void write(final String str) {
+ try {
+ writer.write(str);
+ } catch (final IOException ex) {
+ final String msg = "Error writing to stream " + getName();
+ throw new AppenderLoggingException(msg, ex);
+ }
+ }
+
+ /**
+ * Writes the footer.
+ */
+ protected void writeFooter() {
+ if (layout == null) {
+ return;
+ }
+ final byte[] footer = layout.getFooter();
+ if (footer != null && footer.length > 0) {
+ write(new String(footer, layout.getCharset()));
+ }
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java
index 69a59a7d8c..e433731cf2 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java
@@ -1,110 +1,109 @@
-/*
- * 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.appender.rolling.action;
-
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.List;
-import java.util.Objects;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
-
-/**
- * FileVisitor that deletes files that are accepted by all PathFilters. Directories are ignored.
- */
-public class DeletingVisitor extends SimpleFileVisitor<Path> {
- private static final Logger LOGGER = StatusLogger.getLogger();
-
- private final Path basePath;
- private final boolean testMode;
- private final List<? extends PathCondition> pathConditions;
-
- /**
- * Constructs a new DeletingVisitor.
- *
- * @param basePath used to relativize paths
- * @param pathConditions objects that need to confirm whether a file can be deleted
- * @param testMode if true, files are not deleted but instead a message is printed to the <a
- * href="http://logging.apache.org/log4j/2.x/manual/configuration.html#StatusMessages">status logger</a>
- * at INFO level. Users can use this to do a dry run to test if their configuration works as expected.
- */
- public DeletingVisitor(final Path basePath, final List<? extends PathCondition> pathConditions,
- final boolean testMode) {
- this.testMode = testMode;
- this.basePath = Objects.requireNonNull(basePath, "basePath");
- this.pathConditions = Objects.requireNonNull(pathConditions, "pathConditions");
- for (final PathCondition condition : pathConditions) {
- condition.beforeFileTreeWalk();
- }
- }
-
- @Override
- public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
- for (final PathCondition pathFilter : pathConditions) {
- final Path relative = basePath.relativize(file);
- if (!pathFilter.accept(basePath, relative, attrs)) {
- LOGGER.trace("Not deleting base={}, relative={}", basePath, relative);
- return FileVisitResult.CONTINUE;
- }
- }
- if (isTestMode()) {
- LOGGER.info("Deleting {} (TEST MODE: file not actually deleted)", file);
- } else {
- delete(file);
- }
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(final Path file, final IOException ioException) throws IOException {
- // LOG4J2-2677: Appenders may rollover and purge in parallel. SimpleVisitor rethrows exceptions from
- // failed attempts to load file attributes.
- if (ioException instanceof NoSuchFileException) {
- LOGGER.info("File {} could not be accessed, it has likely already been deleted", file, ioException);
- return FileVisitResult.CONTINUE;
- } else {
- return super.visitFileFailed(file, ioException);
- }
- }
-
- /**
- * Deletes the specified file.
- *
- * @param file the file to delete
- * @throws IOException if a problem occurred deleting the file
- */
- protected void delete(final Path file) throws IOException {
- LOGGER.trace("Deleting {}", file);
- Files.deleteIfExists(file);
- }
-
- /**
- * Returns {@code true} if files are not deleted even when all conditions accept a path, {@code false} otherwise.
- *
- * @return {@code true} if files are not deleted even when all conditions accept a path, {@code false} otherwise
- */
- public boolean isTestMode() {
- return testMode;
- }
-}
+/*
+ * 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.appender.rolling.action;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * FileVisitor that deletes files that are accepted by all PathFilters. Directories are ignored.
+ */
+public class DeletingVisitor extends SimpleFileVisitor<Path> {
+ private static final Logger LOGGER = StatusLogger.getLogger();
+
+ private final Path basePath;
+ private final boolean testMode;
+ private final List<? extends PathCondition> pathConditions;
+
+ /**
+ * Constructs a new DeletingVisitor.
+ *
+ * @param basePath used to relativize paths
+ * @param pathConditions objects that need to confirm whether a file can be deleted
+ * @param testMode if true, files are not deleted but instead a message is printed to the <a
+ * href="http://logging.apache.org/log4j/2.x/manual/configuration.html#StatusMessages">status logger</a>
+ * at INFO level. Users can use this to do a dry run to test if their configuration works as expected.
+ */
+ public DeletingVisitor(final Path basePath, final List<? extends PathCondition> pathConditions,
+ final boolean testMode) {
+ this.testMode = testMode;
+ this.basePath = Objects.requireNonNull(basePath, "basePath");
+ this.pathConditions = Objects.requireNonNull(pathConditions, "pathConditions");
+ for (final PathCondition condition : pathConditions) {
+ condition.beforeFileTreeWalk();
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
+ for (final PathCondition pathFilter : pathConditions) {
+ final Path relative = basePath.relativize(file);
+ if (!pathFilter.accept(basePath, relative, attrs)) {
+ LOGGER.trace("Not deleting base={}, relative={}", basePath, relative);
+ return FileVisitResult.CONTINUE;
+ }
+ }
+ if (isTestMode()) {
+ LOGGER.info("Deleting {} (TEST MODE: file not actually deleted)", file);
+ } else {
+ delete(file);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(final Path file, final IOException ioException) throws IOException {
+ // LOG4J2-2677: Appenders may rollover and purge in parallel. SimpleVisitor rethrows exceptions from
+ // failed attempts to load file attributes.
+ if (ioException instanceof NoSuchFileException) {
+ LOGGER.info("File {} could not be accessed, it has likely already been deleted", file, ioException);
+ return FileVisitResult.CONTINUE;
+ } else {
+ return super.visitFileFailed(file, ioException);
+ }
+ }
+
+ /**
+ * Deletes the specified file.
+ *
+ * @param file the file to delete
+ * @throws IOException if a problem occurred deleting the file
+ */
+ protected void delete(final Path file) throws IOException {
+ LOGGER.trace("Deleting {}", file);
+ Files.deleteIfExists(file);
+ }
+
+ /**
+ * Returns {@code true} if files are not deleted even when all conditions accept a path, {@code false} otherwise.
+ *
+ * @return {@code true} if files are not deleted even when all conditions accept a path, {@code false} otherwise
+ */
+ public boolean isTestMode() {
+ return testMode;
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSorter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSorter.java
index 2e765ab0b8..d8ea3c2d22 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSorter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathSorter.java
@@ -1,27 +1,26 @@
-/*
- * 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.appender.rolling.action;
-
-import java.util.Comparator;
-
-/**
- * Defines the interface of classes that can sort Paths.
- */
-public interface PathSorter extends Comparator<PathWithAttributes>{
-
-}
+/*
+ * 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.appender.rolling.action;
+
+import java.util.Comparator;
+
+/**
+ * Defines the interface of classes that can sort Paths.
+ */
+public interface PathSorter extends Comparator<PathWithAttributes>{
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathWithAttributes.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathWithAttributes.java
index d69835427b..674e784269 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathWithAttributes.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathWithAttributes.java
@@ -1,59 +1,58 @@
-/*
- * 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.appender.rolling.action;
-
-import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Objects;
-
-/**
- * Tuple of a {@code Path} and {@code BasicFileAttributes}, used for sorting.
- */
-public class PathWithAttributes {
-
- private final Path path;
- private final BasicFileAttributes attributes;
-
- public PathWithAttributes(final Path path, final BasicFileAttributes attributes) {
- this.path = Objects.requireNonNull(path, "path");
- this.attributes = Objects.requireNonNull(attributes, "attributes");
- }
-
- @Override
- public String toString() {
- return path + " (modified: " + attributes.lastModifiedTime() + ")";
- }
-
- /**
- * Returns the path.
- *
- * @return the path
- */
- public Path getPath() {
- return path;
- }
-
- /**
- * Returns the attributes.
- *
- * @return the attributes
- */
- public BasicFileAttributes getAttributes() {
- return attributes;
- }
-}
+/*
+ * 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.appender.rolling.action;
+
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Objects;
+
+/**
+ * Tuple of a {@code Path} and {@code BasicFileAttributes}, used for sorting.
+ */
+public class PathWithAttributes {
+
+ private final Path path;
+ private final BasicFileAttributes attributes;
+
+ public PathWithAttributes(final Path path, final BasicFileAttributes attributes) {
+ this.path = Objects.requireNonNull(path, "path");
+ this.attributes = Objects.requireNonNull(attributes, "attributes");
+ }
+
+ @Override
+ public String toString() {
+ return path + " (modified: " + attributes.lastModifiedTime() + ")";
+ }
+
+ /**
+ * Returns the path.
+ *
+ * @return the path
+ */
+ public Path getPath() {
+ return path;
+ }
+
+ /**
+ * Returns the attributes.
+ *
+ * @return the attributes
+ */
+ public BasicFileAttributes getAttributes() {
+ return attributes;
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/SortingVisitor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/SortingVisitor.java
index ba7e00b601..c7ba94ec61 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/SortingVisitor.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/SortingVisitor.java
@@ -1,75 +1,74 @@
-/*
- * 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.appender.rolling.action;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
-
-import java.io.IOException;
-import java.nio.file.FileVisitResult;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * FileVisitor that sorts files.
- */
-public class SortingVisitor extends SimpleFileVisitor<Path> {
-
- private static final Logger LOGGER = StatusLogger.getLogger();
- private final PathSorter sorter;
- private final List<PathWithAttributes> collected = new ArrayList<>();
-
- /**
- * Constructs a new DeletingVisitor.
- *
- * @param basePath used to relativize paths
- * @param pathFilters objects that need to confirm whether a file can be deleted
- */
- public SortingVisitor(final PathSorter sorter) {
- this.sorter = Objects.requireNonNull(sorter, "sorter");
- }
-
- @Override
- public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs) throws IOException {
- collected.add(new PathWithAttributes(path, attrs));
- return FileVisitResult.CONTINUE;
- }
-
- @Override
- public FileVisitResult visitFileFailed(final Path file, final IOException ioException) throws IOException {
- // LOG4J2-2677: Appenders may rollover and purge in parallel. SimpleVisitor rethrows exceptions from
- // failed attempts to load file attributes.
- if (ioException instanceof NoSuchFileException) {
- LOGGER.info("File {} could not be accessed, it has likely already been deleted", file, ioException);
- return FileVisitResult.CONTINUE;
- } else {
- return super.visitFileFailed(file, ioException);
- }
- }
-
- public List<PathWithAttributes> getSortedPaths() {
- Collections.sort(collected, sorter);
- return collected;
- }
-}
+/*
+ * 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.appender.rolling.action;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * FileVisitor that sorts files.
+ */
+public class SortingVisitor extends SimpleFileVisitor<Path> {
+
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private final PathSorter sorter;
+ private final List<PathWithAttributes> collected = new ArrayList<>();
+
+ /**
+ * Constructs a new DeletingVisitor.
+ *
+ * @param basePath used to relativize paths
+ * @param pathFilters objects that need to confirm whether a file can be deleted
+ */
+ public SortingVisitor(final PathSorter sorter) {
+ this.sorter = Objects.requireNonNull(sorter, "sorter");
+ }
+
+ @Override
+ public FileVisitResult visitFile(final Path path, final BasicFileAttributes attrs) throws IOException {
+ collected.add(new PathWithAttributes(path, attrs));
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(final Path file, final IOException ioException) throws IOException {
+ // LOG4J2-2677: Appenders may rollover and purge in parallel. SimpleVisitor rethrows exceptions from
+ // failed attempts to load file attributes.
+ if (ioException instanceof NoSuchFileException) {
+ LOGGER.info("File {} could not be accessed, it has likely already been deleted", file, ioException);
+ return FileVisitResult.CONTINUE;
+ } else {
+ return super.visitFileFailed(file, ioException);
+ }
+ }
+
+ public List<PathWithAttributes> getSortedPaths() {
+ Collections.sort(collected, sorter);
+ return collected;
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java
index b791f0afe4..1cf0c8e66f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDelegate.java
@@ -1,66 +1,65 @@
-/*
- * 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.async;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.impl.LogEventFactory;
-import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
-
-/**
- * Encapsulates the mechanism used to log asynchronously. There is one delegate per configuration, which is shared by
- * all AsyncLoggerConfig objects in the configuration.
- */
-public interface AsyncLoggerConfigDelegate {
-
- /**
- * Creates and returns a new {@code RingBufferAdmin} that instruments the ringbuffer of this
- * {@code AsyncLoggerConfig}.
- *
- * @param contextName name of the {@code LoggerContext}
- * @param loggerConfigName name of the logger config
- * @return the RingBufferAdmin that instruments the ringbuffer
- */
- RingBufferAdmin createRingBufferAdmin(final String contextName, final String loggerConfigName);
-
- /**
- * Returns the {@code EventRoute} for the event with the specified level.
- *
- * @param level the level of the event to log
- * @return the {@code EventRoute}
- */
- EventRoute getEventRoute(final Level level);
-
- /**
- * Enqueues the {@link LogEvent} on the mixed configuration ringbuffer.
- * This method must only be used after {@link #tryEnqueue(LogEvent, AsyncLoggerConfig)} returns <code>false</code>
- * indicating that the ringbuffer is full, otherwise it may incur unnecessary synchronization.
- */
- void enqueueEvent(LogEvent event, AsyncLoggerConfig asyncLoggerConfig);
-
- boolean tryEnqueue(LogEvent event, AsyncLoggerConfig asyncLoggerConfig);
-
- /**
- * Notifies the delegate what LogEventFactory an AsyncLoggerConfig is using, so the delegate can determine
- * whether to populate the ring buffer with mutable log events or not. This method may be invoked multiple times
- * for all AsyncLoggerConfigs that use this delegate.
- *
- * @param logEventFactory the factory used
- */
- void setLogEventFactory(LogEventFactory logEventFactory);
-}
+/*
+ * 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.async;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.LogEventFactory;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
+
+/**
+ * Encapsulates the mechanism used to log asynchronously. There is one delegate per configuration, which is shared by
+ * all AsyncLoggerConfig objects in the configuration.
+ */
+public interface AsyncLoggerConfigDelegate {
+
+ /**
+ * Creates and returns a new {@code RingBufferAdmin} that instruments the ringbuffer of this
+ * {@code AsyncLoggerConfig}.
+ *
+ * @param contextName name of the {@code LoggerContext}
+ * @param loggerConfigName name of the logger config
+ * @return the RingBufferAdmin that instruments the ringbuffer
+ */
+ RingBufferAdmin createRingBufferAdmin(final String contextName, final String loggerConfigName);
+
+ /**
+ * Returns the {@code EventRoute} for the event with the specified level.
+ *
+ * @param level the level of the event to log
+ * @return the {@code EventRoute}
+ */
+ EventRoute getEventRoute(final Level level);
+
+ /**
+ * Enqueues the {@link LogEvent} on the mixed configuration ringbuffer.
+ * This method must only be used after {@link #tryEnqueue(LogEvent, AsyncLoggerConfig)} returns <code>false</code>
+ * indicating that the ringbuffer is full, otherwise it may incur unnecessary synchronization.
+ */
+ void enqueueEvent(LogEvent event, AsyncLoggerConfig asyncLoggerConfig);
+
+ boolean tryEnqueue(LogEvent event, AsyncLoggerConfig asyncLoggerConfig);
+
+ /**
+ * Notifies the delegate what LogEventFactory an AsyncLoggerConfig is using, so the delegate can determine
+ * whether to populate the ring buffer with mutable log events or not. This method may be invoked multiple times
+ * for all AsyncLoggerConfigs that use this delegate.
+ *
+ * @param logEventFactory the factory used
+ */
+ void setLogEventFactory(LogEventFactory logEventFactory);
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java
index 9658f0302f..70f90ca3b6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.java
@@ -1,44 +1,44 @@
-/*
- * 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.async;
-
-import java.net.URI;
-
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.selector.BasicContextSelector;
-import org.apache.logging.log4j.plugins.Inject;
-import org.apache.logging.log4j.plugins.Singleton;
-import org.apache.logging.log4j.plugins.di.Injector;
-
-/**
- * Returns either this Thread's context or the default {@link AsyncLoggerContext}.
- * Single-application instances should prefer this implementation over the {@link AsyncLoggerContextSelector}
- * due to the reduced overhead avoiding classloader lookups.
- */
-@Singleton
-public class BasicAsyncLoggerContextSelector extends BasicContextSelector {
-
- @Inject
- public BasicAsyncLoggerContextSelector(Injector injector) {
- super(injector);
- }
-
- @Override
- protected LoggerContext createContext() {
- return new AsyncLoggerContext("AsyncDefault", null, (URI) null, injector);
- }
-}
+/*
+ * 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.async;
+
+import java.net.URI;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.selector.BasicContextSelector;
+import org.apache.logging.log4j.plugins.Inject;
+import org.apache.logging.log4j.plugins.Singleton;
+import org.apache.logging.log4j.plugins.di.Injector;
+
+/**
+ * Returns either this Thread's context or the default {@link AsyncLoggerContext}.
+ * Single-application instances should prefer this implementation over the {@link AsyncLoggerContextSelector}
+ * due to the reduced overhead avoiding classloader lookups.
+ */
+@Singleton
+public class BasicAsyncLoggerContextSelector extends BasicContextSelector {
+
+ @Inject
+ public BasicAsyncLoggerContextSelector(Injector injector) {
+ super(injector);
+ }
+
+ @Override
+ protected LoggerContext createContext() {
+ return new AsyncLoggerContext("AsyncDefault", null, (URI) null, injector);
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java
index 1ccb74a6b1..b469a73b1d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ReliabilityStrategy.java
@@ -1,95 +1,94 @@
-/*
- * 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.config;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.util.Supplier;
-
-/**
- * Interface for objects that know how to ensure delivery of log events to the appropriate appenders, even during and
- * after the configuration has been modified while the system is actively used.
- */
-public interface ReliabilityStrategy {
-
- /**
- * Logs an event.
- *
- * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
- * @param loggerName The name of the Logger.
- * @param fqcn The fully qualified class name of the caller.
- * @param marker A Marker or null if none is present.
- * @param level The event Level.
- * @param data The Message.
- * @param t A Throwable or null.
- */
- void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, Marker marker, Level level,
- Message data, Throwable t);
- /**
- * Logs an event.
- *
- * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
- * @param loggerName The name of the Logger.
- * @param fqcn The fully qualified class name of the caller.
- * @param location The location of the caller or null.
- * @param marker A Marker or null if none is present.
- * @param level The event Level.
- * @param data The Message.
- * @param t A Throwable or null.
- * @since 3.0
- */
- default void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn, final StackTraceElement location,
- final Marker marker, final Level level, final Message data, final Throwable t) {
- }
-
- /**
- * Logs an event.
- *
- * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
- * @param event The log event.
- */
- void log(Supplier<LoggerConfig> reconfigured, LogEvent event);
-
- /**
- * For internal use by the ReliabilityStrategy; returns the LoggerConfig to use.
- *
- * @param next supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
- * @return the currently active LoggerConfig
- */
- LoggerConfig getActiveLoggerConfig(Supplier<LoggerConfig> next);
-
- /**
- * Called after a log event was logged.
- */
- void afterLogEvent();
-
- /**
- * Called before all appenders are stopped.
- */
- void beforeStopAppenders();
-
- /**
- * Called before the configuration is stopped.
- *
- * @param configuration the configuration that will be stopped
- */
- void beforeStopConfiguration(Configuration configuration);
-
-}
+/*
+ * 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.config;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.util.Supplier;
+
+/**
+ * Interface for objects that know how to ensure delivery of log events to the appropriate appenders, even during and
+ * after the configuration has been modified while the system is actively used.
+ */
+public interface ReliabilityStrategy {
+
+ /**
+ * Logs an event.
+ *
+ * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
+ * @param loggerName The name of the Logger.
+ * @param fqcn The fully qualified class name of the caller.
+ * @param marker A Marker or null if none is present.
+ * @param level The event Level.
+ * @param data The Message.
+ * @param t A Throwable or null.
+ */
+ void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, Marker marker, Level level,
+ Message data, Throwable t);
+ /**
+ * Logs an event.
+ *
+ * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
+ * @param loggerName The name of the Logger.
+ * @param fqcn The fully qualified class name of the caller.
+ * @param location The location of the caller or null.
+ * @param marker A Marker or null if none is present.
+ * @param level The event Level.
+ * @param data The Message.
+ * @param t A Throwable or null.
+ * @since 3.0
+ */
+ default void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn, final StackTraceElement location,
+ final Marker marker, final Level level, final Message data, final Throwable t) {
+ }
+
+ /**
+ * Logs an event.
+ *
+ * @param reconfigured supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
+ * @param event The log event.
+ */
+ void log(Supplier<LoggerConfig> reconfigured, LogEvent event);
+
+ /**
+ * For internal use by the ReliabilityStrategy; returns the LoggerConfig to use.
+ *
+ * @param next supplies the next LoggerConfig if the strategy's LoggerConfig is no longer active
+ * @return the currently active LoggerConfig
+ */
+ LoggerConfig getActiveLoggerConfig(Supplier<LoggerConfig> next);
+
+ /**
+ * Called after a log event was logged.
+ */
+ void afterLogEvent();
+
+ /**
+ * Called before all appenders are stopped.
+ */
+ void beforeStopAppenders();
+
+ /**
+ * Called before the configuration is stopped.
+ *
+ * @param configuration the configuration that will be stopped
+ */
+ void beforeStopConfiguration(Configuration configuration);
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentAndConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentAndConfigurationBuilder.java
index f6e7e1e6bb..2ca603dabe 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentAndConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultComponentAndConfigurationBuilder.java
@@ -1,47 +1,47 @@
-/*
- * 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.config.builder.impl;
-
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
-
-/**
- * Extends {@code DefaultComponentBuilder} to specify
- * {@code DefaultConfigurationBuilder<? extends Configuration>} as the
- * {@code ConfigurationBuilder} type.
- *
- * @since 2.4
- */
-class DefaultComponentAndConfigurationBuilder<T extends ComponentBuilder<T>>
- extends DefaultComponentBuilder<T, DefaultConfigurationBuilder<? extends Configuration>> {
-
- DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
- final String type, final String value) {
- super(builder, name, type, value);
- }
-
- DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
- final String type) {
- super(builder, name, type);
- }
-
- public DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
- final String type) {
- super(builder, type);
- }
-
-}
+/*
+ * 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.config.builder.impl;
+
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
+
+/**
+ * Extends {@code DefaultComponentBuilder} to specify
+ * {@code DefaultConfigurationBuilder<? extends Configuration>} as the
+ * {@code ConfigurationBuilder} type.
+ *
+ * @since 2.4
+ */
+class DefaultComponentAndConfigurationBuilder<T extends ComponentBuilder<T>>
+ extends DefaultComponentBuilder<T, DefaultConfigurationBuilder<? extends Configuration>> {
+
+ DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
+ final String type, final String value) {
+ super(builder, name, type, value);
+ }
+
+ DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
+ final String type) {
+ super(builder, name, type);
+ }
+
+ public DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
+ final String type) {
+ super(builder, type);
+ }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java
index 2ee6b0d4f6..1588d2999d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/selector/CoreContextSelectors.java
@@ -1,31 +1,31 @@
-/*
- * 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.selector;
-
-import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
-import org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector;
-
-public class CoreContextSelectors {
-
- public static final Class<?>[] CLASSES = new Class<?>[] {
- ClassLoaderContextSelector.class,
- BasicContextSelector.class,
- AsyncLoggerContextSelector.class,
- BasicAsyncLoggerContextSelector.class
- };
-
-}
+/*
+ * 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.selector;
+
+import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
+import org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector;
+
+public class CoreContextSelectors {
+
+ public static final Class<?>[] CLASSES = new Class<?>[] {
+ ClassLoaderContextSelector.class,
+ BasicContextSelector.class,
+ AsyncLoggerContextSelector.class,
+ BasicAsyncLoggerContextSelector.class
+ };
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldOutputStream.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldOutputStream.java
index 1139bd20f9..946e0c29b4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldOutputStream.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldOutputStream.java
@@ -1,60 +1,60 @@
-/*
- * 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.util;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A delegating OutputStream that does not close its delegate.
- */
-public class CloseShieldOutputStream extends OutputStream {
-
- private final OutputStream delegate;
-
- public CloseShieldOutputStream(final OutputStream delegate) {
- this.delegate = delegate;
- }
-
- /**
- * Does nothing.
- */
- @Override
- public void close() {
- // do not close delegate
- }
-
- @Override
- public void flush() throws IOException {
- delegate.flush();
- }
-
- @Override
- public void write(final byte[] b) throws IOException {
- delegate.write(b);
- }
-
- @Override
- public void write(final byte[] b, final int off, final int len) throws IOException {
- delegate.write(b, off, len);
- }
-
- @Override
- public void write(final int b) throws IOException {
- delegate.write(b);
- }
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A delegating OutputStream that does not close its delegate.
+ */
+public class CloseShieldOutputStream extends OutputStream {
+
+ private final OutputStream delegate;
+
+ public CloseShieldOutputStream(final OutputStream delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Does nothing.
+ */
+ @Override
+ public void close() {
+ // do not close delegate
+ }
+
+ @Override
+ public void flush() throws IOException {
+ delegate.flush();
+ }
+
+ @Override
+ public void write(final byte[] b) throws IOException {
+ delegate.write(b);
+ }
+
+ @Override
+ public void write(final byte[] b, final int off, final int len) throws IOException {
+ delegate.write(b, off, len);
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ delegate.write(b);
+ }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldWriter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldWriter.java
index c29cdf624e..b2f6fdcd9d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldWriter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/CloseShieldWriter.java
@@ -1,46 +1,46 @@
-/*
- * 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.util;
-
-import java.io.IOException;
-import java.io.Writer;
-
-public class CloseShieldWriter extends Writer {
-
- private final Writer delegate;
-
- public CloseShieldWriter(final Writer delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void close() throws IOException {
- // do not close delegate
- }
-
- @Override
- public void flush() throws IOException {
- delegate.flush();
-
- }
-
- @Override
- public void write(final char[] cbuf, final int off, final int len) throws IOException {
- delegate.write(cbuf, off, len);
- }
-
-}
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.Writer;
+
+public class CloseShieldWriter extends Writer {
+
+ private final Writer delegate;
+
+ public CloseShieldWriter(final Writer delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // do not close delegate
+ }
+
+ @Override
+ public void flush() throws IOException {
+ delegate.flush();
+
+ }
+
+ @Override
+ public void write(final char[] cbuf, final int off, final int len) throws IOException {
+ delegate.write(cbuf, off, len);
+ }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/IOUtils.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/IOUtils.java
index ffb8615cd3..07e5c79316 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/IOUtils.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/IOUtils.java
@@ -1,130 +1,130 @@
-/*
- * 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.util;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-
-/**
- * Copied from Apache Commons IO revision 1686747.
- */
-public class IOUtils {
-
- /**
- * The default buffer size ({@value}) to use for
- * {@link #copyLarge(InputStream, OutputStream)}
- * and
- * {@link #copyLarge(Reader, Writer)}
- */
- private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
-
- /**
- * Represents the end-of-file (or stream).
- */
- public static final int EOF = -1;
-
- /**
- * Copies chars from a <code>Reader</code> to a <code>Writer</code>.
- * <p/>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- * <p/>
- * Large streams (over 2GB) will return a chars copied value of
- * <code>-1</code> after the copy has completed since the correct
- * number of chars cannot be returned as an int. For large streams
- * use the <code>copyLarge(Reader, Writer)</code> method.
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>Writer</code> to write to
- * @return the number of characters copied, or -1 if > Integer.MAX_VALUE
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since 1.1
- */
- public static int copy(final Reader input, final Writer output) throws IOException {
- final long count = copyLarge(input, output);
- if (count > Integer.MAX_VALUE) {
- return -1;
- }
- return (int) count;
- }
-
- /**
- * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
- * <p/>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- * <p/>
- * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>Writer</code> to write to
- * @return the number of characters copied
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since 1.3
- */
- public static long copyLarge(final Reader input, final Writer output) throws IOException {
- return copyLarge(input, output, new char[DEFAULT_BUFFER_SIZE]);
- }
-
- /**
- * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
- * <p/>
- * This method uses the provided buffer, so there is no need to use a
- * <code>BufferedReader</code>.
- * <p/>
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>Writer</code> to write to
- * @param buffer the buffer to be used for the copy
- * @return the number of characters copied
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since 2.2
- */
- public static long copyLarge(final Reader input, final Writer output, final char[] buffer) throws IOException {
- long count = 0;
- int n;
- while (EOF != (n = input.read(buffer))) {
- output.write(buffer, 0, n);
- count += n;
- }
- return count;
- }
-
- /**
- * Gets the contents of a <code>Reader</code> as a String.
- * <p/>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from
- * @return the requested String
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static String toString(final Reader input) throws IOException {
- final StringBuilderWriter sw = new StringBuilderWriter();
- copy(input, sw);
- return sw.toString();
- }
-
-}
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * Copied from Apache Commons IO revision 1686747.
+ */
+public class IOUtils {
+
+ /**
+ * The default buffer size ({@value}) to use for
+ * {@link #copyLarge(InputStream, OutputStream)}
+ * and
+ * {@link #copyLarge(Reader, Writer)}
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+ /**
+ * Represents the end-of-file (or stream).
+ */
+ public static final int EOF = -1;
+
+ /**
+ * Copies chars from a <code>Reader</code> to a <code>Writer</code>.
+ * <p/>
+ * This method buffers the input internally, so there is no need to use a
+ * <code>BufferedReader</code>.
+ * <p/>
+ * Large streams (over 2GB) will return a chars copied value of
+ * <code>-1</code> after the copy has completed since the correct
+ * number of chars cannot be returned as an int. For large streams
+ * use the <code>copyLarge(Reader, Writer)</code> method.
+ *
+ * @param input the <code>Reader</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @return the number of characters copied, or -1 if > Integer.MAX_VALUE
+ * @throws NullPointerException if the input or output is null
+ * @throws IOException if an I/O error occurs
+ * @since 1.1
+ */
+ public static int copy(final Reader input, final Writer output) throws IOException {
+ final long count = copyLarge(input, output);
+ if (count > Integer.MAX_VALUE) {
+ return -1;
+ }
+ return (int) count;
+ }
+
+ /**
+ * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
+ * <p/>
+ * This method buffers the input internally, so there is no need to use a
+ * <code>BufferedReader</code>.
+ * <p/>
+ * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}.
+ *
+ * @param input the <code>Reader</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @return the number of characters copied
+ * @throws NullPointerException if the input or output is null
+ * @throws IOException if an I/O error occurs
+ * @since 1.3
+ */
+ public static long copyLarge(final Reader input, final Writer output) throws IOException {
+ return copyLarge(input, output, new char[DEFAULT_BUFFER_SIZE]);
+ }
+
+ /**
+ * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
+ * <p/>
+ * This method uses the provided buffer, so there is no need to use a
+ * <code>BufferedReader</code>.
+ * <p/>
+ *
+ * @param input the <code>Reader</code> to read from
+ * @param output the <code>Writer</code> to write to
+ * @param buffer the buffer to be used for the copy
+ * @return the number of characters copied
+ * @throws NullPointerException if the input or output is null
+ * @throws IOException if an I/O error occurs
+ * @since 2.2
+ */
+ public static long copyLarge(final Reader input, final Writer output, final char[] buffer) throws IOException {
+ long count = 0;
+ int n;
+ while (EOF != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+ /**
+ * Gets the contents of a <code>Reader</code> as a String.
+ * <p/>
+ * This method buffers the input internally, so there is no need to use a
+ * <code>BufferedReader</code>.
+ *
+ * @param input the <code>Reader</code> to read from
+ * @return the requested String
+ * @throws NullPointerException if the input is null
+ * @throws IOException if an I/O error occurs
+ */
+ public static String toString(final Reader input) throws IOException {
+ final StringBuilderWriter sw = new StringBuilderWriter();
+ copy(input, sw);
+ return sw.toString();
+ }
+
+}
diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java
index c28021a82f..98047a0cff 100644
--- a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java
+++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppender.java
@@ -172,6 +172,11 @@ public final class JeroMqAppender extends AbstractAppender {
sendRcTrue = sendRcFalse = 0;
}
+ // not public, handy for testing
+ byte[] recv(int timeoutMs) {
+ return manager.recv(timeoutMs);
+ }
+
@Override
public String toString() {
return "JeroMqAppender{" +
diff --git a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java
index e50972df03..51aaf1b840 100644
--- a/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java
+++ b/log4j-jeromq/src/main/java/org/apache/logging/log4j/jeromq/appender/JeroMqManager.java
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.util.Cancellable;
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.util.PropertiesUtil;
+import org.zeromq.SocketType;
import org.zeromq.ZMQ;
/**
@@ -60,7 +61,7 @@ public class JeroMqManager extends AbstractManager {
final boolean enableShutdownHook = PropertiesUtil.getProperties().getBooleanProperty(
SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK, true);
- if (enableShutdownHook) {
+ if (enableShutdownHook && LogManager.getFactory() instanceof ShutdownCallbackRegistry) {
SHUTDOWN_HOOK = ((ShutdownCallbackRegistry) LogManager.getFactory()).addShutdownCallback(CONTEXT::close);
} else {
SHUTDOWN_HOOK = null;
@@ -71,7 +72,7 @@ public class JeroMqManager extends AbstractManager {
private JeroMqManager(final String name, final JeroMqConfiguration config) {
super(null, name);
- publisher = CONTEXT.socket(ZMQ.PUB);
+ publisher = CONTEXT.socket(SocketType.XPUB);
publisher.setAffinity(config.affinity);
publisher.setBacklog(config.backlog);
publisher.setDelayAttachOnConnect(config.delayAttachOnConnect);
@@ -104,6 +105,17 @@ public class JeroMqManager extends AbstractManager {
return publisher.send(data);
}
+ // not public, handy for testing
+ byte[] recv(int timeoutMs) {
+ int oldTimeoutMs = publisher.getReceiveTimeOut();
+ try {
+ publisher.setReceiveTimeOut(timeoutMs);
+ return publisher.recv();
+ } finally {
+ publisher.setReceiveTimeOut(oldTimeoutMs);
+ }
+ }
+
@Override
protected boolean releaseSub(final long timeout, final TimeUnit timeUnit) {
publisher.close();
diff --git a/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java b/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java
index e582559281..aafe354a5d 100644
--- a/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java
+++ b/log4j-jeromq/src/test/java/org/apache/logging/log4j/jeromq/appender/JeroMqAppenderTest.java
@@ -21,6 +21,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.Logger;
@@ -31,13 +32,12 @@ import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
+import static org.assertj.core.api.Assertions.fail;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.fail;
@Tag("zeromq")
-@Tag("sleepy")
-@Timeout(value = 200)
+@Timeout(value = 10, unit = TimeUnit.SECONDS)
@LoggerContextSource(value = "JeroMqAppenderTest.xml", timeout = 60)
public class JeroMqAppenderTest {
@@ -61,7 +61,7 @@ public class JeroMqAppenderTest {
final ExecutorService executor = Executors.newSingleThreadExecutor();
try {
final Future<List<String>> future = executor.submit(client);
- Thread.sleep(100);
+ waitForSubscription(appender, 1000);
appender.resetSendRcs();
logger.info("Hello");
logger.info("Again");
@@ -87,7 +87,7 @@ public class JeroMqAppenderTest {
final ExecutorService executor = Executors.newSingleThreadExecutor();
try {
final Future<List<String>> future = executor.submit(client);
- Thread.sleep(100);
+ waitForSubscription(appender, 1000);
appender.resetSendRcs();
final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
for (int i = 0; i < 10.; i++) {
@@ -129,4 +129,15 @@ public class JeroMqAppenderTest {
assertEquals(2, appender.getSendRcTrue());
assertEquals(0, appender.getSendRcFalse());
}
+
+ private void waitForSubscription(JeroMqAppender appender, int timeoutMs) throws Exception {
+ final long start = System.currentTimeMillis();
+ while (System.currentTimeMillis() - start < timeoutMs) {
+ byte[] msg = appender.recv(timeoutMs);
+ if (msg != null && msg.length > 0 && msg[0] == 1) {
+ return;
+ }
+ }
+ throw new TimeoutException();
+ }
}
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java
index 07f3234060..6a8a4a90e9 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java
@@ -75,14 +75,17 @@ public final class TestHelpers {
final Consumer<MapAccessor> accessorConsumer) {
final String serializedLogEventJson = layout.toSerializable(logEvent);
@SuppressWarnings("unchecked")
- final Map<String, Object> deserializedLogEvent =
- (Map<String, Object>) readJson(serializedLogEventJson);
+ final Map<String, Object> deserializedLogEvent = (Map<String, Object>) readJson(serializedLogEventJson);
final MapAccessor serializedLogEventAccessor = new MapAccessor(deserializedLogEvent);
accessorConsumer.accept(serializedLogEventAccessor);
}
public static Object readJson(final String json) {
- return JsonReader.read(json);
+ try {
+ return JsonReader.read(json);
+ } catch (final Exception error) {
+ throw new RuntimeException("failed to deserialize the JSON: " + json, error);
+ }
}
public static Map<String, Object> asMap(final Object... pairs) {
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolverTest.java
new file mode 100644
index 0000000000..8eeb6f7f4a
--- /dev/null
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolverTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.resolver;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.logging.log4j.layout.template.json.TestHelpers.*;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class MarkerResolverTest {
+
+ @Test
+ void should_have_a_marker_name() {
+
+ // Create the event template
+ final String eventTemplate = writeJson(asMap(
+ "marker", asMap(
+ "$resolver", "marker",
+ "field", "name")));
+
+ // Create the layout.
+ final JsonTemplateLayout layout = JsonTemplateLayout
+ .newBuilder()
+ .setConfiguration(CONFIGURATION)
+ .setEventTemplate(eventTemplate)
+ .build();
+
+ // Create the log event.
+ final Marker marker = MarkerManager.getMarker("MARKER");
+ final LogEvent logEvent = Log4jLogEvent
+ .newBuilder()
+ .setMarker(marker)
+ .build();
+
+ // Check the serialized event.
+ usingSerializedLogEventAccessor(layout, logEvent, accessor ->
+ assertThat(accessor.getString("marker")).isEqualTo("MARKER"));
+
+ }
+
+ @Test
+ void should_list_parents_as_array() {
+
+ // Create the event template
+ final String eventTemplate = writeJson(asMap(
+ "parents", asMap(
+ "$resolver", "marker",
+ "field", "parents")));
+
+ // Create the layout.
+ final JsonTemplateLayout layout = JsonTemplateLayout
+ .newBuilder()
+ .setConfiguration(CONFIGURATION)
+ .setEventTemplate(eventTemplate)
+ .build();
+
+ // Create the log event.
+ final Marker parentMarker1 = MarkerManager.getMarker("PARENT_MARKER_NAME_1");
+ final Marker parentMarker2 = MarkerManager.getMarker("PARENT_MARKER_NAME_2");
+ final Marker childMarker = MarkerManager.getMarker("CHILD_MARKER_NAME");
+ childMarker.setParents(parentMarker1, parentMarker2);
+
+ final LogEvent logEvent = Log4jLogEvent
+ .newBuilder()
+ .setMarker(childMarker)
+ .build();
+
+ // Check the serialized event.
+ usingSerializedLogEventAccessor(layout, logEvent, accessor ->
+ assertThat(accessor.getList("parents", String.class))
+ .containsOnly(parentMarker1.getName(), parentMarker2.getName()));
+
+ }
+
+}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolver.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolver.java
index fc1c30c9bc..4975fd2a15 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolver.java
+++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolver.java
@@ -26,7 +26,7 @@ import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
* <h3>Configuration</h3>
*
* <pre>
- * config = "field" -> "name"
+ * config = "field" -> ( "name" | "parents" )
* </pre>
*
* <h3>Examples</h3>
@@ -39,6 +39,15 @@ import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
* "field": "name"
* }
* </pre>
+ *
+ * Resolve the names of the marker's parents:
+ *
+ * <pre>
+ * {
+ * "$resolver": "marker",
+ * "field": "parents"
+ * }
+ * </pre>
*/
public final class MarkerResolver implements EventResolver {
@@ -52,6 +61,30 @@ public final class MarkerResolver implements EventResolver {
}
};
+ private static final TemplateResolver<LogEvent> PARENTS_RESOLVER =
+ (final LogEvent logEvent, final JsonWriter jsonWriter) -> {
+
+ // Short-circuit if there are no parents
+ final Marker marker = logEvent.getMarker();
+ if (marker == null || !marker.hasParents()) {
+ jsonWriter.writeNull();
+ return;
+ }
+
+ // Write parents
+ final Marker[] parents = marker.getParents();
+ jsonWriter.writeArrayStart();
+ for (int parentIndex = 0; parentIndex < parents.length; parentIndex++) {
+ if (parentIndex > 0) {
+ jsonWriter.writeSeparator();
+ }
+ final Marker parentMarker = parents[parentIndex];
+ jsonWriter.writeString(parentMarker.getName());
+ }
+ jsonWriter.writeArrayEnd();
+
+ };
+
private final TemplateResolver<LogEvent> internalResolver;
MarkerResolver(final TemplateResolverConfig config) {
@@ -61,9 +94,15 @@ public final class MarkerResolver implements EventResolver {
private TemplateResolver<LogEvent> createInternalResolver(
final TemplateResolverConfig config) {
final String fieldName = config.getString("field");
+
if ("name".equals(fieldName)) {
return NAME_RESOLVER;
}
+
+ if ("parents".equals(fieldName)) {
+ return PARENTS_RESOLVER;
+ }
+
throw new IllegalArgumentException("unknown field: " + config);
}
diff --git a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/internal/util/HierarchicalCollections.java b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/internal/util/HierarchicalCollections.java
index dbeb78232d..18d0093b88 100644
--- a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/internal/util/HierarchicalCollections.java
+++ b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/internal/util/HierarchicalCollections.java
@@ -16,12 +16,7 @@
*/
package org.apache.logging.log4j.plugins.internal.util;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
class HierarchicalCollections {
diff --git a/log4j-to-slf4j/pom.xml b/log4j-to-slf4j/pom.xml
index 66fe3e4a8d..f7543705b0 100644
--- a/log4j-to-slf4j/pom.xml
+++ b/log4j-to-slf4j/pom.xml
@@ -31,6 +31,7 @@
<docLabel>SLF4J Documentation</docLabel>
<projectDir>/log4j-to-slf4j</projectDir>
<module.name>org.apache.logging.slf4j</module.name>
+ <slf4j.support.bound>3</slf4j.support.bound>
</properties>
<dependencies>
<dependency>
@@ -91,6 +92,7 @@
<configuration>
<instructions>
<Export-Package>org.apache.logging.slf4j</Export-Package>
+ <Import-Package>org.slf4j*;version="${range;[==,${slf4j.support.bound})}",*</Import-Package>
</instructions>
</configuration>
</plugin>
diff --git a/pom.xml b/pom.xml
index 786d2c52aa..9f6cb8412f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -434,6 +434,7 @@
<jetty.version>9.4.50.v20221201</jetty.version>
<jmdns.version>3.5.8</jmdns.version>
<jmh.version>1.36</jmh.version>
+ <jna.version>5.12.1</jna.version>
<json-unit.version>2.36.0</json-unit.version>
<junit.version>4.13.2</junit.version>
<junit-jupiter.version>5.9.1</junit-jupiter.version>
@@ -982,6 +983,12 @@
<version>${jmh.version}</version>
</dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>${jna.version}</version>
+ </dependency>
+
<dependency>
<groupId>net.javacrumbs.json-unit</groupId>
<artifactId>json-unit</artifactId>
@@ -1353,7 +1360,7 @@
</plugin>
<plugin>
- <groupId>org.apache.felix</groupId>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-artifact-plugin</artifactId>
<version>${maven-artifact-plugin.version}</version>
</plugin>
diff --git a/src/changelog/.2.x.x/1232_log4j-to-sfl4j-2-OSGiMetadata.xml b/src/changelog/.2.x.x/1232_log4j-to-sfl4j-2-OSGiMetadata.xml
new file mode 100644
index 0000000000..b166412c83
--- /dev/null
+++ b/src/changelog/.2.x.x/1232_log4j-to-sfl4j-2-OSGiMetadata.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://logging.apache.org/log4j/changelog"
+ xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.0.xsd"
+ type="fixed">
+ <issue id="1232" link="https://github.com/apache/logging-log4j2/issues/1232"/>
+ <author id="hanneswell"/>
+ <author name="Hannes Wellmann"/>
+ <description format="asciidoc">
+ Adapt the OSGi metadata of log4j-to-slf4j to work with slf4j 1 and 2.
+ To achieve that use a version range of `[1.7,3)` for the imported slf4j packages.
+ </description>
+</entry>
diff --git a/src/changelog/.2.x.x/1366_fix_java_sql_date.xml b/src/changelog/.2.x.x/1366_fix_java_sql_date.xml
new file mode 100644
index 0000000000..8a28a5bd2e
--- /dev/null
+++ b/src/changelog/.2.x.x/1366_fix_java_sql_date.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://logging.apache.org/log4j/changelog"
+ xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.1.xsd"
+ type="fixed">
+ <issue id="1366" link="https://github.com/apache/logging-log4j2/pull/1366"/>
+ <author id="Hikarikun92"/>
+ <author name="Lucas Souza"/>
+ <description format="asciidoc">
+ Fixed logging of java.sql.Date objects by appending it before Log4J tries to call java.util.Date.toInstant() on it.
+ </description>
+</entry>
diff --git a/src/site/asciidoc/manual/json-template-layout.adoc.vm b/src/site/asciidoc/manual/json-template-layout.adoc.vm
index f1bb103a21..ad61105033 100644
--- a/src/site/asciidoc/manual/json-template-layout.adoc.vm
+++ b/src/site/asciidoc/manual/json-template-layout.adoc.vm
@@ -743,6 +743,8 @@ Each `pointMatcherRegexes` item triggers a `Pattern#matcher()` call, which is
not garbage-free either.
====
+====== Examples
+
Resolve `logEvent.getThrown().getClass().getCanonicalName()`:
[source,json]
@@ -849,6 +851,8 @@ severity-field = "field" -> ( "keyword" | "code" )
Resolves the fields of the `logEvent.getLevel()`.
+====== Examples
+
Resolve the level name:
[source,json]
@@ -897,6 +901,8 @@ config = "field" -> ( "name" | "fqcn" )
Resolves `logEvent.getLoggerFqcn()` and `logEvent.getLoggerName()`.
+====== Examples
+
Resolve the logger name:
[source,json]
@@ -930,6 +936,8 @@ key = "key" -> string
Performs link:lookups.html#AppMainArgsLookup[Main Argument Lookup] for the
given `index` or `key`.
+====== Examples
+
Resolve the 1st `main()` method argument:
[source,json]
@@ -956,6 +964,38 @@ Resolve the argument coming right after `--userId`:
Resolves ``MapMessage``s. See link:#map-resolver-template[Map Resolver Template]
for details.
+[#event-template-resolver-marker]
+===== `marker`
+
+[source]
+----
+config = "field" -> ( "name" | "parents" )
+----
+
+Resolves `logEvent.getMarker()`.
+
+====== Examples
+
+Resolve the marker name:
+
+[source,json]
+----
+{
+ "$resolver": "marker",
+ "field": "name"
+}
+----
+
+Resolve the names of the marker's parents:
+
+[source,json]
+----
+{
+ "$resolver": "marker",
+ "field": "parents"
+}
+----
+
[#event-template-resolver-mdc]
===== `mdc`
@@ -986,6 +1026,8 @@ For simple string messages, the resolution is performed without allocations.
For ``ObjectMessage``s and ``MultiformatMessage``s, it depends.
====
+====== Examples
+
Resolve the message into a string:
[source,json]
@@ -1047,6 +1089,8 @@ Regarding garbage footprint, `stringified` flag translates to
which is the case if `log4j2.enableThreadLocals` property set to true.
====
+====== Examples
+
Resolve the message parameters into an array:
[source,json]
@@ -1099,6 +1143,8 @@ pattern = "pattern" -> string
Resolves the Nested Diagnostic Context (NDC), aka. Thread Context Stack,
`String[]` returned by `logEvent.getContextStack()`.
+====== Examples
+
Resolve all NDC values into a list:
[source,json]
@@ -1133,6 +1179,8 @@ Resolver delegating to link:layouts.html#PatternLayout[`PatternLayout`].
The default value of `stackTraceEnabled` is inherited from the parent
`JsonTemplateLayout`.
+====== Examples
+
Resolve the string produced by `%p %c{1.} [%t] %X{userId} %X %m%ex` pattern:
[source,json]
@@ -1161,6 +1209,8 @@ Resolves the fields of the `StackTraceElement` returned by
Note that this resolver is toggled by
`log4j.layout.jsonTemplate.locationInfoEnabled` property.
+====== Examples
+
Resolve the line number:
[source,json]
@@ -1182,6 +1232,8 @@ config = "field" -> ( "name" | "id" | "priority" )
Resolves `logEvent.getThreadId()`, `logEvent.getThreadName()`,
`logEvent.getThreadPriority()`.
+====== Examples
+
Resolve the thread name:
[source,json]
@@ -1221,6 +1273,8 @@ rounded = "rounded" -> boolean
Resolves `logEvent.getInstant()` in various forms.
+====== Examples
+
.`timestamp` template resolver examples
[cols="5,2m"]
|===