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("", Level.INFO)) + .haveAtLeastOne(eventContains("sender", Level.INFO)) + .haveAtLeastOne(eventContains("receiver", Level.INFO)); + errorCollector.assertThat(output) + .isEqualTo("finished"); + errorCollector.assertAll(); + } + + @Test + public void givenESLocale_whenLocaleRequestMade_thenMessagesWithEventLogged() throws Exception { + String locale = "es-ES"; + String output = controller.clientLocaleRequest(locale); + + SoftAssertions errorCollector = new SoftAssertions(); + errorCollector.assertThat(ListAppender.getEvents()) + .haveAtLeastOne(eventContains("El cliente parametrizedClientId ha realizado una solicitud usando locale es-ES", Level.INFO)) + .haveAtLeastOne(eventContains("Solicitud iniciada", Level.DEBUG)) + .haveAtLeastOne(eventContains("Solicitud finalizada", Level.INFO)); + errorCollector.assertThat(output) + .isEqualTo("finished"); + errorCollector.assertAll(); + } + + @Test + public void givenENLocale_whenLocaleRequestMade_thenMessagesWithEventLogged() throws Exception { + String locale = "en-US"; + String output = controller.clientLocaleRequest(locale); + + SoftAssertions errorCollector = new SoftAssertions(); + errorCollector.assertThat(ListAppender.getEvents()) + .haveAtLeastOne(eventContains("Client parametrizedClientId has made a request using locale en-US", Level.INFO)) + .haveAtLeastOne(eventContains("Request started", Level.DEBUG)) + .haveAtLeastOne(eventContains("Request finished", Level.INFO)); + errorCollector.assertThat(output) + .isEqualTo("finished"); + errorCollector.assertAll(); + } + + private Condition eventContains(String substring, Level level) { + return eventContains(substring, level, null); + } + + private Condition eventOfLevel(Level level) { + return eventContains(null, level, null); + } + + private Condition eventContains(String substring, Level level, String markerName) { + + return new Condition(entry -> (substring == null || (entry.getFormattedMessage() != null && entry.getFormattedMessage() + .contains(substring))) && (level == null || level.equals(entry.getLevel())) && (markerName == null || (entry.getMarker() != null + && markerName.equals(entry.getMarker() + .getName()))), + String.format("entry with message '%s', level %s and marker %s", substring, level, markerName)); + } +} diff --git a/guest/slf4j/guide/slf4j-logback/src/test/java/com/stackify/slf4j/guide/utils/ListAppender.java b/guest/slf4j/guide/slf4j-logback/src/test/java/com/stackify/slf4j/guide/utils/ListAppender.java new file mode 100644 index 0000000000..e6d4e47fb2 --- /dev/null +++ b/guest/slf4j/guide/slf4j-logback/src/test/java/com/stackify/slf4j/guide/utils/ListAppender.java @@ -0,0 +1,25 @@ +package com.stackify.slf4j.guide.utils; + +import java.util.ArrayList; +import java.util.List; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +public class ListAppender extends AppenderBase { + + static private List events = new ArrayList<>(); + + @Override + protected void append(ILoggingEvent eventObject) { + events.add(eventObject); + } + + public static List getEvents() { + return events; + } + + public static void clearEventList() { + events.clear(); + } +} diff --git a/guest/slf4j/guide/slf4j-logback/src/test/resources/logback-test.xml b/guest/slf4j/guide/slf4j-logback/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..90168a0fea --- /dev/null +++ b/guest/slf4j/guide/slf4j-logback/src/test/resources/logback-test.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file