diff --git a/guest/slf4j/guide/pom.xml b/guest/slf4j/guide/pom.xml
new file mode 100644
index 0000000000..0db9b46247
--- /dev/null
+++ b/guest/slf4j/guide/pom.xml
@@ -0,0 +1,64 @@
+
+
+ 4.0.0
+
+ com.stackify.slf4j.guide
+ slf4j-parent-module
+ 1.0.0-SNAPSHOT
+ pom
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.0.6.RELEASE
+
+
+
+ slf4j-logback
+ slf4j-log4j2
+ slf4j-log4j
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.powermock
+ powermock-module-junit4
+ ${powermock.version}
+ test
+
+
+ org.powermock
+ powermock-api-mockito2
+ ${powermock.version}
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.0.0-beta.5
+
+
diff --git a/guest/slf4j/guide/slf4j-log4j/.gitignore b/guest/slf4j/guide/slf4j-log4j/.gitignore
new file mode 100644
index 0000000000..82eca336e3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-log4j/pom.xml b/guest/slf4j/guide/slf4j-log4j/pom.xml
new file mode 100644
index 0000000000..0d08fa6191
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+
+ slf4j-log4j
+ 0.0.1-SNAPSHOT
+ jar
+
+
+ com.stackify.slf4j.guide
+ slf4j-parent-module
+ 1.0.0-SNAPSHOT
+ ..
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ 1.7.25
+
+
diff --git a/guest/slf4j/guide/slf4j-log4j/src/main/java/com/stackify/slf4j/guide/Application.java b/guest/slf4j/guide/slf4j-log4j/src/main/java/com/stackify/slf4j/guide/Application.java
new file mode 100644
index 0000000000..01ccf519b3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/src/main/java/com/stackify/slf4j/guide/Application.java
@@ -0,0 +1,12 @@
+package com.stackify.slf4j.guide;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java b/guest/slf4j/guide/slf4j-log4j/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java
new file mode 100644
index 0000000000..14f4439545
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java
@@ -0,0 +1,42 @@
+package com.stackify.slf4j.guide.controllers;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class SimpleController {
+
+ Logger logger = LoggerFactory.getLogger(SimpleController.class);
+
+ @GetMapping("/slf4j-guide-request")
+ public String processList(List list) {
+ logger.info("Client requested process the following list: {}", list);
+ try {
+ logger.debug("Starting process");
+ // ...processing list here...
+ Thread.sleep(500);
+ } catch (RuntimeException | InterruptedException e) {
+ logger.error("There was an issue processing the list.", e);
+ } finally {
+ logger.info("Finished processing");
+ }
+ return "done";
+ }
+
+ @GetMapping("/slf4j-guide-mdc-request")
+ public String clientMDCRequest(@RequestHeader String clientId) throws InterruptedException {
+ MDC.put("clientId", clientId);
+ logger.info("Client {} has made a request", clientId);
+ logger.info("Starting request");
+ Thread.sleep(500);
+ logger.info("Finished request");
+ MDC.clear();
+ return "finished";
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j/src/main/resources/application.properties b/guest/slf4j/guide/slf4j-log4j/src/main/resources/application.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/guest/slf4j/guide/slf4j-log4j/src/main/resources/log4j.xml b/guest/slf4j/guide/slf4j-log4j/src/main/resources/log4j.xml
new file mode 100644
index 0000000000..ea432bff77
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/src/main/resources/log4j.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-log4j/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java b/guest/slf4j/guide/slf4j-log4j/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java
new file mode 100644
index 0000000000..991a1e2686
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java
@@ -0,0 +1,80 @@
+package com.stackify.slf4j.guide.controllers;
+
+import static org.powermock.api.mockito.PowerMockito.doNothing;
+import static org.powermock.api.mockito.PowerMockito.spy;
+
+import java.util.Collections;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.spi.LoggingEvent;
+import org.assertj.core.api.Condition;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.slf4j.MDC;
+
+import com.stackify.slf4j.guide.utils.ListAppender;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(MDC.class)
+public class SimpleControllerIntegrationTest {
+
+ private SimpleController controller = new SimpleController();
+
+ @Before
+ public void clearLogList() {
+ ListAppender.clearEventList();
+ }
+
+ @Test
+ public void whenSimpleRequestMade_thenAllRegularMessagesLogged() {
+ String output = controller.processList(Collections.emptyList());
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .haveAtLeastOne(eventContains("Client requested process the following list: []", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting process", Level.DEBUG))
+ .haveAtLeastOne(eventContains("Finished processing", Level.INFO))
+ .haveExactly(0, eventOfLevel(Level.ERROR));
+ errorCollector.assertThat(output)
+ .isEqualTo("done");
+ errorCollector.assertAll();
+ }
+
+ @Test
+ public void givenClientId_whenMDCRequestMade_thenMessagesWithClientIdLogged() throws Exception {
+ // We avoid cleaning the context so tht we can check it afterwards
+ spy(MDC.class);
+ doNothing().when(MDC.class);
+ MDC.clear();
+ String clientId = "id-1234";
+
+ String output = controller.clientMDCRequest(clientId);
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .allMatch(entry -> {
+ return clientId.equals(entry.getMDC("clientId"));
+ })
+ .haveAtLeastOne(eventContains("Client id-1234 has made a request", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting request", Level.INFO))
+ .haveAtLeastOne(eventContains("Finished request", Level.INFO));
+ errorCollector.assertThat(output)
+ .isEqualTo("finished");
+ errorCollector.assertAll();
+
+ }
+
+ private Condition eventOfLevel(Level level) {
+ return eventContains(null, level);
+ }
+
+ private Condition eventContains(String substring, Level level) {
+
+ return new Condition(entry -> (substring == null || (entry.getRenderedMessage() != null && entry.getRenderedMessage()
+ .contains(substring))) && (level == null || level.equals(entry.getLevel())), String.format("entry with message '%s', level %s", substring, level));
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j/src/test/java/com/stackify/slf4j/guide/utils/ListAppender.java b/guest/slf4j/guide/slf4j-log4j/src/test/java/com/stackify/slf4j/guide/utils/ListAppender.java
new file mode 100644
index 0000000000..4ce9e73d6d
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/src/test/java/com/stackify/slf4j/guide/utils/ListAppender.java
@@ -0,0 +1,33 @@
+package com.stackify.slf4j.guide.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.spi.LoggingEvent;
+
+public class ListAppender extends AppenderSkeleton {
+ public static List events = new ArrayList();
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ @Override
+ protected void append(LoggingEvent event) {
+ events.add(event);
+ }
+
+ public static List getEvents() {
+ return events;
+ }
+
+ public static void clearEventList() {
+ events.clear();
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j/src/test/resources/log4j.xml b/guest/slf4j/guide/slf4j-log4j/src/test/resources/log4j.xml
new file mode 100644
index 0000000000..10443e5eab
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j/src/test/resources/log4j.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-log4j2/.gitignore b/guest/slf4j/guide/slf4j-log4j2/.gitignore
new file mode 100644
index 0000000000..82eca336e3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-log4j2/pom.xml b/guest/slf4j/guide/slf4j-log4j2/pom.xml
new file mode 100644
index 0000000000..643649335f
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/pom.xml
@@ -0,0 +1,54 @@
+
+
+ 4.0.0
+
+ slf4j-log4j2
+ 0.0.1-SNAPSHOT
+ jar
+
+
+ com.stackify.slf4j.guide
+ slf4j-parent-module
+ 1.0.0-SNAPSHOT
+ ..
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-log4j2
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+ test-jar
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j.version}
+ test-jar
+
+
+
+
+ 2.11.0
+
+
diff --git a/guest/slf4j/guide/slf4j-log4j2/src/main/java/com/stackify/slf4j/guide/Application.java b/guest/slf4j/guide/slf4j-log4j2/src/main/java/com/stackify/slf4j/guide/Application.java
new file mode 100644
index 0000000000..01ccf519b3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/src/main/java/com/stackify/slf4j/guide/Application.java
@@ -0,0 +1,12 @@
+package com.stackify.slf4j.guide;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j2/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java b/guest/slf4j/guide/slf4j-log4j2/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java
new file mode 100644
index 0000000000..14f4439545
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java
@@ -0,0 +1,42 @@
+package com.stackify.slf4j.guide.controllers;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class SimpleController {
+
+ Logger logger = LoggerFactory.getLogger(SimpleController.class);
+
+ @GetMapping("/slf4j-guide-request")
+ public String processList(List list) {
+ logger.info("Client requested process the following list: {}", list);
+ try {
+ logger.debug("Starting process");
+ // ...processing list here...
+ Thread.sleep(500);
+ } catch (RuntimeException | InterruptedException e) {
+ logger.error("There was an issue processing the list.", e);
+ } finally {
+ logger.info("Finished processing");
+ }
+ return "done";
+ }
+
+ @GetMapping("/slf4j-guide-mdc-request")
+ public String clientMDCRequest(@RequestHeader String clientId) throws InterruptedException {
+ MDC.put("clientId", clientId);
+ logger.info("Client {} has made a request", clientId);
+ logger.info("Starting request");
+ Thread.sleep(500);
+ logger.info("Finished request");
+ MDC.clear();
+ return "finished";
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j2/src/main/resources/application.properties b/guest/slf4j/guide/slf4j-log4j2/src/main/resources/application.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/guest/slf4j/guide/slf4j-log4j2/src/main/resources/log4j2-spring.xml b/guest/slf4j/guide/slf4j-log4j2/src/main/resources/log4j2-spring.xml
new file mode 100644
index 0000000000..7d1494c7a6
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/src/main/resources/log4j2-spring.xml
@@ -0,0 +1,28 @@
+
+
+ ????
+ %5p
+ yyyy-MM-dd HH:mm:ss.SSS
+ %clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta}
+ %clr{---}{faint} %clr{%X{clientId}}{red}%clr{@%15.15t}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-log4j2/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java b/guest/slf4j/guide/slf4j-log4j2/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java
new file mode 100644
index 0000000000..f41c857533
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java
@@ -0,0 +1,81 @@
+package com.stackify.slf4j.guide.controllers;
+
+import java.util.Collections;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.appender.ListAppender;
+import org.assertj.core.api.Condition;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+public class SimpleControllerIntegrationTest {
+
+ private static ListAppender appender;
+ private SimpleController controller = new SimpleController();
+
+ @ClassRule
+ public static LoggerContextRule init = new LoggerContextRule("log4j2-test.xml");
+
+ @BeforeClass
+ public static void setupLogging() {
+ appender = init.getListAppender("ListAppender");
+ }
+
+ @Before
+ public void clearAppender() {
+ appender.clear();
+ }
+
+ @Test
+ public void whenSimpleRequestMade_thenAllRegularMessagesLogged() {
+ String output = controller.processList(Collections.emptyList());
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(appender.getEvents())
+ .haveAtLeastOne(eventContains("Client requested process the following list: []", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting process", Level.DEBUG))
+ .haveAtLeastOne(eventContains("Finished processing", Level.INFO))
+ .haveExactly(0, eventOfLevel(Level.ERROR));
+ errorCollector.assertThat(output)
+ .isEqualTo("done");
+ errorCollector.assertAll();
+ }
+
+ @Test
+ public void givenClientId_whenMDCRequestMade_thenMessagesWithClientIdLogged() throws Exception {
+ String clientId = "id-1234";
+
+ String output = controller.clientMDCRequest(clientId);
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(appender.getEvents())
+ .allMatch(entry -> {
+ return clientId.equals(entry.getContextData()
+ .getValue("clientId"));
+ })
+ .haveAtLeastOne(eventContains("Client id-1234 has made a request", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting request", Level.INFO))
+ .haveAtLeastOne(eventContains("Finished request", Level.INFO));
+ errorCollector.assertThat(output)
+ .isEqualTo("finished");
+ errorCollector.assertAll();
+ }
+
+ private Condition eventOfLevel(Level level) {
+ return eventContains(null, level);
+ }
+
+ private Condition eventContains(String substring, Level level) {
+
+ return new Condition(entry -> (substring == null || (entry.getMessage()
+ .getFormattedMessage() != null && entry.getMessage()
+ .getFormattedMessage()
+ .contains(substring)))
+ && (level == null || level.equals(entry.getLevel())), String.format("entry with message '%s', level %s", substring, level));
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-log4j2/src/test/resources/log4j2-test.xml b/guest/slf4j/guide/slf4j-log4j2/src/test/resources/log4j2-test.xml
new file mode 100644
index 0000000000..2ca386f7f6
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-log4j2/src/test/resources/log4j2-test.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-logback/.gitignore b/guest/slf4j/guide/slf4j-logback/.gitignore
new file mode 100644
index 0000000000..82eca336e3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/build/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-logback/pom.xml b/guest/slf4j/guide/slf4j-logback/pom.xml
new file mode 100644
index 0000000000..e8aebf0ef6
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/pom.xml
@@ -0,0 +1,32 @@
+
+
+ 4.0.0
+
+ slf4j-logback
+ 0.0.1-SNAPSHOT
+ jar
+
+
+ com.stackify.slf4j.guide
+ slf4j-parent-module
+ 1.0.0-SNAPSHOT
+ ..
+
+
+
+
+ org.slf4j
+ slf4j-ext
+
+
+ ch.qos.cal10n
+ cal10n-api
+ ${cal10n.version}
+
+
+
+
+ 0.8.1
+
+
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/Application.java b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/Application.java
new file mode 100644
index 0000000000..01ccf519b3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/Application.java
@@ -0,0 +1,12 @@
+package com.stackify.slf4j.guide;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java
new file mode 100644
index 0000000000..1fab675c94
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/controllers/SimpleController.java
@@ -0,0 +1,133 @@
+package com.stackify.slf4j.guide.controllers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+import org.slf4j.cal10n.LocLogger;
+import org.slf4j.cal10n.LocLoggerFactory;
+import org.slf4j.ext.EventData;
+import org.slf4j.ext.EventLogger;
+import org.slf4j.profiler.Profiler;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.stackify.slf4j.guide.l10n.Messages;
+
+import ch.qos.cal10n.IMessageConveyor;
+import ch.qos.cal10n.MessageConveyor;
+
+@RestController
+public class SimpleController {
+
+ Logger logger = LoggerFactory.getLogger(SimpleController.class);
+
+ @GetMapping("/slf4j-guide-request")
+ public String processList(List list) {
+ logger.info("Client requested process the following list: {}", list);
+ try {
+ logger.debug("Starting process");
+ // ...processing list here...
+ Thread.sleep(500);
+ } catch (RuntimeException | InterruptedException e) {
+ logger.error("There was an issue processing the list.", e);
+ } finally {
+ logger.info("Finished processing");
+ }
+ return "done";
+ }
+
+ @GetMapping("/slf4j-guide-mdc-request")
+ public String clientMDCRequest(@RequestHeader String clientId) throws InterruptedException {
+ MDC.put("clientId", clientId);
+ logger.info("Client {} has made a request", clientId);
+ logger.info("Starting request");
+ Thread.sleep(500);
+ logger.info("Finished request");
+ MDC.clear();
+ return "finished";
+ }
+
+ @GetMapping("/slf4j-guide-marker-request")
+ public String clientMarkerRequest() throws InterruptedException {
+ logger.info("client has made a request");
+ Marker myMarker = MarkerFactory.getMarker("MYMARKER");
+ logger.info(myMarker, "Starting request");
+ Thread.sleep(500);
+ logger.debug(myMarker, "Finished request");
+ return "finished";
+ }
+
+ @GetMapping("/slf4j-guide-profiler-request")
+ public String clientProfilerRequest() {
+ logger.info("client has made a request");
+ Profiler myProfiler = new Profiler("MYPROFILER");
+ // Associate the logger to handle the output( for testing purposes here)
+ myProfiler.setLogger(logger);
+
+ myProfiler.start("List generation process");
+ List list = generateList();
+
+ myProfiler.start("List sorting process");
+ Collections.sort(list);
+
+ // Use the log() method instead of print() to use the logger (for testing purposes here)
+ myProfiler.stop()
+ .log();
+ return "finished";
+ }
+
+ private List generateList() {
+ List generated = new ArrayList<>();
+ for (int i = 0; i < 5000; i++) {
+ generated.add(ThreadLocalRandom.current()
+ .nextInt(2000));
+ }
+ return generated;
+ }
+
+ @GetMapping("/slf4j-guide-event-request")
+ public String clientEventRequest(@RequestParam("sender") String sender, @RequestParam("receiver") String receiver) {
+ logger.info("sending from {} to {}", sender, receiver);
+
+ // ...sending process...
+
+ EventData data = new EventData();
+ data.setEventDateTime(new Date());
+ data.setEventType("sending");
+ String confirm = UUID.randomUUID()
+ .toString();
+ data.setEventId(confirm);
+ data.put("from", sender);
+ data.put("to", receiver);
+ EventLogger.logEvent(data);
+
+ return "finished";
+ }
+
+ @GetMapping("/slf4j-guide-locale-request")
+ public String clientLocaleRequest(@RequestHeader("Accept-Language") String localeHeader) {
+ List list = Locale.LanguageRange.parse(localeHeader);
+ Locale locale = Locale.lookup(list, Arrays.asList(Locale.getAvailableLocales()));
+ IMessageConveyor messageConveyor = new MessageConveyor(locale);
+ LocLoggerFactory llFactory = new LocLoggerFactory(messageConveyor);
+ LocLogger locLogger = llFactory.getLocLogger(this.getClass());
+ locLogger.info(Messages.CLIENT_REQUEST, "parametrizedClientId", localeHeader);
+ locLogger.debug(Messages.REQUEST_STARTED);
+ locLogger.info(Messages.REQUEST_FINISHED);
+ return "finished";
+ }
+
+}
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/l10n/Messages.java b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/l10n/Messages.java
new file mode 100644
index 0000000000..e4aacaf3be
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/l10n/Messages.java
@@ -0,0 +1,11 @@
+package com.stackify.slf4j.guide.l10n;
+
+import ch.qos.cal10n.BaseName;
+import ch.qos.cal10n.Locale;
+import ch.qos.cal10n.LocaleData;
+
+@BaseName("messages")
+@LocaleData({ @Locale("en_US"), @Locale("es_ES") })
+public enum Messages {
+ CLIENT_REQUEST, REQUEST_STARTED, REQUEST_FINISHED
+}
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/xlogger/XLoggerController.java b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/xlogger/XLoggerController.java
new file mode 100644
index 0000000000..8690c0ebc9
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/java/com/stackify/slf4j/guide/xlogger/XLoggerController.java
@@ -0,0 +1,28 @@
+package com.stackify.slf4j.guide.xlogger;
+
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class XLoggerController {
+
+ private XLogger logger = XLoggerFactory.getXLogger(XLoggerController.class);
+
+ @GetMapping("/slf4j-guide-xlogger-request")
+ public Integer clientXLoggerRequest(@RequestParam("queryParam") Integer queryParam) {
+ logger.info("Starting process");
+ logger.entry(queryParam);
+ Integer rest = 0;
+ try {
+ rest = queryParam % 3;
+ } catch (RuntimeException anyException) {
+ logger.catching(anyException);
+ }
+ logger.exit(rest);
+ return rest;
+ }
+
+}
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/resources/application.properties b/guest/slf4j/guide/slf4j-logback/src/main/resources/application.properties
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/resources/logback-spring.xml b/guest/slf4j/guide/slf4j-logback/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000000..112e79c340
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/resources/logback-spring.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ %marker %d{yyyy-MM-dd HH:mm:ss.SSS} -%5p %X{clientId}@%15.15t %-40.40logger{39} : %m%n
+
+
+
+
+
+
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/resources/messages_en_US.properties b/guest/slf4j/guide/slf4j-logback/src/main/resources/messages_en_US.properties
new file mode 100644
index 0000000000..a35dd60da3
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/resources/messages_en_US.properties
@@ -0,0 +1,3 @@
+CLIENT_REQUEST=Client {0} has made a request using locale {1}
+REQUEST_STARTED=Request started
+REQUEST_FINISHED=Request finished
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-logback/src/main/resources/messages_es_ES.properties b/guest/slf4j/guide/slf4j-logback/src/main/resources/messages_es_ES.properties
new file mode 100644
index 0000000000..6cdab09236
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/main/resources/messages_es_ES.properties
@@ -0,0 +1,3 @@
+CLIENT_REQUEST=El cliente {0} ha realizado una solicitud usando locale {1}
+REQUEST_STARTED=Solicitud iniciada
+REQUEST_FINISHED=Solicitud finalizada
\ No newline at end of file
diff --git a/guest/slf4j/guide/slf4j-logback/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java b/guest/slf4j/guide/slf4j-logback/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java
new file mode 100644
index 0000000000..b870cc9ebd
--- /dev/null
+++ b/guest/slf4j/guide/slf4j-logback/src/test/java/com/stackify/slf4j/guide/controllers/SimpleControllerIntegrationTest.java
@@ -0,0 +1,163 @@
+package com.stackify.slf4j.guide.controllers;
+
+import static org.powermock.api.mockito.PowerMockito.doNothing;
+import static org.powermock.api.mockito.PowerMockito.spy;
+
+import java.util.Collections;
+
+import org.assertj.core.api.Condition;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.slf4j.MDC;
+
+import com.stackify.slf4j.guide.utils.ListAppender;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(MDC.class)
+public class SimpleControllerIntegrationTest {
+
+ SimpleController controller = new SimpleController();
+
+ @Before
+ public void clearLogList() {
+ ListAppender.clearEventList();
+ }
+
+ @Test
+ public void whenSimpleRequestMade_thenAllRegularMessagesLogged() {
+ String output = controller.processList(Collections.emptyList());
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .haveAtLeastOne(eventContains("Client requested process the following list: []", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting process", Level.DEBUG))
+ .haveAtLeastOne(eventContains("Finished processing", Level.INFO))
+ .haveExactly(0, eventOfLevel(Level.ERROR));
+ errorCollector.assertThat(output)
+ .isEqualTo("done");
+ errorCollector.assertAll();
+ }
+
+ @Test
+ public void givenClientId_whenMDCRequestMade_thenMessagesWithClientIdLogged() throws Exception {
+ // We avoid cleaning the context so tht we can check it afterwards
+ spy(MDC.class);
+ doNothing().when(MDC.class);
+ MDC.clear();
+ String clientId = "id-1234";
+
+ String output = controller.clientMDCRequest(clientId);
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .allMatch(entry -> {
+ return clientId.equals(entry.getMDCPropertyMap()
+ .get("clientId"));
+ })
+ .haveAtLeastOne(eventContains("Client id-1234 has made a request", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting request", Level.INFO))
+ .haveAtLeastOne(eventContains("Finished request", Level.INFO));
+ errorCollector.assertThat(output)
+ .isEqualTo("finished");
+ errorCollector.assertAll();
+ }
+
+ @Test
+ public void whenMarkerRequestMade_thenMessagesWithMarkerLogged() throws Exception {
+ String output = controller.clientMarkerRequest();
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .haveAtLeastOne(eventContains("client has made a request", Level.INFO))
+ .haveAtLeastOne(eventContains("Starting request", Level.INFO, "MYMARKER"))
+ .haveAtLeastOne(eventContains("Finished request", Level.DEBUG, "MYMARKER"))
+ .haveExactly(2, eventContains(null, null, "MYMARKER"));
+ errorCollector.assertThat(output)
+ .isEqualTo("finished");
+ errorCollector.assertAll();
+ }
+
+ @Test
+ public void whenProfilerRequestMade_thenMessagesWithPerformanceLogged() throws Exception {
+ String output = controller.clientProfilerRequest();
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .haveAtLeastOne(eventContains("client has made a request", Level.INFO))
+ .haveAtLeastOne(eventContains("Profiler [MYPROFILER]", Level.DEBUG));
+ errorCollector.assertThat(output)
+ .isEqualTo("finished");
+ errorCollector.assertAll();
+ }
+
+ @Test
+ public void whenEventRequestMade_thenMessagesWithEventLogged() throws Exception {
+ String sender = "sender";
+ String receiver = "receiver";
+ String output = controller.clientEventRequest(sender, receiver);
+
+ SoftAssertions errorCollector = new SoftAssertions();
+ errorCollector.assertThat(ListAppender.getEvents())
+ .haveAtLeastOne(eventContains("sending from sender to receiver", Level.INFO))
+ .haveAtLeastOne(eventContains("