StructuredLogEncoderTests Class — spring-boot Architecture
Architecture documentation for the StructuredLogEncoderTests class in StructuredLogEncoderTests.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/test/java/org/springframework/boot/logging/logback/StructuredLogEncoderTests.java lines 46–229
class StructuredLogEncoderTests extends AbstractStructuredLoggingTests {
private StructuredLogEncoder encoder;
private Context loggerContext;
private MockEnvironment environment;
@Override
@BeforeEach
void setUp() {
super.setUp();
this.environment = new MockEnvironment();
this.environment.setProperty("logging.structured.json.stacktrace.printer",
SimpleStackTracePrinter.class.getName());
this.loggerContext = new ContextBase();
this.loggerContext.putObject(Environment.class.getName(), this.environment);
this.encoder = new StructuredLogEncoder();
this.encoder.setContext(this.loggerContext);
}
@Override
@AfterEach
void tearDown() {
super.tearDown();
this.encoder.stop();
}
@Test
@SuppressWarnings("unchecked")
void shouldSupportEcsCommonFormat() {
this.encoder.setFormat("ecs");
this.encoder.start();
LoggingEvent event = createEvent(new RuntimeException("Boom!"));
event.setMDCPropertyMap(Collections.emptyMap());
String json = encode(event);
Map<String, Object> deserialized = deserialize(json);
assertThat(deserialized).containsEntry("ecs", Map.of("version", "8.11"));
Map<String, Object> error = (Map<String, Object>) deserialized.get("error");
assertThat(error).isNotNull();
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
void shouldSupportLogstashCommonFormat() {
this.encoder.setFormat("logstash");
this.encoder.start();
LoggingEvent event = createEvent(new RuntimeException("Boom!"));
event.setMDCPropertyMap(Collections.emptyMap());
String json = encode(event);
Map<String, Object> deserialized = deserialize(json);
assertThat(deserialized).containsKey("@version");
assertThat(deserialized.get("stack_trace")).isEqualTo("stacktrace:RuntimeException");
}
@Test
void shouldSupportGelfCommonFormat() {
this.encoder.setFormat("gelf");
this.encoder.start();
LoggingEvent event = createEvent(new RuntimeException("Boom!"));
event.setMDCPropertyMap(Collections.emptyMap());
String json = encode(event);
Map<String, Object> deserialized = deserialize(json);
assertThat(deserialized).containsKey("version");
assertThat(deserialized.get("_error_stack_trace")).isEqualTo("stacktrace:RuntimeException");
}
@Test
void shouldSupportCustomFormat() {
this.encoder.setFormat(CustomLogbackStructuredLoggingFormatter.class.getName());
this.encoder.start();
LoggingEvent event = createEvent();
event.setMDCPropertyMap(Collections.emptyMap());
String format = encode(event);
assertThat(format).isEqualTo("custom-format");
}
@Test
void shouldInjectCustomFormatConstructorParameters() {
this.environment.setProperty("spring.application.pid", "42");
this.encoder.setFormat(CustomLogbackStructuredLoggingFormatterWithInjection.class.getName());
this.encoder.start();
LoggingEvent event = createEvent();
event.setMDCPropertyMap(Collections.emptyMap());
String format = encode(event);
assertThat(format).isEqualTo("custom-format-with-injection pid=42 hasThrowableProxyConverter=true");
}
@Test
void shouldCheckTypeArgument() {
assertThatIllegalStateException().isThrownBy(() -> {
this.encoder.setFormat(CustomLogbackStructuredLoggingFormatterWrongType.class.getName());
this.encoder.start();
}).withMessageContaining("must be ch.qos.logback.classic.spi.ILoggingEvent but was java.lang.String");
}
@Test
void shouldCheckTypeArgumentWithRawType() {
assertThatIllegalStateException().isThrownBy(() -> {
this.encoder.setFormat(CustomLogbackStructuredLoggingFormatterRawType.class.getName());
this.encoder.start();
}).withMessageContaining("must be ch.qos.logback.classic.spi.ILoggingEvent but was null");
}
@Test
void shouldFailIfNoCommonOrCustomFormatIsSet() {
assertThatIllegalArgumentException().isThrownBy(() -> {
this.encoder.setFormat("does-not-exist");
this.encoder.start();
})
.withMessageContaining("Unknown format 'does-not-exist'. Values can be a valid fully-qualified "
+ "class name or one of the common formats: [ecs, gelf, logstash]");
}
private String encode(LoggingEvent event) {
return new String(this.encoder.encode(event), StandardCharsets.UTF_8);
}
static final class CustomLogbackStructuredLoggingFormatter implements StructuredLogFormatter<ILoggingEvent> {
@Override
public String format(ILoggingEvent event) {
return "custom-format";
}
}
static final class CustomLogbackStructuredLoggingFormatterWithInjection
implements StructuredLogFormatter<ILoggingEvent> {
private final Environment environment;
private final ThrowableProxyConverter throwableProxyConverter;
CustomLogbackStructuredLoggingFormatterWithInjection(Environment environment,
ThrowableProxyConverter throwableProxyConverter) {
this.environment = environment;
this.throwableProxyConverter = throwableProxyConverter;
}
@Override
public String format(ILoggingEvent event) {
boolean hasThrowableProxyConverter = this.throwableProxyConverter != null;
return "custom-format-with-injection pid=" + this.environment.getProperty("spring.application.pid")
+ " hasThrowableProxyConverter=" + hasThrowableProxyConverter;
}
}
static final class CustomLogbackStructuredLoggingFormatterWrongType implements StructuredLogFormatter<String> {
@Override
public String format(String event) {
return event;
}
}
@SuppressWarnings("rawtypes")
static final class CustomLogbackStructuredLoggingFormatterRawType implements StructuredLogFormatter {
@Override
public String format(Object event) {
return "";
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free