Skip to content

Commit be22bd2

Browse files
rozagerardomaibin
authored andcommitted
[BAEL-2111] guest | Why SLF4J? 10 Reasons to use it (eugenp#5536)
* Added new submodule for SLF4J guest post, containg modules for logback, log4j and log4j2 * * added tests for logging endpoints * removed application tests, no use now that we have other tests
1 parent c10101a commit be22bd2

31 files changed

Lines changed: 1044 additions & 0 deletions

File tree

guest/slf4j/guide/pom.xml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.stackify.slf4j.guide</groupId>
7+
<artifactId>slf4j-parent-module</artifactId>
8+
<version>1.0.0-SNAPSHOT</version>
9+
<packaging>pom</packaging>
10+
11+
12+
<parent>
13+
<groupId>org.springframework.boot</groupId>
14+
<artifactId>spring-boot-starter-parent</artifactId>
15+
<version>2.0.6.RELEASE</version>
16+
</parent>
17+
18+
<modules>
19+
<module>slf4j-logback</module>
20+
<module>slf4j-log4j2</module>
21+
<module>slf4j-log4j</module>
22+
</modules>
23+
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-starter-web</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-test</artifactId>
32+
<scope>test</scope>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.powermock</groupId>
36+
<artifactId>powermock-module-junit4</artifactId>
37+
<version>${powermock.version}</version>
38+
<scope>test</scope>
39+
</dependency>
40+
<dependency>
41+
<groupId>org.powermock</groupId>
42+
<artifactId>powermock-api-mockito2</artifactId>
43+
<version>${powermock.version}</version>
44+
<scope>test</scope>
45+
</dependency>
46+
</dependencies>
47+
48+
49+
<build>
50+
<plugins>
51+
<plugin>
52+
<groupId>org.springframework.boot</groupId>
53+
<artifactId>spring-boot-maven-plugin</artifactId>
54+
</plugin>
55+
</plugins>
56+
</build>
57+
58+
<properties>
59+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
60+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
61+
<java.version>1.8</java.version>
62+
<powermock.version>2.0.0-beta.5</powermock.version>
63+
</properties>
64+
</project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
4+
### STS ###
5+
.apt_generated
6+
.classpath
7+
.factorypath
8+
.project
9+
.settings
10+
.springBeans
11+
.sts4-cache
12+
13+
### IntelliJ IDEA ###
14+
.idea
15+
*.iws
16+
*.iml
17+
*.ipr
18+
19+
### NetBeans ###
20+
/nbproject/private/
21+
/build/
22+
/nbbuild/
23+
/dist/
24+
/nbdist/
25+
/.nb-gradle/
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<artifactId>slf4j-log4j</artifactId>
7+
<version>0.0.1-SNAPSHOT</version>
8+
<packaging>jar</packaging>
9+
10+
<parent>
11+
<groupId>com.stackify.slf4j.guide</groupId>
12+
<artifactId>slf4j-parent-module</artifactId>
13+
<version>1.0.0-SNAPSHOT</version>
14+
<relativePath>..</relativePath>
15+
</parent>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-starter-web</artifactId>
21+
<exclusions>
22+
<exclusion>
23+
<groupId>org.springframework.boot</groupId>
24+
<artifactId>spring-boot-starter-logging</artifactId>
25+
</exclusion>
26+
</exclusions>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.slf4j</groupId>
30+
<artifactId>slf4j-log4j12</artifactId>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-starter-test</artifactId>
35+
<scope>test</scope>
36+
</dependency>
37+
</dependencies>
38+
<properties>
39+
<slf4j.log4j.version>1.7.25</slf4j.log4j.version>
40+
</properties>
41+
</project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.stackify.slf4j.guide;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class Application {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(Application.class, args);
11+
}
12+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.stackify.slf4j.guide.controllers;
2+
3+
import java.util.List;
4+
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.slf4j.MDC;
8+
import org.springframework.web.bind.annotation.GetMapping;
9+
import org.springframework.web.bind.annotation.RequestHeader;
10+
import org.springframework.web.bind.annotation.RestController;
11+
12+
@RestController
13+
public class SimpleController {
14+
15+
Logger logger = LoggerFactory.getLogger(SimpleController.class);
16+
17+
@GetMapping("/slf4j-guide-request")
18+
public String processList(List<String> list) {
19+
logger.info("Client requested process the following list: {}", list);
20+
try {
21+
logger.debug("Starting process");
22+
// ...processing list here...
23+
Thread.sleep(500);
24+
} catch (RuntimeException | InterruptedException e) {
25+
logger.error("There was an issue processing the list.", e);
26+
} finally {
27+
logger.info("Finished processing");
28+
}
29+
return "done";
30+
}
31+
32+
@GetMapping("/slf4j-guide-mdc-request")
33+
public String clientMDCRequest(@RequestHeader String clientId) throws InterruptedException {
34+
MDC.put("clientId", clientId);
35+
logger.info("Client {} has made a request", clientId);
36+
logger.info("Starting request");
37+
Thread.sleep(500);
38+
logger.info("Finished request");
39+
MDC.clear();
40+
return "finished";
41+
}
42+
}

guest/slf4j/guide/slf4j-log4j/src/main/resources/application.properties

Whitespace-only changes.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
3+
4+
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
5+
<appender name="console" class="org.apache.log4j.ConsoleAppender">
6+
<param name="Target" value="System.out"/>
7+
<layout class="org.apache.log4j.PatternLayout">
8+
<param name="ConversionPattern" value="%5p %d{ISO8601} [%X{clientId}@%t][%x] %c - %m%n"/>
9+
</layout>
10+
</appender>
11+
12+
<root>
13+
<priority value ="info" />
14+
<appender-ref ref="console" />
15+
</root>
16+
17+
</log4j:configuration>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.stackify.slf4j.guide.controllers;
2+
3+
import static org.powermock.api.mockito.PowerMockito.doNothing;
4+
import static org.powermock.api.mockito.PowerMockito.spy;
5+
6+
import java.util.Collections;
7+
8+
import org.apache.log4j.Level;
9+
import org.apache.log4j.spi.LoggingEvent;
10+
import org.assertj.core.api.Condition;
11+
import org.assertj.core.api.SoftAssertions;
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
import org.junit.runner.RunWith;
15+
import org.powermock.core.classloader.annotations.PrepareForTest;
16+
import org.powermock.modules.junit4.PowerMockRunner;
17+
import org.slf4j.MDC;
18+
19+
import com.stackify.slf4j.guide.utils.ListAppender;
20+
21+
@RunWith(PowerMockRunner.class)
22+
@PrepareForTest(MDC.class)
23+
public class SimpleControllerIntegrationTest {
24+
25+
private SimpleController controller = new SimpleController();
26+
27+
@Before
28+
public void clearLogList() {
29+
ListAppender.clearEventList();
30+
}
31+
32+
@Test
33+
public void whenSimpleRequestMade_thenAllRegularMessagesLogged() {
34+
String output = controller.processList(Collections.emptyList());
35+
36+
SoftAssertions errorCollector = new SoftAssertions();
37+
errorCollector.assertThat(ListAppender.getEvents())
38+
.haveAtLeastOne(eventContains("Client requested process the following list: []", Level.INFO))
39+
.haveAtLeastOne(eventContains("Starting process", Level.DEBUG))
40+
.haveAtLeastOne(eventContains("Finished processing", Level.INFO))
41+
.haveExactly(0, eventOfLevel(Level.ERROR));
42+
errorCollector.assertThat(output)
43+
.isEqualTo("done");
44+
errorCollector.assertAll();
45+
}
46+
47+
@Test
48+
public void givenClientId_whenMDCRequestMade_thenMessagesWithClientIdLogged() throws Exception {
49+
// We avoid cleaning the context so tht we can check it afterwards
50+
spy(MDC.class);
51+
doNothing().when(MDC.class);
52+
MDC.clear();
53+
String clientId = "id-1234";
54+
55+
String output = controller.clientMDCRequest(clientId);
56+
57+
SoftAssertions errorCollector = new SoftAssertions();
58+
errorCollector.assertThat(ListAppender.getEvents())
59+
.allMatch(entry -> {
60+
return clientId.equals(entry.getMDC("clientId"));
61+
})
62+
.haveAtLeastOne(eventContains("Client id-1234 has made a request", Level.INFO))
63+
.haveAtLeastOne(eventContains("Starting request", Level.INFO))
64+
.haveAtLeastOne(eventContains("Finished request", Level.INFO));
65+
errorCollector.assertThat(output)
66+
.isEqualTo("finished");
67+
errorCollector.assertAll();
68+
69+
}
70+
71+
private Condition<LoggingEvent> eventOfLevel(Level level) {
72+
return eventContains(null, level);
73+
}
74+
75+
private Condition<LoggingEvent> eventContains(String substring, Level level) {
76+
77+
return new Condition<LoggingEvent>(entry -> (substring == null || (entry.getRenderedMessage() != null && entry.getRenderedMessage()
78+
.contains(substring))) && (level == null || level.equals(entry.getLevel())), String.format("entry with message '%s', level %s", substring, level));
79+
}
80+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.stackify.slf4j.guide.utils;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.apache.log4j.AppenderSkeleton;
7+
import org.apache.log4j.spi.LoggingEvent;
8+
9+
public class ListAppender extends AppenderSkeleton {
10+
public static List<LoggingEvent> events = new ArrayList<LoggingEvent>();
11+
12+
@Override
13+
public void close() {
14+
}
15+
16+
@Override
17+
public boolean requiresLayout() {
18+
return false;
19+
}
20+
21+
@Override
22+
protected void append(LoggingEvent event) {
23+
events.add(event);
24+
}
25+
26+
public static List<LoggingEvent> getEvents() {
27+
return events;
28+
}
29+
30+
public static void clearEventList() {
31+
events.clear();
32+
}
33+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
3+
4+
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
5+
<appender name="console" class="org.apache.log4j.ConsoleAppender">
6+
<param name="Target" value="System.out"/>
7+
</appender>
8+
<appender name="list" class="com.stackify.slf4j.guide.utils.ListAppender">
9+
</appender>
10+
11+
<root>
12+
<priority value ="trace" />
13+
<appender-ref ref="list" />
14+
</root>
15+
16+
</log4j:configuration>

0 commit comments

Comments
 (0)