From 686db1e0a5f3d903c64b121be54b3f66f58d1918 Mon Sep 17 00:00:00 2001 From: Mike Heath Date: Wed, 6 May 2026 12:07:39 -0600 Subject: [PATCH] Allow Environment to be passed to custom StackTracePrinter instances See gh-50303 Signed-off-by: mheath --- .../StructuredLogFormatterFactory.java | 9 ++++--- .../StructuredLoggingJsonProperties.java | 9 ++++--- .../StructuredLoggingJsonPropertiesTests.java | 27 ++++++++++--------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java index 3d56c441c07..577aa3cc7dd 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java @@ -89,7 +89,8 @@ public class StructuredLogFormatterFactory { new JsonMembersCustomizerBuilder(properties).build()); allAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.Builder.class, new JsonMembersCustomizerBuilder(properties)); - allAvailableParameters.add(StackTracePrinter.class, (type) -> getStackTracePrinter(properties)); + allAvailableParameters.add(StackTracePrinter.class, + (type) -> getStackTracePrinter(properties, environment)); allAvailableParameters.add(ContextPairs.class, (type) -> getContextPairs(properties)); if (availableParameters != null) { availableParameters.accept(allAvailableParameters); @@ -99,8 +100,10 @@ public class StructuredLogFormatterFactory { commonFormatters.accept(this.commonFormatters); } - private StackTracePrinter getStackTracePrinter(StructuredLoggingJsonProperties properties) { - return (properties != null && properties.stackTrace() != null) ? properties.stackTrace().createPrinter() : null; + private StackTracePrinter getStackTracePrinter(StructuredLoggingJsonProperties properties, + Environment environment) { + return (properties != null && properties.stackTrace() != null) + ? properties.stackTrace().createPrinter(environment) : null; } private ContextPairs getContextPairs(StructuredLoggingJsonProperties properties) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonProperties.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonProperties.java index 87380ccfb7e..5cef73c8f97 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonProperties.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonProperties.java @@ -90,7 +90,7 @@ record StructuredLoggingJsonProperties(Set include, Set exclude, record StackTrace(String printer, Root root, Integer maxLength, Integer maxThrowableDepth, Boolean includeCommonFrames, Boolean includeHashes) { - StackTracePrinter createPrinter() { + StackTracePrinter createPrinter(Environment environment) { String name = sanitizePrinter(); if ("loggingsystem".equals(name) || (name.isEmpty() && !hasAnyOtherProperty())) { return null; @@ -99,9 +99,10 @@ record StructuredLoggingJsonProperties(Set include, Set exclude, if ("standard".equals(name) || name.isEmpty()) { return standardPrinter; } - return (StackTracePrinter) new Instantiator<>(StackTracePrinter.class, - (parameters) -> parameters.add(StandardStackTracePrinter.class, standardPrinter)) - .instantiate(printer()); + return (StackTracePrinter) new Instantiator<>(StackTracePrinter.class, (parameters) -> { + parameters.add(StandardStackTracePrinter.class, standardPrinter); + parameters.add(Environment.class, environment); + }).instantiate(printer()); } boolean hasCustomPrinter() { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java index f65faa47323..3d02c108ed6 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java @@ -35,6 +35,7 @@ import org.springframework.boot.logging.structured.StructuredLoggingJsonProperti import org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace; import org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace.Root; import org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StructuredLoggingJsonPropertiesRuntimeHints; +import org.springframework.core.env.Environment; import org.springframework.mock.env.MockEnvironment; import org.springframework.util.ClassUtils; @@ -115,44 +116,44 @@ class StructuredLoggingJsonPropertiesTests { @Test void createPrinterWhenEmptyReturnsNull() { StackTrace properties = new StackTrace(null, null, null, null, null, null); - assertThat(properties.createPrinter()).isNull(); + assertThat(properties.createPrinter(new MockEnvironment())).isNull(); } @Test void createPrinterWhenNoPrinterAndNotEmptyReturnsStandard() { StackTrace properties = new StackTrace(null, Root.LAST, null, null, null, null); - assertThat(properties.createPrinter()).isInstanceOf(StandardStackTracePrinter.class); + assertThat(properties.createPrinter(new MockEnvironment())).isInstanceOf(StandardStackTracePrinter.class); } @Test void createPrinterWhenLoggingSystemReturnsNull() { StackTrace properties = new StackTrace("logging-system", null, null, null, null, null); - assertThat(properties.createPrinter()).isNull(); + assertThat(properties.createPrinter(new MockEnvironment())).isNull(); } @Test void createPrinterWhenLoggingSystemRelaxedReturnsNull() { StackTrace properties = new StackTrace("LoggingSystem", null, null, null, null, null); - assertThat(properties.createPrinter()).isNull(); + assertThat(properties.createPrinter(new MockEnvironment())).isNull(); } @Test void createPrinterWhenStandardReturnsStandardPrinter() { StackTrace properties = new StackTrace("standard", null, null, null, null, null); - assertThat(properties.createPrinter()).isInstanceOf(StandardStackTracePrinter.class); + assertThat(properties.createPrinter(new MockEnvironment())).isInstanceOf(StandardStackTracePrinter.class); } @Test void createPrinterWhenStandardRelaxedReturnsStandardPrinter() { StackTrace properties = new StackTrace("STANDARD", null, null, null, null, null); - assertThat(properties.createPrinter()).isInstanceOf(StandardStackTracePrinter.class); + assertThat(properties.createPrinter(new MockEnvironment())).isInstanceOf(StandardStackTracePrinter.class); } @Test void createPrinterWhenStandardAppliesCustomizations() { Exception exception = TestException.create(); StackTrace properties = new StackTrace(null, Root.FIRST, 300, 2, true, false); - StackTracePrinter printer = ((StandardStackTracePrinter) properties.createPrinter()) + StackTracePrinter printer = ((StandardStackTracePrinter) properties.createPrinter(new MockEnvironment())) .withLineSeparator("\n"); String actual = TestException.withoutLineNumbers(printer.printStackTraceToString(exception)); assertThat(actual).isEqualToNormalizingNewlines(""" @@ -167,7 +168,7 @@ class StructuredLoggingJsonPropertiesTests { void createPrinterWhenStandardWithHashesPrintsHash() { Exception exception = TestException.create(); StackTrace properties = new StackTrace(null, null, null, null, null, true); - StackTracePrinter printer = properties.createPrinter(); + StackTracePrinter printer = properties.createPrinter(new MockEnvironment()); String actual = printer.printStackTraceToString(exception); assertThat(actual).containsPattern("<#[0-9a-z]{8}>"); } @@ -176,16 +177,18 @@ class StructuredLoggingJsonPropertiesTests { void createPrinterWhenClassNameCreatesPrinter() { Exception exception = TestException.create(); StackTrace properties = new StackTrace(TestStackTracePrinter.class.getName(), null, null, null, true, null); - StackTracePrinter printer = properties.createPrinter(); + StackTracePrinter printer = properties.createPrinter(new MockEnvironment()); assertThat(printer.printStackTraceToString(exception)).isEqualTo("java.lang.RuntimeException: exception"); } @Test void createPrinterWhenClassNameInjectsConfiguredPrinter() { Exception exception = TestException.create(); + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("stracktracelineseparator", "!"); StackTrace properties = new StackTrace(TestStackTracePrinterCustomized.class.getName(), Root.FIRST, 300, 2, true, null); - StackTracePrinter printer = properties.createPrinter(); + StackTracePrinter printer = properties.createPrinter(environment); String actual = TestException.withoutLineNumbers(printer.printStackTraceToString(exception)); assertThat(actual).isEqualTo("RuntimeExceptionroot! at org.springfr..."); } @@ -237,9 +240,9 @@ class StructuredLoggingJsonPropertiesTests { private final StandardStackTracePrinter printer; - TestStackTracePrinterCustomized(StandardStackTracePrinter printer) { + TestStackTracePrinterCustomized(StandardStackTracePrinter printer, Environment environment) { this.printer = printer.withMaximumLength(40) - .withLineSeparator("!") + .withLineSeparator(environment.getProperty("stracktracelineseparator", "\n")) .withFormatter((throwable) -> ClassUtils.getShortName(throwable.getClass()) + throwable.getMessage()); }