Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ record StackTrace(String printer, Root root, Integer maxLength, Integer maxThrow
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;
}
Expand All @@ -101,6 +100,18 @@ StackTracePrinter createPrinter() {
.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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.boot.logging.structured;

import java.util.Optional;
import java.util.Set;

import org.springframework.aot.generate.GenerationContext;
Expand All @@ -26,6 +27,7 @@
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;

/**
Expand All @@ -36,7 +38,7 @@
* @author Yanming Zhou
* @author Phillip Webb
*/
class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor
class StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor
implements BeanFactoryInitializationAotProcessor {

private static final String ENVIRONMENT_BEAN_NAME = "environment";
Expand All @@ -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
Expand All @@ -62,10 +68,26 @@ public void applyTo(GenerationContext generationContext,
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(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);
}

static AotContribution get(Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers) {
return (!customizers.isEmpty()) ? new AotContribution(customizers) : null;
private static String getStackTracePrinter(StructuredLoggingJsonProperties properties) {
return Optional.ofNullable(properties.stackTrace())
.filter(StackTrace::hasCustomPrinter)
.map(StackTrace::printer)
.orElse(null);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,28 +30,28 @@
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;

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());

Expand All @@ -63,14 +67,40 @@ void shouldRegisterStructuredLoggingJsonMembersCustomizerRuntimeHints() {
}

@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 shouldNotRegisterStructuredLoggingJsonMembersCustomizerRuntimeHintsWhenCustomizerIsNotSet() {
void shouldNotRegisterRuntimeHintsWhenPropertiesAreNotSet() {
MockEnvironment environment = new MockEnvironment();
BeanFactoryInitializationAotContribution contribution = getContribution(environment);
assertThat(contribution).isNull();
}

@Test
void shouldNotRegisterRuntimeHintsWhenCustomizerAndPrinterAreNotSet() {
MockEnvironment environment = new MockEnvironment();
environment.setProperty("logging.structured.json.exclude", "something");
BeanFactoryInitializationAotContribution contribution = getContribution(environment);
Expand All @@ -81,7 +111,7 @@ private BeanFactoryInitializationAotContribution getContribution(ConfigurableEnv
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
context.setEnvironment(environment);
context.refresh();
return new StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor()
return new StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor()
.processAheadOfTime(context.getBeanFactory());
}
}
Expand All @@ -100,4 +130,13 @@ public void customize(Members<String> members) {

}

static class TestStackTracePrinter implements StackTracePrinter {

@Override
public void printStackTrace(Throwable throwable, Appendable out) throws IOException {

}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ void shouldRegisterRuntimeHints() throws Exception {
.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
Expand Down Expand Up @@ -184,6 +188,30 @@ void createPrinterWhenClassNameInjectsConfiguredPrinter() {

}

@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> {
Expand Down