Add RuntimeHints for StackTracePrinter
See gh-44242 Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
This commit is contained in:
parent
9f920be87c
commit
5d781ffcbb
|
@ -87,8 +87,7 @@ record StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude,
|
|||
Boolean includeCommonFrames, Boolean includeHashes) {
|
||||
|
||||
StackTracePrinter createPrinter() {
|
||||
String name = (printer() != null) ? printer() : "";
|
||||
name = name.toLowerCase(Locale.getDefault()).replace("-", "");
|
||||
String name = getPrinter();
|
||||
if ("loggingsystem".equals(name) || (name.isEmpty() && !hasAnyOtherProperty())) {
|
||||
return null;
|
||||
}
|
||||
|
@ -101,6 +100,18 @@ record StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude,
|
|||
.instantiate(printer());
|
||||
}
|
||||
|
||||
boolean hasCustomPrinter() {
|
||||
String name = getPrinter();
|
||||
if (name.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return !("loggingsystem".equals(name) || "standard".equals(name));
|
||||
}
|
||||
|
||||
private String getPrinter() {
|
||||
return Objects.toString(printer(), "").toLowerCase(Locale.ROOT).replace("-", "");
|
||||
}
|
||||
|
||||
private boolean hasAnyOtherProperty() {
|
||||
return Stream.of(root(), maxLength(), maxThrowableDepth(), includeCommonFrames(), includeHashes())
|
||||
.anyMatch(Objects::nonNull);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.boot.logging.structured;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
|
@ -26,6 +27,7 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContrib
|
|||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
|
@ -36,7 +38,7 @@ import org.springframework.core.env.Environment;
|
|||
* @author Yanming Zhou
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor
|
||||
class StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor
|
||||
implements BeanFactoryInitializationAotProcessor {
|
||||
|
||||
private static final String ENVIRONMENT_BEAN_NAME = "environment";
|
||||
|
@ -45,15 +47,19 @@ class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcesso
|
|||
public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
|
||||
Environment environment = beanFactory.getBean(ENVIRONMENT_BEAN_NAME, Environment.class);
|
||||
StructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);
|
||||
return (properties != null) ? AotContribution.get(properties.customizer()) : null;
|
||||
return (properties != null) ? AotContribution.get(properties) : null;
|
||||
}
|
||||
|
||||
private static final class AotContribution implements BeanFactoryInitializationAotContribution {
|
||||
|
||||
private final Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers;
|
||||
|
||||
private AotContribution(Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers) {
|
||||
private final String stackTracePrinter;
|
||||
|
||||
private AotContribution(Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers,
|
||||
String stackTracePrinter) {
|
||||
this.customizers = customizers;
|
||||
this.stackTracePrinter = stackTracePrinter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,10 +68,26 @@ class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcesso
|
|||
ReflectionHints reflection = generationContext.getRuntimeHints().reflection();
|
||||
this.customizers.forEach((customizer) -> reflection.registerType(customizer,
|
||||
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
|
||||
if (this.stackTracePrinter != null) {
|
||||
reflection.registerTypeIfPresent(getClass().getClassLoader(), this.stackTracePrinter,
|
||||
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
}
|
||||
}
|
||||
|
||||
static AotContribution get(Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers) {
|
||||
return (!customizers.isEmpty()) ? new AotContribution(customizers) : null;
|
||||
static AotContribution get(StructuredLoggingJsonProperties properties) {
|
||||
Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers = properties.customizer();
|
||||
String stackTracePrinter = getStackTracePrinter(properties);
|
||||
if (stackTracePrinter == null && customizers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new AotContribution(customizers, stackTracePrinter);
|
||||
}
|
||||
|
||||
private static String getStackTracePrinter(StructuredLoggingJsonProperties properties) {
|
||||
return Optional.ofNullable(properties.stackTrace())
|
||||
.filter(StackTrace::hasCustomPrinter)
|
||||
.map(StackTrace::printer)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,7 @@ org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\
|
|||
org.springframework.boot.context.properties.ConfigurationPropertiesBeanFactoryInitializationAotProcessor,\
|
||||
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.EnvironmentBeanFactoryInitializationAotProcessor,\
|
||||
org.springframework.boot.jackson.JsonComponentModule.JsonComponentBeanFactoryInitializationAotProcessor,\
|
||||
org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor
|
||||
org.springframework.boot.logging.structured.StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor
|
||||
|
||||
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
|
||||
org.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrationAotProcessor,\
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
|
||||
package org.springframework.boot.logging.structured;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
|
@ -26,6 +30,7 @@ import org.springframework.beans.factory.aot.AotServices;
|
|||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
|
||||
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
|
||||
import org.springframework.boot.json.JsonWriter.Members;
|
||||
import org.springframework.boot.logging.StackTracePrinter;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
@ -33,21 +38,20 @@ import org.springframework.mock.env.MockEnvironment;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for
|
||||
* {@link StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor}.
|
||||
* Tests for {@link StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor}.
|
||||
*
|
||||
* @author Dmytro Nosan
|
||||
*/
|
||||
class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessorTests {
|
||||
class StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests {
|
||||
|
||||
@Test
|
||||
void structuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessorIsRegistered() {
|
||||
void structuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorIsRegistered() {
|
||||
assertThat(AotServices.factories().load(BeanFactoryInitializationAotProcessor.class))
|
||||
.anyMatch(StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor.class::isInstance);
|
||||
.anyMatch(StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor.class::isInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRegisterStructuredLoggingJsonMembersCustomizerRuntimeHints() {
|
||||
void shouldRegisterRuntimeHintsWhenCustomizerIsPresent() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("logging.structured.json.customizer", TestCustomizer.class.getName());
|
||||
|
||||
|
@ -63,14 +67,40 @@ class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcesso
|
|||
}
|
||||
|
||||
@Test
|
||||
void shouldNotRegisterStructuredLoggingJsonMembersCustomizerRuntimeHintsWhenPropertiesAreNotSet() {
|
||||
void shouldRegisterRuntimeHintsWhenStackTracePrinterIsPresent() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("logging.structured.json.stacktrace.printer", TestStackTracePrinter.class.getName());
|
||||
|
||||
BeanFactoryInitializationAotContribution contribution = getContribution(environment);
|
||||
assertThat(contribution).isNotNull();
|
||||
|
||||
RuntimeHints hints = getRuntimeHints(contribution);
|
||||
assertThat(RuntimeHintsPredicates.reflection()
|
||||
.onType(TestStackTracePrinter.class)
|
||||
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
|
||||
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS))
|
||||
.accepts(hints);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "logging-system", "standard" })
|
||||
void shouldNotRegisterRuntimeHintsWhenStackTracePrinterIsNotCustomImplementation(String printer) {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("logging.structured.json.stacktrace.printer", printer);
|
||||
|
||||
BeanFactoryInitializationAotContribution contribution = getContribution(environment);
|
||||
assertThat(contribution).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotRegisterRuntimeHintsWhenPropertiesAreNotSet() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
BeanFactoryInitializationAotContribution contribution = getContribution(environment);
|
||||
assertThat(contribution).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotRegisterStructuredLoggingJsonMembersCustomizerRuntimeHintsWhenCustomizerIsNotSet() {
|
||||
void shouldNotRegisterRuntimeHintsWhenCustomizerAndPrinterAreNotSet() {
|
||||
MockEnvironment environment = new MockEnvironment();
|
||||
environment.setProperty("logging.structured.json.exclude", "something");
|
||||
BeanFactoryInitializationAotContribution contribution = getContribution(environment);
|
||||
|
@ -81,7 +111,7 @@ class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcesso
|
|||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.setEnvironment(environment);
|
||||
context.refresh();
|
||||
return new StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor()
|
||||
return new StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor()
|
||||
.processAheadOfTime(context.getBeanFactory());
|
||||
}
|
||||
}
|
||||
|
@ -100,4 +130,13 @@ class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcesso
|
|||
|
||||
}
|
||||
|
||||
static class TestStackTracePrinter implements StackTracePrinter {
|
||||
|
||||
@Override
|
||||
public void printStackTrace(Throwable throwable, Appendable out) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -93,6 +93,10 @@ class StructuredLoggingJsonPropertiesTests {
|
|||
.onConstructor(StructuredLoggingJsonProperties.class.getDeclaredConstructor(Set.class, Set.class, Map.class,
|
||||
Map.class, StackTrace.class, Set.class))
|
||||
.invoke()).accepts(hints);
|
||||
assertThat(RuntimeHintsPredicates.reflection()
|
||||
.onConstructor(StackTrace.class.getDeclaredConstructor(String.class, Root.class, Integer.class,
|
||||
Integer.class, Boolean.class, Boolean.class))
|
||||
.invoke()).accepts(hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -184,6 +188,30 @@ class StructuredLoggingJsonPropertiesTests {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnFalseWhenPrinterIsEmpty() {
|
||||
StackTrace stackTrace = new StackTrace("", null, null, null, null, null);
|
||||
assertThat(stackTrace.hasCustomPrinter()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasCustomPrinterShouldReturnFalseWhenPrinterHasLoggingSystem() {
|
||||
StackTrace stackTrace = new StackTrace("loggingsystem", null, null, null, null, null);
|
||||
assertThat(stackTrace.hasCustomPrinter()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasCustomPrinterShouldReturnFalseWhenPrinterHasStandard() {
|
||||
StackTrace stackTrace = new StackTrace("standard", null, null, null, null, null);
|
||||
assertThat(stackTrace.hasCustomPrinter()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasCustomPrinterShouldReturnTrueWhenPrinterHasCustom() {
|
||||
StackTrace stackTrace = new StackTrace("custom-printer", null, null, null, null, null);
|
||||
assertThat(stackTrace.hasCustomPrinter()).isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {
|
||||
|
|
Loading…
Reference in New Issue