commit
4c72ce69da
|
@ -84,4 +84,5 @@
|
||||||
<suppress files="SpringBootBanner\.java" checks="SpringLeadingWhitespace" />
|
<suppress files="SpringBootBanner\.java" checks="SpringLeadingWhitespace" />
|
||||||
<suppress files="LoadTimeWeaverAwareConsumerContainers\.java" checks="InterfaceIsType" />
|
<suppress files="LoadTimeWeaverAwareConsumerContainers\.java" checks="InterfaceIsType" />
|
||||||
<suppress files="ConfigurationPropertyCaching\.java" checks="SpringJavadoc" message="\@since"/>
|
<suppress files="ConfigurationPropertyCaching\.java" checks="SpringJavadoc" message="\@since"/>
|
||||||
|
<suppress files="StructuredLoggingJsonMembersCustomizer\.java" checks="SpringJavadoc" message="\@since"/>
|
||||||
</suppressions>
|
</suppressions>
|
||||||
|
|
|
@ -49,8 +49,9 @@ import org.springframework.util.ObjectUtils;
|
||||||
class ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {
|
class ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {
|
||||||
|
|
||||||
ElasticCommonSchemaStructuredLogFormatter(Environment environment, StackTracePrinter stackTracePrinter,
|
ElasticCommonSchemaStructuredLogFormatter(Environment environment, StackTracePrinter stackTracePrinter,
|
||||||
ContextPairs contextPairs, StructuredLoggingJsonMembersCustomizer<?> customizer) {
|
ContextPairs contextPairs, StructuredLoggingJsonMembersCustomizer.Builder<?> customizerBuilder) {
|
||||||
super((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, members), customizer);
|
super((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, members),
|
||||||
|
customizerBuilder.nested().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void jsonMembers(Environment environment, StackTracePrinter stackTracePrinter,
|
private static void jsonMembers(Environment environment, StackTracePrinter stackTracePrinter,
|
||||||
|
|
|
@ -115,10 +115,10 @@ final class StructuredLogLayout extends AbstractStringLayout {
|
||||||
Environment environment = instantiator.getArg(Environment.class);
|
Environment environment = instantiator.getArg(Environment.class);
|
||||||
StackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);
|
StackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);
|
||||||
ContextPairs contextPairs = instantiator.getArg(ContextPairs.class);
|
ContextPairs contextPairs = instantiator.getArg(ContextPairs.class);
|
||||||
StructuredLoggingJsonMembersCustomizer<?> jsonMembersCustomizer = instantiator
|
StructuredLoggingJsonMembersCustomizer.Builder<?> jsonMembersCustomizerBuilder = instantiator
|
||||||
.getArg(StructuredLoggingJsonMembersCustomizer.class);
|
.getArg(StructuredLoggingJsonMembersCustomizer.Builder.class);
|
||||||
return new ElasticCommonSchemaStructuredLogFormatter(environment, stackTracePrinter, contextPairs,
|
return new ElasticCommonSchemaStructuredLogFormatter(environment, stackTracePrinter, contextPairs,
|
||||||
jsonMembersCustomizer);
|
jsonMembersCustomizerBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GraylogExtendedLogFormatStructuredLogFormatter createGraylogFormatter(Instantiator<?> instantiator) {
|
private GraylogExtendedLogFormatStructuredLogFormatter createGraylogFormatter(Instantiator<?> instantiator) {
|
||||||
|
|
|
@ -53,9 +53,9 @@ class ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogF
|
||||||
|
|
||||||
ElasticCommonSchemaStructuredLogFormatter(Environment environment, StackTracePrinter stackTracePrinter,
|
ElasticCommonSchemaStructuredLogFormatter(Environment environment, StackTracePrinter stackTracePrinter,
|
||||||
ContextPairs contextPairs, ThrowableProxyConverter throwableProxyConverter,
|
ContextPairs contextPairs, ThrowableProxyConverter throwableProxyConverter,
|
||||||
StructuredLoggingJsonMembersCustomizer<?> customizer) {
|
StructuredLoggingJsonMembersCustomizer.Builder<?> customizerBuilder) {
|
||||||
super((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, throwableProxyConverter, members),
|
super((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, throwableProxyConverter, members),
|
||||||
customizer);
|
customizerBuilder.nested().build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void jsonMembers(Environment environment, StackTracePrinter stackTracePrinter,
|
private static void jsonMembers(Environment environment, StackTracePrinter stackTracePrinter,
|
||||||
|
|
|
@ -93,10 +93,10 @@ public class StructuredLogEncoder extends EncoderBase<ILoggingEvent> {
|
||||||
StackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);
|
StackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);
|
||||||
ContextPairs contextParis = instantiator.getArg(ContextPairs.class);
|
ContextPairs contextParis = instantiator.getArg(ContextPairs.class);
|
||||||
ThrowableProxyConverter throwableProxyConverter = instantiator.getArg(ThrowableProxyConverter.class);
|
ThrowableProxyConverter throwableProxyConverter = instantiator.getArg(ThrowableProxyConverter.class);
|
||||||
StructuredLoggingJsonMembersCustomizer<?> jsonMembersCustomizer = instantiator
|
StructuredLoggingJsonMembersCustomizer.Builder<?> jsonMembersCustomizerBuilder = instantiator
|
||||||
.getArg(StructuredLoggingJsonMembersCustomizer.class);
|
.getArg(StructuredLoggingJsonMembersCustomizer.Builder.class);
|
||||||
return new ElasticCommonSchemaStructuredLogFormatter(environment, stackTracePrinter, contextParis,
|
return new ElasticCommonSchemaStructuredLogFormatter(environment, stackTracePrinter, contextParis,
|
||||||
throwableProxyConverter, jsonMembersCustomizer);
|
throwableProxyConverter, jsonMembersCustomizerBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructuredLogFormatter<ILoggingEvent> createGraylogFormatter(Instantiator<?> instantiator) {
|
private StructuredLogFormatter<ILoggingEvent> createGraylogFormatter(Instantiator<?> instantiator) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.core.env.Environment;
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link Environment}</li>
|
* <li>{@link Environment}</li>
|
||||||
* <li>{@link StructuredLoggingJsonMembersCustomizer}</li>
|
* <li>{@link StructuredLoggingJsonMembersCustomizer}</li>
|
||||||
|
* <li>{@link StructuredLoggingJsonMembersCustomizer.Builder}</li>
|
||||||
* <li>{@link StackTracePrinter} (may be {@code null})</li>
|
* <li>{@link StackTracePrinter} (may be {@code null})</li>
|
||||||
* <li>{@link ContextPairs}</li>
|
* <li>{@link ContextPairs}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.springframework.boot.logging.structured.StructuredLoggingJsonProperti
|
||||||
import org.springframework.boot.util.Instantiator;
|
import org.springframework.boot.util.Instantiator;
|
||||||
import org.springframework.boot.util.Instantiator.AvailableParameters;
|
import org.springframework.boot.util.Instantiator.AvailableParameters;
|
||||||
import org.springframework.boot.util.Instantiator.FailureHandler;
|
import org.springframework.boot.util.Instantiator.FailureHandler;
|
||||||
|
import org.springframework.boot.util.LambdaSafe;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||||
|
@ -85,7 +86,9 @@ public class StructuredLogFormatterFactory<E> {
|
||||||
this.instantiator = new Instantiator<>(Object.class, (allAvailableParameters) -> {
|
this.instantiator = new Instantiator<>(Object.class, (allAvailableParameters) -> {
|
||||||
allAvailableParameters.add(Environment.class, environment);
|
allAvailableParameters.add(Environment.class, environment);
|
||||||
allAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.class,
|
allAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.class,
|
||||||
(type) -> getStructuredLoggingJsonMembersCustomizer(properties));
|
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));
|
||||||
allAvailableParameters.add(ContextPairs.class, (type) -> getContextPairs(properties));
|
allAvailableParameters.add(ContextPairs.class, (type) -> getContextPairs(properties));
|
||||||
if (availableParameters != null) {
|
if (availableParameters != null) {
|
||||||
|
@ -96,30 +99,6 @@ public class StructuredLogFormatterFactory<E> {
|
||||||
commonFormatters.accept(this.commonFormatters);
|
commonFormatters.accept(this.commonFormatters);
|
||||||
}
|
}
|
||||||
|
|
||||||
StructuredLoggingJsonMembersCustomizer<?> getStructuredLoggingJsonMembersCustomizer(
|
|
||||||
StructuredLoggingJsonProperties properties) {
|
|
||||||
List<StructuredLoggingJsonMembersCustomizer<?>> customizers = new ArrayList<>();
|
|
||||||
if (properties != null) {
|
|
||||||
customizers.add(new StructuredLoggingJsonPropertiesJsonMembersCustomizer(this.instantiator, properties));
|
|
||||||
}
|
|
||||||
customizers.addAll(loadStructuredLoggingJsonMembersCustomizers());
|
|
||||||
return (members) -> invokeCustomizers(customizers, members);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
||||||
private List<StructuredLoggingJsonMembersCustomizer<?>> loadStructuredLoggingJsonMembersCustomizers() {
|
|
||||||
return (List) this.factoriesLoader.load(StructuredLoggingJsonMembersCustomizer.class,
|
|
||||||
ArgumentResolver.from(this.instantiator::getArg));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
||||||
private void invokeCustomizers(List<StructuredLoggingJsonMembersCustomizer<?>> customizers,
|
|
||||||
Members<Object> members) {
|
|
||||||
for (StructuredLoggingJsonMembersCustomizer<?> customizer : customizers) {
|
|
||||||
((StructuredLoggingJsonMembersCustomizer) customizer).customize(members);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private StackTracePrinter getStackTracePrinter(StructuredLoggingJsonProperties properties) {
|
private StackTracePrinter getStackTracePrinter(StructuredLoggingJsonProperties properties) {
|
||||||
return (properties != null && properties.stackTrace() != null) ? properties.stackTrace().createPrinter() : null;
|
return (properties != null && properties.stackTrace() != null) ? properties.stackTrace().createPrinter() : null;
|
||||||
}
|
}
|
||||||
|
@ -218,4 +197,53 @@ public class StructuredLogFormatterFactory<E> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link StructuredLoggingJsonMembersCustomizer.Builder} implementation.
|
||||||
|
*/
|
||||||
|
class JsonMembersCustomizerBuilder implements StructuredLoggingJsonMembersCustomizer.Builder<E> {
|
||||||
|
|
||||||
|
private final StructuredLoggingJsonProperties properties;
|
||||||
|
|
||||||
|
private boolean nested;
|
||||||
|
|
||||||
|
JsonMembersCustomizerBuilder(StructuredLoggingJsonProperties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonMembersCustomizerBuilder nested(boolean nested) {
|
||||||
|
this.nested = nested;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructuredLoggingJsonMembersCustomizer<E> build() {
|
||||||
|
return (members) -> {
|
||||||
|
List<StructuredLoggingJsonMembersCustomizer<?>> customizers = new ArrayList<>();
|
||||||
|
if (this.properties != null) {
|
||||||
|
customizers.add(new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
|
StructuredLogFormatterFactory.this.instantiator, this.properties, this.nested));
|
||||||
|
}
|
||||||
|
customizers.addAll(loadStructuredLoggingJsonMembersCustomizers());
|
||||||
|
invokeCustomizers(members, customizers);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
private List<StructuredLoggingJsonMembersCustomizer<?>> loadStructuredLoggingJsonMembersCustomizers() {
|
||||||
|
return (List) StructuredLogFormatterFactory.this.factoriesLoader.load(
|
||||||
|
StructuredLoggingJsonMembersCustomizer.class,
|
||||||
|
ArgumentResolver.from(StructuredLogFormatterFactory.this.instantiator::getArg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void invokeCustomizers(Members<E> members,
|
||||||
|
List<StructuredLoggingJsonMembersCustomizer<?>> customizers) {
|
||||||
|
LambdaSafe.callbacks(StructuredLoggingJsonMembersCustomizer.class, customizers, members)
|
||||||
|
.withFilter(LambdaSafe.Filter.allowAll())
|
||||||
|
.invoke((customizer) -> customizer.customize(members));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,4 +53,37 @@ public interface StructuredLoggingJsonMembersCustomizer<T> {
|
||||||
*/
|
*/
|
||||||
void customize(JsonWriter.Members<T> members);
|
void customize(JsonWriter.Members<T> members);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder that can be injected into a {@link StructuredLogFormatter} to build the
|
||||||
|
* {@link StructuredLoggingJsonMembersCustomizer} when specific settings are required.
|
||||||
|
*
|
||||||
|
* @param <T> the type being written
|
||||||
|
* @since 3.5.4
|
||||||
|
*/
|
||||||
|
interface Builder<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use nested fields when adding JSON from user defined properties.
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
default Builder<T> nested() {
|
||||||
|
return nested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if nested fields should be used when adding JSON from user defined
|
||||||
|
* properties.
|
||||||
|
* @param nested if nested fields are to be used
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
Builder<T> nested(boolean nested);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the {@link StructuredLoggingJsonMembersCustomizer}.
|
||||||
|
* @return the built customizer
|
||||||
|
*/
|
||||||
|
StructuredLoggingJsonMembersCustomizer<T> build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,13 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizer implements Structured
|
||||||
|
|
||||||
private final StructuredLoggingJsonProperties properties;
|
private final StructuredLoggingJsonProperties properties;
|
||||||
|
|
||||||
|
private final boolean nested;
|
||||||
|
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer(Instantiator<?> instantiator,
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer(Instantiator<?> instantiator,
|
||||||
StructuredLoggingJsonProperties properties) {
|
StructuredLoggingJsonProperties properties, boolean nested) {
|
||||||
this.instantiator = instantiator;
|
this.instantiator = instantiator;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
this.nested = nested;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,7 +51,13 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizer implements Structured
|
||||||
members.applyingNameProcessor(this::renameJsonMembers);
|
members.applyingNameProcessor(this::renameJsonMembers);
|
||||||
Map<String, String> add = this.properties.add();
|
Map<String, String> add = this.properties.add();
|
||||||
if (!CollectionUtils.isEmpty(add)) {
|
if (!CollectionUtils.isEmpty(add)) {
|
||||||
add.forEach(members::add);
|
if (this.nested) {
|
||||||
|
ContextPairs contextPairs = new ContextPairs(true, "");
|
||||||
|
members.add().usingPairs(contextPairs.nested((pairs) -> pairs.addMapEntries((source) -> add)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
add.forEach(members::add);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.properties.customizers(this.instantiator).forEach((customizer) -> customizer.customize(members));
|
this.properties.customizers(this.instantiator).forEach((customizer) -> customizer.customize(members));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import org.springframework.boot.logging.structured.MockStructuredLoggingJsonMembersCustomizerBuilder;
|
||||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -50,6 +51,9 @@ abstract class AbstractStructuredLoggingTests {
|
||||||
@Mock
|
@Mock
|
||||||
StructuredLoggingJsonMembersCustomizer<?> customizer;
|
StructuredLoggingJsonMembersCustomizer<?> customizer;
|
||||||
|
|
||||||
|
MockStructuredLoggingJsonMembersCustomizerBuilder<?> customizerBuilder = new MockStructuredLoggingJsonMembersCustomizerBuilder<>(
|
||||||
|
() -> this.customizer);
|
||||||
|
|
||||||
protected Map<String, Object> map(Object... values) {
|
protected Map<String, Object> map(Object... values) {
|
||||||
assertThat(values.length).isEven();
|
assertThat(values.length).isEven();
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
|
@ -56,7 +56,12 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL
|
||||||
this.environment.setProperty("logging.structured.ecs.service.node-name", "node-1");
|
this.environment.setProperty("logging.structured.ecs.service.node-name", "node-1");
|
||||||
this.environment.setProperty("spring.application.pid", "1");
|
this.environment.setProperty("spring.application.pid", "1");
|
||||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, null,
|
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, null,
|
||||||
TestContextPairs.include(), this.customizer);
|
TestContextPairs.include(), this.customizerBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void callsNestedOnCustomizerBuilder() {
|
||||||
|
assertThat(this.customizerBuilder.isNested()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -109,7 +114,7 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void shouldFormatExceptionUsingStackTracePrinter() {
|
void shouldFormatExceptionUsingStackTracePrinter() {
|
||||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, new SimpleStackTracePrinter(),
|
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, new SimpleStackTracePrinter(),
|
||||||
TestContextPairs.include(), this.customizer);
|
TestContextPairs.include(), this.customizerBuilder);
|
||||||
MutableLogEvent event = createEvent();
|
MutableLogEvent event = createEvent();
|
||||||
event.setThrown(new RuntimeException("Boom"));
|
event.setThrown(new RuntimeException("Boom"));
|
||||||
Map<String, Object> deserialized = deserialize(this.formatter.format(event));
|
Map<String, Object> deserialized = deserialize(this.formatter.format(event));
|
||||||
|
|
|
@ -72,6 +72,18 @@ class StructuredLogLayoutTests extends AbstractStructuredLoggingTests {
|
||||||
assertThat(error.get("stack_trace")).isEqualTo("stacktrace:RuntimeException");
|
assertThat(error.get("stack_trace")).isEqualTo("stacktrace:RuntimeException");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void shouldOutputNestedAdditionalEcsJson() {
|
||||||
|
this.environment.setProperty("logging.structured.json.add.extra.value", "test");
|
||||||
|
StructuredLogLayout layout = newBuilder().setFormat("ecs").build();
|
||||||
|
String json = layout.toSerializable(createEvent(new RuntimeException("Boom!")));
|
||||||
|
Map<String, Object> deserialized = deserialize(json);
|
||||||
|
assertThat(deserialized).containsKey("extra");
|
||||||
|
assertThat((Map<String, Object>) deserialized.get("extra")).containsEntry("value", "test");
|
||||||
|
System.out.println(deserialized);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldSupportLogstashCommonFormat() {
|
void shouldSupportLogstashCommonFormat() {
|
||||||
StructuredLogLayout layout = newBuilder().setFormat("logstash").build();
|
StructuredLogLayout layout = newBuilder().setFormat("logstash").build();
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.slf4j.Marker;
|
||||||
import org.slf4j.event.KeyValuePair;
|
import org.slf4j.event.KeyValuePair;
|
||||||
import org.slf4j.helpers.BasicMarkerFactory;
|
import org.slf4j.helpers.BasicMarkerFactory;
|
||||||
|
|
||||||
|
import org.springframework.boot.logging.structured.MockStructuredLoggingJsonMembersCustomizerBuilder;
|
||||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -62,6 +63,9 @@ abstract class AbstractStructuredLoggingTests {
|
||||||
@Mock
|
@Mock
|
||||||
StructuredLoggingJsonMembersCustomizer<?> customizer;
|
StructuredLoggingJsonMembersCustomizer<?> customizer;
|
||||||
|
|
||||||
|
MockStructuredLoggingJsonMembersCustomizerBuilder<?> customizerBuilder = new MockStructuredLoggingJsonMembersCustomizerBuilder<>(
|
||||||
|
() -> this.customizer);
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
this.markerFactory = new BasicMarkerFactory();
|
this.markerFactory = new BasicMarkerFactory();
|
||||||
|
|
|
@ -58,7 +58,12 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL
|
||||||
this.environment.setProperty("logging.structured.ecs.service.node-name", "node-1");
|
this.environment.setProperty("logging.structured.ecs.service.node-name", "node-1");
|
||||||
this.environment.setProperty("spring.application.pid", "1");
|
this.environment.setProperty("spring.application.pid", "1");
|
||||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, null,
|
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, null,
|
||||||
TestContextPairs.include(), getThrowableProxyConverter(), this.customizer);
|
TestContextPairs.include(), getThrowableProxyConverter(), this.customizerBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void callsNestedOnCustomizerBuilder() {
|
||||||
|
assertThat(this.customizerBuilder.isNested()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -115,7 +120,7 @@ class ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredL
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void shouldFormatExceptionUsingStackTracePrinter() {
|
void shouldFormatExceptionUsingStackTracePrinter() {
|
||||||
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, new SimpleStackTracePrinter(),
|
this.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, new SimpleStackTracePrinter(),
|
||||||
TestContextPairs.include(), getThrowableProxyConverter(), this.customizer);
|
TestContextPairs.include(), getThrowableProxyConverter(), this.customizerBuilder);
|
||||||
LoggingEvent event = createEvent();
|
LoggingEvent event = createEvent();
|
||||||
event.setMDCPropertyMap(Collections.emptyMap());
|
event.setMDCPropertyMap(Collections.emptyMap());
|
||||||
event.setThrowableProxy(new ThrowableProxy(new RuntimeException("Boom")));
|
event.setThrowableProxy(new ThrowableProxy(new RuntimeException("Boom")));
|
||||||
|
|
|
@ -85,6 +85,21 @@ class StructuredLogEncoderTests extends AbstractStructuredLoggingTests {
|
||||||
assertThat(error.get("stack_trace")).isEqualTo("stacktrace:RuntimeException");
|
assertThat(error.get("stack_trace")).isEqualTo("stacktrace:RuntimeException");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void shouldOutputNestedAdditionalEcsJson() {
|
||||||
|
this.environment.setProperty("logging.structured.json.add.extra.value", "test");
|
||||||
|
this.encoder.setFormat("ecs");
|
||||||
|
this.encoder.start();
|
||||||
|
LoggingEvent event = createEvent();
|
||||||
|
event.setMDCPropertyMap(Collections.emptyMap());
|
||||||
|
String json = encode(event);
|
||||||
|
Map<String, Object> deserialized = deserialize(json);
|
||||||
|
assertThat(deserialized).containsKey("extra");
|
||||||
|
assertThat((Map<String, Object>) deserialized.get("extra")).containsEntry("value", "test");
|
||||||
|
System.out.println(deserialized);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldSupportLogstashCommonFormat() {
|
void shouldSupportLogstashCommonFormat() {
|
||||||
this.encoder.setFormat("logstash");
|
this.encoder.setFormat("logstash");
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-present the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.logging.structured;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer.Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock {@link StructuredLoggingJsonMembersCustomizer.Builder}.
|
||||||
|
*
|
||||||
|
* @param <T> the type being written
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class MockStructuredLoggingJsonMembersCustomizerBuilder<T>
|
||||||
|
implements StructuredLoggingJsonMembersCustomizer.Builder<T> {
|
||||||
|
|
||||||
|
private final Supplier<StructuredLoggingJsonMembersCustomizer<T>> customizerSupplier;
|
||||||
|
|
||||||
|
public MockStructuredLoggingJsonMembersCustomizerBuilder(
|
||||||
|
Supplier<StructuredLoggingJsonMembersCustomizer<T>> customizerSupplier) {
|
||||||
|
this.customizerSupplier = customizerSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean nested;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder<T> nested(boolean nested) {
|
||||||
|
this.nested = nested;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNested() {
|
||||||
|
return this.nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructuredLoggingJsonMembersCustomizer<T> build() {
|
||||||
|
return this.customizerSupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -51,7 +51,7 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
||||||
Set.of("a"), Collections.emptyMap(), Collections.emptyMap(), null, null, null);
|
Set.of("a"), Collections.emptyMap(), Collections.emptyMap(), null, null, null);
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).doesNotContain("a").contains("b");
|
assertThat(writeSampleJson(customizer)).doesNotContain("a").contains("b");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Set.of("a"),
|
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Set.of("a"),
|
||||||
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null, null);
|
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null, null);
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).contains("a")
|
assertThat(writeSampleJson(customizer)).contains("a")
|
||||||
.doesNotContain("b")
|
.doesNotContain("b")
|
||||||
.doesNotContain("c")
|
.doesNotContain("c")
|
||||||
|
@ -72,7 +72,7 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Set.of("a", "b"), Set.of("b"),
|
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Set.of("a", "b"), Set.of("b"),
|
||||||
Collections.emptyMap(), Collections.emptyMap(), null, null, null);
|
Collections.emptyMap(), Collections.emptyMap(), null, null, null);
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).contains("a")
|
assertThat(writeSampleJson(customizer)).contains("a")
|
||||||
.doesNotContain("b")
|
.doesNotContain("b")
|
||||||
.doesNotContain("c")
|
.doesNotContain("c")
|
||||||
|
@ -84,7 +84,7 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
||||||
Collections.emptySet(), Map.of("a", "z"), Collections.emptyMap(), null, null, null);
|
Collections.emptySet(), Map.of("a", "z"), Collections.emptyMap(), null, null, null);
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).contains("\"z\":\"a\"");
|
assertThat(writeSampleJson(customizer)).contains("\"z\":\"a\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,10 +93,19 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
||||||
Collections.emptySet(), Collections.emptyMap(), Map.of("z", "z"), null, null, null);
|
Collections.emptySet(), Collections.emptyMap(), Map.of("z", "z"), null, null, null);
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).contains("\"z\":\"z\"");
|
assertThat(writeSampleJson(customizer)).contains("\"z\":\"z\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void customizeWhenHasNestedAddAddsMember() {
|
||||||
|
StructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),
|
||||||
|
Collections.emptySet(), Collections.emptyMap(), Map.of("y.z", "yz"), null, null, null);
|
||||||
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
|
this.instantiator, properties, true);
|
||||||
|
assertThat(writeSampleJson(customizer)).contains("\"y\":{\"z\":\"yz\"}");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void customizeWhenHasCustomizerCustomizesMember() {
|
void customizeWhenHasCustomizerCustomizesMember() {
|
||||||
|
@ -107,7 +116,7 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null,
|
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null,
|
||||||
Set.of(TestCustomizer.class));
|
Set.of(TestCustomizer.class));
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).contains("\"A\":\"a\"");
|
assertThat(writeSampleJson(customizer)).contains("\"A\":\"a\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +129,7 @@ class StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {
|
||||||
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null,
|
Collections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null,
|
||||||
Set.of(FooCustomizer.class, BarCustomizer.class));
|
Set.of(FooCustomizer.class, BarCustomizer.class));
|
||||||
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
StructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(
|
||||||
this.instantiator, properties);
|
this.instantiator, properties, false);
|
||||||
assertThat(writeSampleJson(customizer)).contains("\"foo\":\"foo\"").contains("\"bar\":\"bar\"");
|
assertThat(writeSampleJson(customizer)).contains("\"foo\":\"foo\"").contains("\"bar\":\"bar\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue