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 layout = PatternLayout.newBuilder() - .withPattern(DefaultConfiguration.DEFAULT_PATTERN) - .withConfiguration(this) - .build(); + final Layout 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 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 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 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]. + +