Skip to content

Add support for multiple StructuredLoggingJsonMembersCustomizers #43368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
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 @@ -17,6 +17,7 @@
package org.springframework.boot.logging.structured;

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

import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.MemberCategory;
Expand All @@ -32,6 +33,7 @@
* {@link StructuredLoggingJsonPropertiesJsonMembersCustomizer}.
*
* @author Dmytro Nosan
* @author Yanming Zhou
*/
class StructuredLoggingJsonMembersCustomizerBeanFactoryInitializationAotProcessor
implements BeanFactoryInitializationAotProcessor {
Expand All @@ -49,19 +51,19 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL

private static final class AotContribution implements BeanFactoryInitializationAotContribution {

private final Class<? extends StructuredLoggingJsonMembersCustomizer<?>> customizer;
private final Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer;

private AotContribution(Class<? extends StructuredLoggingJsonMembersCustomizer<?>> customizer) {
private AotContribution(Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer) {
this.customizer = customizer;
}

@Override
public void applyTo(GenerationContext generationContext,
BeanFactoryInitializationCode beanFactoryInitializationCode) {
generationContext.getRuntimeHints()
this.customizer.forEach((it) -> generationContext.getRuntimeHints()
.reflection()
.registerType(this.customizer, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
.registerType(it, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
* @param customizer the fully qualified name of a
* {@link StructuredLoggingJsonMembersCustomizer}
* @author Phillip Webb
* @author Yanming Zhou
*/
record StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude, Map<String, String> rename,
Map<String, String> add, Class<? extends StructuredLoggingJsonMembersCustomizer<?>> customizer) {
Map<String, String> add, Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer) {

static StructuredLoggingJsonProperties get(Environment environment) {
return Binder.get(environment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.boot.logging.structured;

import java.util.Map;
import java.util.Set;

import org.springframework.boot.json.JsonWriter.MemberPath;
import org.springframework.boot.json.JsonWriter.Members;
Expand All @@ -28,6 +29,7 @@
* {@link StructuredLoggingJsonProperties}.
*
* @author Phillip Webb
* @author Yanming Zhou
*/
class StructuredLoggingJsonPropertiesJsonMembersCustomizer implements StructuredLoggingJsonMembersCustomizer<Object> {

Expand All @@ -49,9 +51,9 @@ public void customize(Members<Object> members) {
if (!CollectionUtils.isEmpty(add)) {
add.forEach(members::add);
}
Class<? extends StructuredLoggingJsonMembersCustomizer<?>> customizer = this.properties.customizer();
Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer = this.properties.customizer();
if (customizer != null) {
createAndApplyCustomizer(members, customizer);
customizer.forEach((c) -> createAndApplyCustomizer(members, c));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@
},
{
"name": "logging.structured.json.customizer",
"type": "java.lang.Class<? extends org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer<?>>",
"description": "The fully qualified class name of a StructuredLoggingJsonMembersCustomizer"
"type": "java.util.Set<java.lang.Class<? extends org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer<?>>>",
"description": "The fully qualified class names of a StructuredLoggingJsonMembersCustomizer"
},
{
"name": "logging.structured.json.exclude",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* Tests for {@link StructuredLoggingJsonPropertiesJsonMembersCustomizer}.
*
* @author Phillip Webb
* @author Yanming Zhou
*/
@ExtendWith(MockitoExtension.class)
class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
Expand Down Expand Up @@ -102,12 +103,25 @@ void customizeWhenHasCustomizerCustomizesMember() {
.applyingNameProcessor(NameProcessor.of(String::toUpperCase));
given(((Instantiator) this.instantiator).instantiateType(TestCustomizer.class)).willReturn(uppercaseCustomizer);
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), TestCustomizer.class);
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), Set.of(TestCustomizer.class));
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
this.instantiator, properties);
assertThat(writeSampleJson(customizer)).contains("\"A\":\"a\"");
}

@Test
@SuppressWarnings({ "rawtypes", "unchecked" })
void multipleCustomizers() {
given(((Instantiator) this.instantiator).instantiateType(FooCustomizer.class)).willReturn(new FooCustomizer());
given(((Instantiator) this.instantiator).instantiateType(BarCustomizer.class)).willReturn(new BarCustomizer());
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(),
Set.of(FooCustomizer.class, BarCustomizer.class));
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
this.instantiator, properties);
assertThat(writeSampleJson(customizer)).contains("\"foo\":\"foo\"").contains("\"bar\":\"bar\"");
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private String writeSampleJson(StructuredLoggingJsonMembersCustomizer customizer) {
return JsonWriter.of((members) -> {
Expand All @@ -126,4 +140,22 @@ public void customize(Members<String> members) {

}

static class FooCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {

@Override
public void customize(Members<String> members) {
members.add("foo", "foo");
}

}

static class BarCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {

@Override
public void customize(Members<String> members) {
members.add("bar", "bar");
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void getBindsFromEnvironment() {
environment.setProperty("logging.structured.json.customizer", TestCustomizer.class.getName());
StructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);
assertThat(properties).isEqualTo(new StructuredLoggingJsonProperties(Set.of("a", "b"), Set.of("c", "d"),
Map.of("e", "f"), Map.of("g", "h"), TestCustomizer.class));
Map.of("e", "f"), Map.of("g", "h"), Set.of(TestCustomizer.class)));
}

@Test
Expand All @@ -64,7 +64,7 @@ void shouldRegisterRuntimeHints() throws Exception {
assertThat(RuntimeHintsPredicates.reflection().onType(StructuredLoggingJsonProperties.class)).accepts(hints);
assertThat(RuntimeHintsPredicates.reflection()
.onConstructor(StructuredLoggingJsonProperties.class.getDeclaredConstructor(Set.class, Set.class, Map.class,
Map.class, Class.class))
Map.class, Set.class))
.invoke()).accepts(hints);
}

Expand Down
Loading