From 72c7f01e04cab7137d02b88918bfe12ce0a69a4d Mon Sep 17 00:00:00 2001
From: "Piotr P. Karwasz"
Date: Thu, 24 Oct 2024 08:53:31 +0200
Subject: [PATCH 1/4] Create `DefaultLayout` independent of `PatternLayout`
Currently, `PatternLayout` and all its patterns are a required element of Log4j Core, since `DefaultConfiguration` uses it.
The default configuration is used in all Log4j Core installation as failsafe to handle logging between the time a logger context is created and the real configuration starts (a couple of ms).
This PR creates a simple hardcoded layout to use with `DefaultConfiguration`.
---
.../core/config/AbstractConfiguration.java | 6 +-
.../core/config/DefaultConfiguration.java | 68 +++++++++++++++++++
2 files changed, 69 insertions(+), 5 deletions(-)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 3b301bde4d7..3b56d879511 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -58,7 +58,6 @@
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.filter.AbstractFilterable;
-import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.PropertiesLookup;
@@ -779,10 +778,7 @@ public static Level getDefaultLevel() {
protected void setToDefault() {
// LOG4J2-1176 facilitate memory leak investigation
setName(DefaultConfiguration.DEFAULT_NAME + "@" + Integer.toHexString(hashCode()));
- final Layout extends Serializable> layout = PatternLayout.newBuilder()
- .withPattern(DefaultConfiguration.DEFAULT_PATTERN)
- .withConfiguration(this)
- .build();
+ final Layout extends Serializable> layout = DefaultConfiguration.createDefaultLayout();
final Appender appender = ConsoleAppender.createDefaultAppenderForLayout(layout);
appender.start();
addAppender(appender);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
index 03444e8dc66..9cc978f340d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
@@ -16,6 +16,18 @@
*/
package org.apache.logging.log4j.core.config;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import org.apache.logging.log4j.LoggingException;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.layout.AbstractLayout;
+import org.apache.logging.log4j.core.util.StringBuilderWriter;
+import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
+import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
+
/**
* The default configuration writes all output to the Console using the default logging level. You configure default
* logging level by setting the system property "org.apache.logging.log4j.level" to a level name. If you do not
@@ -49,4 +61,60 @@ public DefaultConfiguration() {
@Override
protected void doConfigure() {}
+
+ static Layout extends String> createDefaultLayout() {
+ return new DefaultLayout();
+ }
+
+ /**
+ * A simple layout used only by {@link DefaultConfiguration}
+ *
+ * This layout allows to create applications that don't contain {@link org.apache.logging.log4j.core.layout.PatternLayout}
+ * and all its patterns, e.g. GraalVM applications.
+ *
+ */
+ private static final class DefaultLayout extends AbstractLayout {
+
+ private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+ private final FixedDateFormat dateFormat = FixedDateFormat.create(FixedFormat.ABSOLUTE);
+
+ private DefaultLayout() {
+ super(null, EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY);
+ }
+
+ @Override
+ public String toSerializable(LogEvent event) {
+ try (Writer sw = new StringBuilderWriter();
+ PrintWriter pw = new PrintWriter(sw)) {
+ pw.append(dateFormat.format(event.getTimeMillis()))
+ .append(" [")
+ .append(event.getThreadName())
+ .append("] ")
+ .append(event.getLevel().toString())
+ .append(" ")
+ .append(event.getLoggerName())
+ .append(" - ")
+ .append(event.getMessage().getFormattedMessage())
+ .append("\n");
+ Throwable throwable = event.getThrown();
+ if (throwable != null) {
+ throwable.printStackTrace(pw);
+ }
+ return sw.toString();
+ } catch (IOException e) {
+ throw new LoggingException(e);
+ }
+ }
+
+ @Override
+ public byte[] toByteArray(LogEvent event) {
+ return toSerializable(event).getBytes(Charset.defaultCharset());
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/plain";
+ }
+ }
}
From bf892e169e273d3e9c4e4812e4ffac4178460a3d Mon Sep 17 00:00:00 2001
From: "Piotr P. Karwasz"
Date: Thu, 24 Oct 2024 12:47:06 +0200
Subject: [PATCH 2/4] Address review suggestions
---
.../core/config/AbstractConfiguration.java | 5 +-
.../core/config/DefaultConfiguration.java | 68 ---------------
.../log4j/core/config/DefaultLayout.java | 86 +++++++++++++++++++
3 files changed, 87 insertions(+), 72 deletions(-)
create mode 100644 log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 3b56d879511..5b60a7727b3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -20,7 +20,6 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.util.ArrayList;
@@ -40,7 +39,6 @@
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LifeCycle2;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.LoggerContext;
@@ -778,8 +776,7 @@ public static Level getDefaultLevel() {
protected void setToDefault() {
// LOG4J2-1176 facilitate memory leak investigation
setName(DefaultConfiguration.DEFAULT_NAME + "@" + Integer.toHexString(hashCode()));
- final Layout extends Serializable> layout = DefaultConfiguration.createDefaultLayout();
- final Appender appender = ConsoleAppender.createDefaultAppenderForLayout(layout);
+ final Appender appender = ConsoleAppender.createDefaultAppenderForLayout(DefaultLayout.INSTANCE);
appender.start();
addAppender(appender);
final LoggerConfig rootLoggerConfig = getRootLogger();
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
index 9cc978f340d..03444e8dc66 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java
@@ -16,18 +16,6 @@
*/
package org.apache.logging.log4j.core.config;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import org.apache.logging.log4j.LoggingException;
-import org.apache.logging.log4j.core.Layout;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.layout.AbstractLayout;
-import org.apache.logging.log4j.core.util.StringBuilderWriter;
-import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
-import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
-
/**
* The default configuration writes all output to the Console using the default logging level. You configure default
* logging level by setting the system property "org.apache.logging.log4j.level" to a level name. If you do not
@@ -61,60 +49,4 @@ public DefaultConfiguration() {
@Override
protected void doConfigure() {}
-
- static Layout extends String> createDefaultLayout() {
- return new DefaultLayout();
- }
-
- /**
- * A simple layout used only by {@link DefaultConfiguration}
- *
- * This layout allows to create applications that don't contain {@link org.apache.logging.log4j.core.layout.PatternLayout}
- * and all its patterns, e.g. GraalVM applications.
- *
- */
- private static final class DefaultLayout extends AbstractLayout {
-
- private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-
- private final FixedDateFormat dateFormat = FixedDateFormat.create(FixedFormat.ABSOLUTE);
-
- private DefaultLayout() {
- super(null, EMPTY_BYTE_ARRAY, EMPTY_BYTE_ARRAY);
- }
-
- @Override
- public String toSerializable(LogEvent event) {
- try (Writer sw = new StringBuilderWriter();
- PrintWriter pw = new PrintWriter(sw)) {
- pw.append(dateFormat.format(event.getTimeMillis()))
- .append(" [")
- .append(event.getThreadName())
- .append("] ")
- .append(event.getLevel().toString())
- .append(" ")
- .append(event.getLoggerName())
- .append(" - ")
- .append(event.getMessage().getFormattedMessage())
- .append("\n");
- Throwable throwable = event.getThrown();
- if (throwable != null) {
- throwable.printStackTrace(pw);
- }
- return sw.toString();
- } catch (IOException e) {
- throw new LoggingException(e);
- }
- }
-
- @Override
- public byte[] toByteArray(LogEvent event) {
- return toSerializable(event).getBytes(Charset.defaultCharset());
- }
-
- @Override
- public String getContentType() {
- return "text/plain";
- }
- }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java
new file mode 100644
index 00000000000..3e02eac1ae9
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java
@@ -0,0 +1,86 @@
+/*
+ * 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 java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.StringLayout;
+import org.apache.logging.log4j.core.layout.ByteBufferDestination;
+import org.apache.logging.log4j.status.StatusData;
+
+/**
+ * A simple layout used only by {@link DefaultConfiguration}
+ *
+ * This layout allows to create applications that don't contain {@link org.apache.logging.log4j.core.layout.PatternLayout}
+ * and all its patterns, e.g. GraalVM applications.
+ *
+ */
+final class DefaultLayout implements StringLayout {
+
+ static final StringLayout INSTANCE = new DefaultLayout();
+
+ private DefaultLayout() {}
+
+ @Override
+ public String toSerializable(LogEvent event) {
+ return new StatusData(
+ event.getSource(),
+ event.getLevel(),
+ event.getMessage(),
+ event.getThrown(),
+ event.getThreadName())
+ .getFormattedStatus();
+ }
+
+ @Override
+ public byte[] toByteArray(LogEvent event) {
+ return toSerializable(event).getBytes(Charset.defaultCharset());
+ }
+
+ @Override
+ public void encode(LogEvent event, ByteBufferDestination destination) {
+ final byte[] data = toByteArray(event);
+ destination.writeBytes(data, 0, data.length);
+ }
+
+ @Override
+ public String getContentType() {
+ return "text/plain";
+ }
+
+ @Override
+ public Charset getCharset() {
+ return Charset.defaultCharset();
+ }
+
+ @Override
+ public byte[] getFooter() {
+ return null;
+ }
+
+ @Override
+ public byte[] getHeader() {
+ return null;
+ }
+
+ @Override
+ public Map getContentFormat() {
+ return Collections.emptyMap();
+ }
+}
From 19e7a166685b676227f607e38225aa20acea1064 Mon Sep 17 00:00:00 2001
From: "Piotr P. Karwasz"
Date: Fri, 25 Oct 2024 09:13:39 +0200
Subject: [PATCH 3/4] Apply suggestions from code review
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Volkan Yazıcı
---
.../org/apache/logging/log4j/core/config/DefaultLayout.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java
index 3e02eac1ae9..5aabbec39bb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/DefaultLayout.java
@@ -30,6 +30,8 @@
* This layout allows to create applications that don't contain {@link org.apache.logging.log4j.core.layout.PatternLayout}
* and all its patterns, e.g. GraalVM applications.
*
+ *
+ * @since 2.25.0
*/
final class DefaultLayout implements StringLayout {
From 69f2823bfee9566fcdd04ab66e2cb8e50da2641d Mon Sep 17 00:00:00 2001
From: "Piotr P. Karwasz"
Date: Fri, 25 Oct 2024 09:27:13 +0200
Subject: [PATCH 4/4] Adds changelog
---
src/changelog/.2.x.x/3118_default_layout.xml | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 src/changelog/.2.x.x/3118_default_layout.xml
diff --git a/src/changelog/.2.x.x/3118_default_layout.xml b/src/changelog/.2.x.x/3118_default_layout.xml
new file mode 100644
index 00000000000..366942fe5ed
--- /dev/null
+++ b/src/changelog/.2.x.x/3118_default_layout.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ Changes the layout used by the
+ https://logging.apache.org/log4j/2.x/manual/configuration.html#automatic-configuration[default configuration].
+
+