runnable) throws E {
+ try (MdcContext c = MdcContext.of(keySupplier, mdcValue)) {
+ runnable.run();
+ }
+ }
+
/**
* update an existing MDC context
*
diff --git a/src/main/java/de/dm/prom/structuredlogging/MdcRunnable.java b/src/main/java/de/dm/prom/structuredlogging/MdcRunnable.java
new file mode 100644
index 0000000..a9b8497
--- /dev/null
+++ b/src/main/java/de/dm/prom/structuredlogging/MdcRunnable.java
@@ -0,0 +1,15 @@
+package de.dm.prom.structuredlogging;
+
+/**
+ * Runnable that throws, to be able to handle MDC Context that throw one checked Exception
+ *
+ * @param thrown checked Exception
+ */
+public interface MdcRunnable {
+ /**
+ * callback to run with context
+ *
+ * @throws E thrown checked Exception
+ */
+ void run() throws E;
+}
diff --git a/src/main/java/de/dm/prom/structuredlogging/MdcSupplier.java b/src/main/java/de/dm/prom/structuredlogging/MdcSupplier.java
new file mode 100644
index 0000000..ff6c418
--- /dev/null
+++ b/src/main/java/de/dm/prom/structuredlogging/MdcSupplier.java
@@ -0,0 +1,18 @@
+package de.dm.prom.structuredlogging;
+
+/**
+ * Supplier that throws, to be able to handle MDC Context that throw one checked Exception
+ *
+ * @param return value of context
+ * @param thrown checked Exception
+ */
+public interface MdcSupplier {
+ /**
+ * callback to run with context
+ *
+ * @return specified return value
+ *
+ * @throws E thrown checked Exception
+ */
+ T get() throws E;
+}
diff --git a/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java b/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java
index f4acfec..64f85c1 100644
--- a/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java
+++ b/src/test/java/de/dm/prom/structuredlogging/MdcContextUnitTest.java
@@ -6,6 +6,7 @@
import de.dm.infrastructure.logcapture.LogCapture;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.MDC;
@@ -15,8 +16,10 @@
import static de.dm.infrastructure.logcapture.ExpectedException.exception;
import static de.dm.infrastructure.logcapture.LogExpectation.error;
import static de.dm.infrastructure.logcapture.LogExpectation.warn;
+import static de.dm.prom.structuredlogging.MdcContext.mdc;
import static de.dm.prom.structuredlogging.StructuredMdcJsonProvider.JSON_PREFIX;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -48,27 +51,167 @@ void resetMdc() {
MdcContext.resetGlobalObjectMapper();
}
- @Test
- void createSampleContextWithContextId() throws IOException {
- try (MdcContext c = MdcContext.of(ExampleBeanKeySupplier.class, ExampleBean.getExample())) {
- assertMdcFieldContentIsCorrect("example_bean", SAMPLE_BEAN_JSON);
+ @Nested
+ class ContextId {
+ @Test
+ void withTryBlock() throws IOException {
+ try (MdcContext c = MdcContext.of(ExampleBeanKeySupplier.class, ExampleBean.getExample())) {
+ assertMdcFieldContentIsCorrect("example_bean", SAMPLE_BEAN_JSON);
+ }
+ }
+
+ @Test
+ void withRunnable() throws IOException {
+ mdc(ExampleBeanKeySupplier.class, ExampleBean.getExample(), () ->
+ assertMdcFieldContentIsCorrect("example_bean", SAMPLE_BEAN_JSON));
+ }
+
+ @Test
+ void withThrowingRunnable() {
+ try {
+ mdc(ExampleBeanKeySupplier.class, ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("example_bean", SAMPLE_BEAN_JSON);
+ throwIOException();
+ });
+ fail("expected an Exception");
+ } catch (IOException e) {
+ // everything is fine
+ }
+ }
+
+ @Test
+ void withSupplier() throws IOException {
+ var actual = mdc(ExampleBeanKeySupplier.class, ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("example_bean", SAMPLE_BEAN_JSON);
+ return 42;
+ });
+ assertThat(actual).isEqualTo(42);
+ }
+
+ @Test
+ void withThrowingSupplier() {
+ try {
+ mdc(ExampleBeanKeySupplier.class, ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("example_bean", SAMPLE_BEAN_JSON);
+ throwIOException();
+ return 42;
+ });
+ fail("expected an Exception");
+ } catch (IOException e) {
+ // everything is fine
+ }
}
}
- @Test
- void createSampleContextWithClassOnly() throws IOException {
- try (MdcContext c = MdcContext.of(ExampleBean.getExample())) {
- assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON);
+ @Nested
+ class ClassOnly {
+ @Test
+ void withTryBlock() throws IOException {
+ try (MdcContext c = MdcContext.of(ExampleBean.getExample())) {
+ assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON);
+ }
+ }
+
+ @Test
+ void withRunnable() throws IOException {
+ mdc(ExampleBean.getExample(), () ->
+ assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON));
+ }
+
+ @Test
+ void withThrowingRunnable() {
+ try {
+ mdc(ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON);
+ throwIOException();
+ });
+ fail("expected an Exception");
+ } catch (IOException e) {
+ // everything is fine
+ }
+ }
+
+ @Test
+ void withSupplier() throws IOException {
+ var actual = mdc(ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON);
+ return 42;
+ });
+ assertThat(actual).isEqualTo(42);
+ }
+
+ @Test
+ void withThrowingSupplier() {
+ try {
+ mdc(ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("ExampleBean", SAMPLE_BEAN_JSON);
+ throwIOException();
+ return 42;
+ });
+ fail("expected an Exception");
+ } catch (IOException e) {
+ // everything is fine
+ }
}
}
- @Test
- void createSampleContextWithKey() throws IOException {
- try (MdcContext c = MdcContext.of("explicit_key", ExampleBean.getExample())) {
- assertMdcFieldContentIsCorrect("explicit_key", SAMPLE_BEAN_JSON);
+ @Nested
+ class KeyFromString {
+ @Test
+ void withTryBlock() throws IOException {
+ try (MdcContext c = MdcContext.of("explicit_key", ExampleBean.getExample())) {
+ assertMdcFieldContentIsCorrect("explicit_key", SAMPLE_BEAN_JSON);
+ }
+ }
+
+ @Test
+ void withRunnable() throws IOException {
+ mdc("explicit_key", ExampleBean.getExample(), () ->
+ assertMdcFieldContentIsCorrect("explicit_key", SAMPLE_BEAN_JSON));
+ }
+
+ @Test
+ void withThrowingRunnable() {
+ try {
+ mdc("explicit_key", ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("explicit_key", SAMPLE_BEAN_JSON);
+ throwIOException();
+ });
+ fail("expected an Exception");
+ } catch (IOException e) {
+ // everything is fine
+ }
+ }
+
+ @Test
+ void withSupplier() throws IOException {
+ var actual = mdc("explicit_key", ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("explicit_key", SAMPLE_BEAN_JSON);
+ return 42;
+ });
+ assertThat(actual).isEqualTo(42);
+ }
+
+ @Test
+ void withThrowingSupplier() {
+ try {
+ mdc("explicit_key", ExampleBean.getExample(), () -> {
+ assertMdcFieldContentIsCorrect("explicit_key", SAMPLE_BEAN_JSON);
+ throwIOException();
+ return 42;
+ });
+ fail("expected an Exception");
+ } catch (IOException e) {
+ // everything is fine
+ }
}
}
+ 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);
diff --git a/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java b/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java
index 6d15ade..b31e7dc 100644
--- a/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java
+++ b/src/test/java/de/dm/prom/structuredlogging/StructuredMdcJsonProviderUnitTest.java
@@ -1,7 +1,8 @@
package de.dm.prom.structuredlogging;
import ch.qos.logback.classic.Logger;
-import ch.qos.logback.classic.util.ContextInitializer;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.joran.spi.JoranException;
import com.fasterxml.jackson.databind.JsonNode;
@@ -26,7 +27,7 @@
// LogCapture is not applicable here because the actual output format of the log is relevant
@Slf4j
class StructuredMdcJsonProviderUnitTest {
- private static String SAMPLE_LOGSTASH_JSON_LOG = "{\"@version\":\"1\"," +
+ 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\"," +
@@ -51,14 +52,16 @@ class StructuredMdcJsonProviderUnitTest {
"\"yearMonth\":\"2000-08\"," +
"\"zonedDateTime\":\"2019-01-01T13:37Z[UTC]\"}}";
- private Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ private final Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
@BeforeEach
void setupLogback() throws FileNotFoundException, JoranException {
rootLogger.iteratorForAppenders().forEachRemaining(Appender::stop);
- new ContextInitializer(rootLogger.getLoggerContext())
- .configureByResource(ResourceUtils.getURL("src/test/resources/logback-stdout-json.xml"));
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(context);
+ configurator.doConfigure(ResourceUtils.getURL("src/test/resources/logback-stdout-json.xml"));
}
@AfterEach