diff --git a/config/checkstyle/checkstyle-suppressions.xml b/config/checkstyle/checkstyle-suppressions.xml index 30b078caeb2..482da4a39e1 100644 --- a/config/checkstyle/checkstyle-suppressions.xml +++ b/config/checkstyle/checkstyle-suppressions.xml @@ -75,7 +75,4 @@ - - - diff --git a/core/spring-boot/build.gradle b/core/spring-boot/build.gradle index cc64ced1a1b..44cb7ba5066 100644 --- a/core/spring-boot/build.gradle +++ b/core/spring-boot/build.gradle @@ -87,12 +87,6 @@ tasks.named("checkFormatMain") { source(fileTree("src/main/javaTemplates")) } -tasks.named("compileJava") { - // Provide the project coordinates to the `GraalVmProcessor`: - options.compilerArgs << '-Alog4j.graalvm.groupId=org.springframework.boot' - options.compilerArgs << '-Alog4j.graalvm.artifactId=spring-boot-log4j' -} - plugins.withType(EclipsePlugin) { eclipse { synchronizationTasks syncJavaTemplates diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatter.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatter.java index ab97f7a23e8..0f26973cec5 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatter.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatter.java @@ -19,11 +19,11 @@ package org.springframework.boot.logging.log4j2; import java.util.Objects; import java.util.Set; import java.util.TreeSet; -import java.util.function.Function; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.apache.logging.log4j.core.time.Instant; import org.apache.logging.log4j.util.ReadOnlyStringMap; import org.jspecify.annotations.Nullable; @@ -71,10 +71,10 @@ class ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogF members.add("message", LogEvent::getMessage).as(StructuredMessage::get); members.from(LogEvent::getContextData) .usingPairs(contextPairs.nested(ElasticCommonSchemaStructuredLogFormatter::addContextDataPairs)); - members.from(LogEvent::getThrown).whenNotNull().usingMembers((thrownProxyMembers) -> { + members.from(LogEvent::getThrownProxy).whenNotNull().usingMembers((thrownProxyMembers) -> { thrownProxyMembers.add("error").usingMembers((error) -> { - error.add("type", Function.identity()).whenNotNull().as(ObjectUtils::nullSafeClassName); - error.add("message", Throwable::getMessage); + error.add("type", ThrowableProxy::getThrowable).whenNotNull().as(ObjectUtils::nullSafeClassName); + error.add("message", ThrowableProxy::getMessage); error.add("stack_trace", extractor::stackTrace); }); }); diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ExtendedWhitespaceThrowablePatternConverter.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ExtendedWhitespaceThrowablePatternConverter.java index defe0704e00..3b45bb66293 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ExtendedWhitespaceThrowablePatternConverter.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ExtendedWhitespaceThrowablePatternConverter.java @@ -21,7 +21,6 @@ import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.pattern.ConverterKeys; import org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter; -import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; import org.apache.logging.log4j.core.pattern.PatternConverter; import org.apache.logging.log4j.core.pattern.ThrowablePatternConverter; import org.jspecify.annotations.Nullable; @@ -36,33 +35,24 @@ import org.jspecify.annotations.Nullable; */ @Plugin(name = "ExtendedWhitespaceThrowablePatternConverter", category = PatternConverter.CATEGORY) @ConverterKeys({ "xwEx", "xwThrowable", "xwException" }) -public final class ExtendedWhitespaceThrowablePatternConverter extends LogEventPatternConverter { +public final class ExtendedWhitespaceThrowablePatternConverter extends ThrowablePatternConverter { private final ExtendedThrowablePatternConverter delegate; - private final String separator; - - @SuppressWarnings("deprecation") // https://github.com/apache/logging-log4j2/issues/3809 - private ExtendedWhitespaceThrowablePatternConverter(Configuration configuration, @Nullable String[] options) { - super("WhitespaceExtendedThrowable", "throwable"); + private ExtendedWhitespaceThrowablePatternConverter(Configuration configuration, String @Nullable [] options) { + super("WhitespaceExtendedThrowable", "throwable", options, configuration); this.delegate = ExtendedThrowablePatternConverter.newInstance(configuration, options); - this.separator = this.delegate.getOptions().getSeparator(); } @Override public void format(LogEvent event, StringBuilder buffer) { if (event.getThrown() != null) { - buffer.append(this.separator); + buffer.append(this.options.getSeparator()); this.delegate.format(event, buffer); - buffer.append(this.separator); + buffer.append(this.options.getSeparator()); } } - @Override - public boolean handlesThrowable() { - return true; - } - /** * Creates a new instance of the class. Required by Log4J2. * @param configuration current configuration @@ -71,7 +61,7 @@ public final class ExtendedWhitespaceThrowablePatternConverter extends LogEventP * @return a new {@code WhitespaceThrowablePatternConverter} */ public static ExtendedWhitespaceThrowablePatternConverter newInstance(Configuration configuration, - @Nullable String[] options) { + String @Nullable [] options) { return new ExtendedWhitespaceThrowablePatternConverter(configuration, options); } diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Extractor.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Extractor.java index 0d9fa411e6e..bda41b00561 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Extractor.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Extractor.java @@ -16,14 +16,13 @@ package org.springframework.boot.logging.log4j2; -import java.io.PrintWriter; -import java.io.StringWriter; - import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.jspecify.annotations.Nullable; import org.slf4j.event.LoggingEvent; import org.springframework.boot.logging.StackTracePrinter; +import org.springframework.util.Assert; /** * Functions to extract items from {@link LoggingEvent}. @@ -43,23 +42,19 @@ class Extractor { } @Nullable String stackTrace(LogEvent event) { - return stackTrace(event.getThrown()); + return stackTrace(event.getThrownProxy()); } - @Nullable String stackTrace(@Nullable Throwable throwable) { - if (throwable == null) { + @Nullable String stackTrace(@Nullable ThrowableProxy throwableProxy) { + if (throwableProxy == null) { return null; } if (this.stackTracePrinter != null) { + Throwable throwable = throwableProxy.getThrowable(); + Assert.state(throwable != null, "Proxy must return Throwable in order to print exception"); return this.stackTracePrinter.printStackTraceToString(throwable); } - return printStackTrace(throwable); - } - - private static String printStackTrace(Throwable throwable) { - StringWriter stringWriter = new StringWriter(); - throwable.printStackTrace(new PrintWriter(stringWriter)); - return stringWriter.toString(); + return throwableProxy.getExtendedStackTraceAsString(); } } diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/GraylogExtendedLogFormatStructuredLogFormatter.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/GraylogExtendedLogFormatStructuredLogFormatter.java index d7026150f4f..39602890819 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/GraylogExtendedLogFormatStructuredLogFormatter.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/GraylogExtendedLogFormatStructuredLogFormatter.java @@ -98,8 +98,8 @@ class GraylogExtendedLogFormatStructuredLogFormatter extends JsonWriterStructure .usingPairs(contextPairs.flat(additionalFieldJoiner(), GraylogExtendedLogFormatStructuredLogFormatter::addContextDataPairs)); members.add() - .whenNotNull(LogEvent::getThrown) - .usingMembers((thrownMembers) -> throwableMembers(thrownMembers, extractor)); + .whenNotNull(LogEvent::getThrownProxy) + .usingMembers((thrownProxyMembers) -> throwableMembers(thrownProxyMembers, extractor)); } private static String getMessageText(Message message) { @@ -131,9 +131,11 @@ class GraylogExtendedLogFormatStructuredLogFormatter extends JsonWriterStructure private static void throwableMembers(Members members, Extractor extractor) { members.add("full_message", extractor::messageAndStackTrace); - members.add("_error_type", LogEvent::getThrown).whenNotNull().as(ObjectUtils::nullSafeClassName); + members.add("_error_type", (event) -> event.getThrownProxy().getThrowable()) + .whenNotNull() + .as(ObjectUtils::nullSafeClassName); members.add("_error_stack_trace", extractor::stackTrace); - members.add("_error_message", (event) -> event.getThrown().getMessage()); + members.add("_error_message", (event) -> event.getThrownProxy().getMessage()); } private static void addContextDataPairs(ContextPairs.Pairs contextPairs) { diff --git a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/LogstashStructuredLogFormatter.java b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/LogstashStructuredLogFormatter.java index 85321ce74a6..cbd2d70254f 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/LogstashStructuredLogFormatter.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/LogstashStructuredLogFormatter.java @@ -68,7 +68,7 @@ class LogstashStructuredLogFormatter extends JsonWriterStructuredLogFormatter deserialized = deserialize(json); String stackTrace = (String) deserialized.get("stack_trace"); assertThat(stackTrace).startsWith( - "java.lang.RuntimeException: Boom%n\tat org.springframework.boot.logging.log4j2.LogstashStructuredLogFormatterTests.shouldFormatException" - .formatted()); + """ + java.lang.RuntimeException: Boom + \tat org.springframework.boot.logging.log4j2.LogstashStructuredLogFormatterTests.shouldFormatException"""); assertThat(json).contains( - "java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.log4j2.LogstashStructuredLogFormatterTests.shouldFormatException" - .formatted() - .replace("\n", "\\n") - .replace("\r", "\\r")); + """ + java.lang.RuntimeException: Boom\\n\\tat org.springframework.boot.logging.log4j2.LogstashStructuredLogFormatterTests.shouldFormatException"""); } @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/WhitespaceThrowablePatternConverterTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/WhitespaceThrowablePatternConverterTests.java index 782cbeae15e..970176a04b2 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/WhitespaceThrowablePatternConverterTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/WhitespaceThrowablePatternConverterTests.java @@ -19,7 +19,7 @@ package org.springframework.boot.logging.log4j2; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.impl.Log4jLogEvent; -import org.apache.logging.log4j.core.pattern.LogEventPatternConverter; +import org.apache.logging.log4j.core.pattern.ThrowablePatternConverter; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ class WhitespaceThrowablePatternConverterTests { - private final LogEventPatternConverter converter = WhitespaceThrowablePatternConverter + private final ThrowablePatternConverter converter = WhitespaceThrowablePatternConverter .newInstance(new DefaultConfiguration(), new String[] {}); @Test diff --git a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ExtractorTests.java b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ExtractorTests.java index b058a9dc26b..35f445bc000 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ExtractorTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ExtractorTests.java @@ -46,7 +46,7 @@ class ExtractorTests { } @Test - void stackTraceWhenNoPrinterPrintsUsingFallback() { + void stackTraceWhenNoPrinterPrintsUsingLoggingSystem() { Extractor extractor = new Extractor(null, createConverter()); assertThat(extractor.stackTrace(createEvent())).contains("java.lang.RuntimeException: Boom!"); } diff --git a/platform/spring-boot-dependencies/build.gradle b/platform/spring-boot-dependencies/build.gradle index bbeff402dd7..995e0d68a0b 100644 --- a/platform/spring-boot-dependencies/build.gradle +++ b/platform/spring-boot-dependencies/build.gradle @@ -1252,14 +1252,23 @@ bom { releaseNotes("https://github.com/liquibase/liquibase/releases/tag/v{version}") } } - library("Log4j2", "2.25.1") { + library("Log4j2", "2.24.3") { prohibit { contains "-alpha" contains "-beta" because "we don't want alphas or betas" } group("org.apache.logging.log4j") { - bom("log4j-bom") + bom("log4j-bom") { + permit("biz.aQute.bnd:biz.aQute.bnd.annotation") + permit("com.github.spotbugs:spotbugs-annotations") + permit("org.apache.logging:logging-parent") + permit("org.apache.maven.plugin-tools:maven-plugin-annotations") + permit("org.jspecify:jspecify") + permit("org.osgi:org.osgi.annotation.bundle") + permit("org.osgi:org.osgi.annotation.versioning") + permit("org.osgi:osgi.annotation") + } } links { site("https://logging.apache.org/log4j") diff --git a/smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/CustomStructuredLogFormatter.java b/smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/CustomStructuredLogFormatter.java index 239c433b6b5..2e7af6c1d80 100644 --- a/smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/CustomStructuredLogFormatter.java +++ b/smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/CustomStructuredLogFormatter.java @@ -16,10 +16,8 @@ package smoketest.structuredlogging.log4j2; -import java.io.PrintWriter; -import java.io.StringWriter; - import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ThrowableProxy; import org.jspecify.annotations.Nullable; import org.springframework.boot.logging.structured.StructuredLogFormatter; @@ -41,11 +39,9 @@ public class CustomStructuredLogFormatter implements StructuredLogFormatter