From fbd7aa91a4b0a18e229317e17bf9f2aaf1554478 Mon Sep 17 00:00:00 2001 From: Daniel Flassak Date: Fri, 29 Nov 2024 15:38:45 +0100 Subject: [PATCH] update dependencies and serialize Optional properly --- pom.xml | 52 +-- .../dm/prom/structuredlogging/MdcContext.java | 60 ++-- .../prom/structuredlogging/ExampleBean.java | 5 + .../structuredlogging/MdcContextUnitTest.java | 335 +++++++++--------- .../StructuredMdcJsonProviderUnitTest.java | 57 +-- 5 files changed, 269 insertions(+), 240 deletions(-) diff --git a/pom.xml b/pom.xml index f9c321b..2322017 100644 --- a/pom.xml +++ b/pom.xml @@ -41,34 +41,39 @@ net.logstash.logback logstash-logback-encoder - 7.4 + 8.0 org.projectlombok lombok - 1.18.30 + 1.18.36 provided org.slf4j slf4j-api - 2.0.9 + 2.0.16 ch.qos.logback logback-classic - 1.4.14 + 1.5.11 + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + 2.18.2 org.springframework spring-core - 6.1.1 + 6.1.14 true org.springframework.boot spring-boot - 3.2.0 + 3.4.0 true compile @@ -77,31 +82,31 @@ org.springframework.boot spring-boot-starter-test - 3.2.0 + 3.4.0 test org.junit.jupiter junit-jupiter-engine - 5.10.1 + 5.10.5 test org.junit.jupiter junit-jupiter-api - 5.10.1 + 5.10.5 test org.assertj assertj-core - 3.24.2 + 3.25.3 test org.mockito mockito-core - 5.8.0 + 5.11.0 test @@ -118,7 +123,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.13.0 ${java.version} ${java.version} @@ -130,7 +135,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.3.1 + 3.6.0 checkstyle.xml true @@ -141,7 +146,7 @@ com.puppycrawl.tools checkstyle - 10.12.5 + 10.20.1 @@ -157,12 +162,12 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.2 + 3.5.2 org.apache.maven.plugins maven-release-plugin - 3.0.1 + 3.1.1 @{project.version} @@ -170,7 +175,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 + 1.7.0 true ossrh @@ -192,12 +197,12 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.3.1 org.apache.maven.plugins maven-javadoc-plugin - 3.6.3 + 3.11.1 ${java.version} ${encoding} @@ -222,7 +227,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.1.0 + 3.2.7 sign-artifacts @@ -296,5 +301,12 @@ scm:git:ssh://git@github.com/dm-drogeriemarkt/structured-logging.git http://github.com/dm-drogeriemarkt/structured-logging/tree/master + + + maven_central + Maven Central + https://repo.maven.apache.org/maven2/ + + diff --git a/src/main/java/de/dm/prom/structuredlogging/MdcContext.java b/src/main/java/de/dm/prom/structuredlogging/MdcContext.java index 8728d22..7a1bce7 100644 --- a/src/main/java/de/dm/prom/structuredlogging/MdcContext.java +++ b/src/main/java/de/dm/prom/structuredlogging/MdcContext.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; @@ -29,28 +30,34 @@ */ @Slf4j public final class MdcContext implements java.io.Closeable { - private final String oldValue; //MDC value outside this context - private final String key; - private static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper(); private static Optional customObjectMapper = Optional.empty(); static { SimpleModule module = new SimpleModule(); - module.addSerializer(Instant.class, new ToStringSerializer()); - module.addSerializer(LocalDate.class, new ToStringSerializer()); - module.addSerializer(LocalDateTime.class, new ToStringSerializer()); - module.addSerializer(OffsetDateTime.class, new ToStringSerializer()); - module.addSerializer(OffsetTime.class, new ToStringSerializer()); - module.addSerializer(Period.class, new ToStringSerializer()); - module.addSerializer(ZonedDateTime.class, new ToStringSerializer()); - module.addSerializer(LocalTime.class, new ToStringSerializer()); - module.addSerializer(Duration.class, new ToStringSerializer()); - module.addSerializer(MonthDay.class, new ToStringSerializer()); - module.addSerializer(Year.class, new ToStringSerializer()); - module.addSerializer(YearMonth.class, new ToStringSerializer()); + module.addSerializer(Instant.class, ToStringSerializer.instance); + module.addSerializer(LocalDate.class, ToStringSerializer.instance); + module.addSerializer(LocalDateTime.class, ToStringSerializer.instance); + module.addSerializer(OffsetDateTime.class, ToStringSerializer.instance); + module.addSerializer(OffsetTime.class, ToStringSerializer.instance); + module.addSerializer(Period.class, ToStringSerializer.instance); + module.addSerializer(ZonedDateTime.class, ToStringSerializer.instance); + module.addSerializer(LocalTime.class, ToStringSerializer.instance); + module.addSerializer(Duration.class, ToStringSerializer.instance); + module.addSerializer(MonthDay.class, ToStringSerializer.instance); + module.addSerializer(Year.class, ToStringSerializer.instance); + module.addSerializer(YearMonth.class, ToStringSerializer.instance); DEFAULT_OBJECT_MAPPER.registerModule(module); + DEFAULT_OBJECT_MAPPER.registerModule(new Jdk8Module()); + } + + private final String oldValue; //MDC value outside this context + private final String key; + + private MdcContext(String key, Object value) { + this.key = key; + oldValue = putToMDCwithOverwriteWarning(key, toJson(value)); } /** @@ -288,20 +295,6 @@ public static void update(Object mdcValue) { updateMdcContent(mdcValue.getClass().getSimpleName(), toJson(mdcValue)); } - private MdcContext(String key, Object value) { - this.key = key; - oldValue = putToMDCwithOverwriteWarning(key, toJson(value)); - } - - @Override - public void close() { - if (oldValue == null) { - MDC.remove(key); - } else { - MDC.put(key, oldValue); - } - } - private static String toJson(Object object) { String objectToJson = "{\"json_error\":\"Unserializable Object.\"}"; //needs to be an object, not a string, for Kibana. Otherwise, Kibana will throw away the log entry because the field has the wrong type. @@ -355,4 +348,13 @@ private static void logFailedUpdate(String key) { log.warn("Cannot update content of MDC key {} in {}.{}({}:{}) because it does not exist.", key, caller.getClassName(), caller.getMethodName(), caller.getFileName(), caller.getLineNumber()); } + + @Override + public void close() { + if (oldValue == null) { + MDC.remove(key); + } else { + MDC.put(key, oldValue); + } + } } diff --git a/src/test/java/de/dm/prom/structuredlogging/ExampleBean.java b/src/test/java/de/dm/prom/structuredlogging/ExampleBean.java index 646a3a6..aa646de 100644 --- a/src/test/java/de/dm/prom/structuredlogging/ExampleBean.java +++ b/src/test/java/de/dm/prom/structuredlogging/ExampleBean.java @@ -19,6 +19,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.Optional; import static java.time.DayOfWeek.MONDAY; import static java.time.Month.JANUARY; @@ -42,6 +43,8 @@ class ExampleBean { private MonthDay monthDay; private Year year; private YearMonth yearMonth; + private Optional emptyOptional; + private Optional nonEmptyOptional; static ExampleBean getExample() { LocalDateTime importantTime = LocalDateTime.of(2019, JANUARY, 1, 13, 37); @@ -63,6 +66,8 @@ static ExampleBean getExample() { .monthDay(MonthDay.of(12, 24)) .year(Year.of(1984)) .yearMonth(YearMonth.of(2000, 8)) + .emptyOptional(Optional.empty()) + .nonEmptyOptional(Optional.of("Hello")) .build(); } } diff --git a/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java b/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java index 64f85c1..9ff2c15 100644 --- a/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java +++ b/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java @@ -25,32 +25,184 @@ @Slf4j class MdcContextUnitTest { - private static final String SAMPLE_BEAN_JSON = "{\"name\":\"John Doe\"," + - "\"age\":35," + - "\"importantTime\":\"2019-01-01T13:37\"," + - "\"importantOffsetTime\":\"2019-01-01T13:37+01:00\"," + - "\"instant\":\"1970-01-01T00:00:01Z\"," + - "\"localDate\":\"2020-01-01\"," + - "\"offsetTime\":\"13:37+01:00\"," + - "\"period\":\"P42D\"," + - "\"zonedDateTime\":\"2019-01-01T13:37Z[UTC]\"," + - "\"localTime\":\"13:37\"," + - "\"duration\":\"PT42M\"," + - "\"dayOfWeek\":\"MONDAY\"," + - "\"month\":\"JANUARY\"," + - "\"monthDay\":\"--12-24\"," + - "\"year\":\"1984\"," + - "\"yearMonth\":\"2000-08\"" + - "}"; + private static final String SAMPLE_BEAN_JSON = """ + { + "name":"John Doe", + "age":35, + "importantTime":"2019-01-01T13:37", + "importantOffsetTime":"2019-01-01T13:37+01:00", + "instant":"1970-01-01T00:00:01Z", + "localDate":"2020-01-01", + "offsetTime":"13:37+01:00", + "period":"P42D", + "zonedDateTime":"2019-01-01T13:37Z[UTC]", + "localTime":"13:37", + "duration":"PT42M", + "dayOfWeek":"MONDAY", + "month":"JANUARY", + "monthDay":"--12-24", + "year":"1984", + "yearMonth":"2000-08", + "emptyOptional" : null, + "nonEmptyOptional" : "Hello" + } + """; @RegisterExtension public LogCapture logCapture = LogCapture.forCurrentPackage(); + private static void throwIOException() throws IOException { + throw new IOException("not really an IOException, just an example"); + } + @AfterEach void resetMdc() { MdcContext.resetGlobalObjectMapper(); } + @Test + void customObjectMapperIsUsedAndReset() throws IOException { + ObjectMapper customObjectMapper = mock(ObjectMapper.class); + ExampleBean objectToSerialize = ExampleBean.getExample(); + String expectedCustomJson = "{\"content\": \"custom json string\"}"; + + when(customObjectMapper.writeValueAsString(objectToSerialize)).thenReturn(expectedCustomJson); + + try (MdcContext c = MdcContext.of(objectToSerialize)) { + assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON); + } + + MdcContext.setGlobalObjectMapper(customObjectMapper); + + try (MdcContext c = MdcContext.of(objectToSerialize)) { + assertMdcFieldContentIsCorrect("ExampleBean", expectedCustomJson); + } + + MdcContext.resetGlobalObjectMapper(); + + try (MdcContext c = MdcContext.of(objectToSerialize)) { + assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON); + } + } + + @Test + void exceptionsThrownByObjectMapperAreCaughtAndLogged() throws IOException { + ObjectMapper customObjectMapper = mock(ObjectMapper.class); + String objectToSerialize = "I have a toString method"; + + when(customObjectMapper.writeValueAsString(objectToSerialize)).thenThrow(new RuntimeException("something terrible happened")); + + MdcContext.setGlobalObjectMapper(customObjectMapper); + try (MdcContext c = MdcContext.of(objectToSerialize)) { + log.info("something happened"); + } + + logCapture.assertLogged(error("Object cannot be serialized\\: \"I have a toString method\"", exception().expectedMessageRegex("something terrible happened").build())); + } + + private void assertMdcFieldContentIsCorrect(String mdcFieldName, String expectedJson) throws JsonProcessingException { + String jsonStringFromMdc = MDC.get(mdcFieldName); + + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode sampleBeanTree = objectMapper.readTree(expectedJson); + + assertThat(jsonStringFromMdc).startsWith(JSON_PREFIX); + String actualJson = jsonStringFromMdc.replaceFirst(JSON_PREFIX, ""); + JsonNode treeFromMDC = objectMapper.readTree(actualJson); + + assertThat(treeFromMDC.toPrettyString()) + .isEqualTo(sampleBeanTree.toPrettyString()); + } + + @Test + void putSomethingToMDCUpdateAndRemoveWhenDone() { + String mdcKey = new StringKeySupplier().getMdcKey(); + String mdcValue = "test value"; //JSON strings are expected at this point + String updatedValue = "updated value"; + try (MdcContext c = MdcContext.of(StringKeySupplier.class, mdcValue)) { + assertThat(MDC.get(mdcKey)).isEqualTo(String.format("%s\"%s\"", JSON_PREFIX, mdcValue)); + MdcContext.update(StringKeySupplier.class, updatedValue); + assertThat(MDC.get(mdcKey)).isEqualTo(String.format("%s\"%s\"", JSON_PREFIX, updatedValue)); + } + assertThat(MDC.get(mdcKey)).isNull(); + } + + @Test + void withSuppliedStringAsKey() throws Exception { + ExampleBean exampleBean = ExampleBean.getExample(); + String mdcKey = "custom_key"; + + try (MdcContext c = MdcContext.of(mdcKey, exampleBean)) { + assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON); + String updatedName = "Jack Frost"; + exampleBean.setName(updatedName); + MdcContext.update(mdcKey, exampleBean); + assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON.replace("John Doe", updatedName)); + } + assertThat(MDC.get(mdcKey)).isNull(); + } + + @Test + void withSimpleNameAsKey() throws Exception { + ExampleBean exampleBean = ExampleBean.getExample(); + String mdcKey = "ExampleBean"; + + try (MdcContext c = MdcContext.of(exampleBean)) { + assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON); + String updatedName = "Jack Frost"; + exampleBean.setName(updatedName); + MdcContext.update(exampleBean); + assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON.replace("John Doe", updatedName)); + } + assertThat(MDC.get(mdcKey)).isNull(); + } + + @Test + void failedUpdate() { + MdcContext.update(ExampleBean.getExample()); + + logCapture.assertLogged(warn("^Cannot update content of MDC key ExampleBean in .*\\.failedUpdate\\(MdcContextUnitTest.java:[0-9]+\\) because it does not exist.$")); + } + + @Test + void accidentallyOverwriteMDCValue() { + String someValue = "some value"; + String someValueJson = JSON_PREFIX + "\"" + someValue + "\""; + String otherValue = "other value"; + String otherValueJson = JSON_PREFIX + "\"" + otherValue + "\""; + + String mdcKey = new StringKeySupplier().getMdcKey(); + + try (MdcContext c = MdcContext.of(StringKeySupplier.class, someValue)) { + assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); + try (MdcContext inner = MdcContext.of(StringKeySupplier.class, someValue)) { + assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); + try (MdcContext sameIdWithDifferentValue = MdcContext.of(StringKeySupplier.class, otherValue)) { + assertThat(MDC.get(mdcKey)).isEqualTo(otherValueJson); + } + assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); + } + assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); + } + assertThat(MDC.get(mdcKey)).isNull(); + + logCapture.assertLoggedInOrder(warn("^Overwriting MDC key string_sample in .*\\.accidentallyOverwriteMDCValue\\(MdcContextUnitTest.java:[0-9]+\\) " + + "- a context with a certain key should never contain another context with the same one. " + + "The value is overwritten with the same value. This is superfluous and should be removed."), + error("^Overwriting MDC key string_sample in .*\\.accidentallyOverwriteMDCValue\\(MdcContextUnitTest.java:[0-9]+\\) " + + "- a context with a certain key should never contain another context with the same one. " + + "The old value differs from new value. This should never happen, because it messes up the MDC context. " + + "Old value: MDC_JSON_VALUE:\"some value\" - new value: MDC_JSON_VALUE:\"other value\"")); + } + + // useful for this test: ObjectMapper is not needed for comparison of serialized JSON + public static final class StringKeySupplier implements MdcKeySupplier { + @Override + public String getMdcKey() { + return "string_sample"; + } + } + @Nested class ContextId { @Test @@ -206,153 +358,4 @@ void withThrowingSupplier() { } } } - - private static void throwIOException() throws IOException { - throw new IOException("not really an IOException, just an example"); - } - - - @Test - void customObjectMapperIsUsedAndReset() throws IOException { - ObjectMapper customObjectMapper = mock(ObjectMapper.class); - ExampleBean objectToSerialize = ExampleBean.getExample(); - String expectedCustomJson = "{\"content\": \"custom json string\"}"; - - when(customObjectMapper.writeValueAsString(objectToSerialize)).thenReturn(expectedCustomJson); - - try (MdcContext c = MdcContext.of(objectToSerialize)) { - assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON); - } - - MdcContext.setGlobalObjectMapper(customObjectMapper); - - try (MdcContext c = MdcContext.of(objectToSerialize)) { - assertMdcFieldContentIsCorrect("ExampleBean", expectedCustomJson); - } - - MdcContext.resetGlobalObjectMapper(); - - try (MdcContext c = MdcContext.of(objectToSerialize)) { - assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON); - } - } - - @Test - void exceptionsThrownByObjectMapperAreCaughtAndLogged() throws IOException { - ObjectMapper customObjectMapper = mock(ObjectMapper.class); - String objectToSerialize = "I have a toString method"; - - when(customObjectMapper.writeValueAsString(objectToSerialize)).thenThrow(new RuntimeException("something terrible happened")); - - MdcContext.setGlobalObjectMapper(customObjectMapper); - try (MdcContext c = MdcContext.of(objectToSerialize)) { - log.info("something happened"); - } - - logCapture.assertLogged(error("Object cannot be serialized\\: \"I have a toString method\"", exception().expectedMessageRegex("something terrible happened").build())); - } - - private void assertMdcFieldContentIsCorrect(String mdcFieldName, String expectedJson) throws JsonProcessingException { - String jsonStringFromMdc = MDC.get(mdcFieldName); - - ObjectMapper objectMapper = new ObjectMapper(); - JsonNode sampleBeanTree = objectMapper.readTree(expectedJson); - - assertThat(jsonStringFromMdc).startsWith(JSON_PREFIX); - String actualJson = jsonStringFromMdc.replaceFirst(JSON_PREFIX, ""); - JsonNode treeFromMDC = objectMapper.readTree(actualJson); - - assertThat(treeFromMDC).as("Expecting:\n<%s>\nto be equal to:\n<%s>\nbut was not.\n\n\n", - treeFromMDC.toPrettyString(), sampleBeanTree.toPrettyString()) - .isEqualTo(sampleBeanTree); - } - - @Test - void putSomethingToMDCUpdateAndRemoveWhenDone() { - String mdcKey = new StringKeySupplier().getMdcKey(); - String mdcValue = "test value"; //JSON strings are expected at this point - String updatedValue = "updated value"; - try (MdcContext c = MdcContext.of(StringKeySupplier.class, mdcValue)) { - assertThat(MDC.get(mdcKey)).isEqualTo(String.format("%s\"%s\"", JSON_PREFIX, mdcValue)); - MdcContext.update(StringKeySupplier.class, updatedValue); - assertThat(MDC.get(mdcKey)).isEqualTo(String.format("%s\"%s\"", JSON_PREFIX, updatedValue)); - } - assertThat(MDC.get(mdcKey)).isNull(); - } - - @Test - void withSuppliedStringAsKey() throws Exception { - ExampleBean exampleBean = ExampleBean.getExample(); - String mdcKey = "custom_key"; - - try (MdcContext c = MdcContext.of(mdcKey, exampleBean)) { - assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON); - String updatedName = "Jack Frost"; - exampleBean.setName(updatedName); - MdcContext.update(mdcKey, exampleBean); - assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON.replace("John Doe", updatedName)); - } - assertThat(MDC.get(mdcKey)).isNull(); - } - - @Test - void withSimpleNameAsKey() throws Exception { - ExampleBean exampleBean = ExampleBean.getExample(); - String mdcKey = "ExampleBean"; - - try (MdcContext c = MdcContext.of(exampleBean)) { - assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON); - String updatedName = "Jack Frost"; - exampleBean.setName(updatedName); - MdcContext.update(exampleBean); - assertMdcFieldContentIsCorrect(mdcKey, SAMPLE_BEAN_JSON.replace("John Doe", updatedName)); - } - assertThat(MDC.get(mdcKey)).isNull(); - } - - @Test - void failedUpdate() { - MdcContext.update(ExampleBean.getExample()); - - logCapture.assertLogged(warn("^Cannot update content of MDC key ExampleBean in .*\\.failedUpdate\\(MdcContextUnitTest.java:[0-9]+\\) because it does not exist.$")); - } - - @Test - void accidentallyOverwriteMDCValue() { - String someValue = "some value"; - String someValueJson = JSON_PREFIX + "\"" + someValue + "\""; - String otherValue = "other value"; - String otherValueJson = JSON_PREFIX + "\"" + otherValue + "\""; - - String mdcKey = new StringKeySupplier().getMdcKey(); - - try (MdcContext c = MdcContext.of(StringKeySupplier.class, someValue)) { - assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); - try (MdcContext inner = MdcContext.of(StringKeySupplier.class, someValue)) { - assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); - try (MdcContext sameIdWithDifferentValue = MdcContext.of(StringKeySupplier.class, otherValue)) { - assertThat(MDC.get(mdcKey)).isEqualTo(otherValueJson); - } - assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); - } - assertThat(MDC.get(mdcKey)).isEqualTo(someValueJson); - } - assertThat(MDC.get(mdcKey)).isNull(); - - logCapture.assertLoggedInOrder(warn("^Overwriting MDC key string_sample in .*\\.accidentallyOverwriteMDCValue\\(MdcContextUnitTest.java:[0-9]+\\) " + - "- a context with a certain key should never contain another context with the same one. " + - "The value is overwritten with the same value. This is superfluous and should be removed."), - error("^Overwriting MDC key string_sample in .*\\.accidentallyOverwriteMDCValue\\(MdcContextUnitTest.java:[0-9]+\\) " + - "- a context with a certain key should never contain another context with the same one. " + - "The old value differs from new value. This should never happen, because it messes up the MDC context. " + - "Old value: MDC_JSON_VALUE:\"some value\" - new value: MDC_JSON_VALUE:\"other value\"")); - } - - // useful for this test: ObjectMapper is not needed for comparison of serialized JSON - public static final class StringKeySupplier implements MdcKeySupplier { - @Override - public String getMdcKey() { - return "string_sample"; - } - } } diff --git a/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java b/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java index b31e7dc..1bf376b 100644 --- a/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java +++ b/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java @@ -27,30 +27,37 @@ // LogCapture is not applicable here because the actual output format of the log is relevant @Slf4j class StructuredMdcJsonProviderUnitTest { - private static final String SAMPLE_LOGSTASH_JSON_LOG = "{\"@version\":\"1\"," + - "\"message\":\"something in which the ExampleBean context is relevant\"," + - "\"logger_name\":\"de.dm.prom.structuredlogging.StructuredMdcJsonProviderUnitTest\"," + - "\"thread_name\":\"main\"," + - "\"level\":\"INFO\"," + - "\"level_value\":20000," + - "\"an_unmanaged_mdc_field\":\"some value\"," + - "\"example_bean\":" + - "{\"name\":\"John Doe\"," + - "\"age\":35," + - "\"importantTime\":\"2019-01-01T13:37\"," + - "\"importantOffsetTime\":\"2019-01-01T13:37+01:00\"," + - "\"instant\":\"1970-01-01T00:00:01Z\"," + - "\"localDate\":\"2020-01-01\"," + - "\"offsetTime\":\"13:37+01:00\"," + - "\"period\":\"P42D\"," + - "\"localTime\":\"13:37\"," + - "\"duration\":\"PT42M\"," + - "\"dayOfWeek\":\"MONDAY\"," + - "\"month\":\"JANUARY\"," + - "\"monthDay\":\"--12-24\"," + - "\"year\":\"1984\"," + - "\"yearMonth\":\"2000-08\"," + - "\"zonedDateTime\":\"2019-01-01T13:37Z[UTC]\"}}"; + private static final String SAMPLE_LOGSTASH_JSON_LOG = """ + { + "@version":"1", + "message":"something in which the ExampleBean context is relevant", + "logger_name":"de.dm.prom.structuredlogging.StructuredMdcJsonProviderUnitTest", + "thread_name":"main", + "level":"INFO", + "level_value":20000, + "an_unmanaged_mdc_field":"some value", + "example_bean": { + "name":"John Doe", + "age":35, + "importantTime":"2019-01-01T13:37", + "importantOffsetTime":"2019-01-01T13:37+01:00", + "instant":"1970-01-01T00:00:01Z", + "localDate":"2020-01-01", + "offsetTime":"13:37+01:00", + "period":"P42D", + "zonedDateTime":"2019-01-01T13:37Z[UTC]", + "localTime":"13:37", + "duration":"PT42M", + "dayOfWeek":"MONDAY", + "month":"JANUARY", + "monthDay":"--12-24", + "year":"1984", + "yearMonth":"2000-08", + "emptyOptional" : null, + "nonEmptyOptional" : "Hello" + } + } + """; private final Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); @@ -85,7 +92,7 @@ void logTest(CapturedOutput output) throws IOException { ((ObjectNode) actualJson).remove("@timestamp"); //because only ObjectNode provides .remove(...) - Assertions.assertThat(actualJson).isEqualTo(expectedJson); + Assertions.assertThat(actualJson.toPrettyString()).isEqualTo(expectedJson.toPrettyString()); } } }