This commit is contained in:
Jonathan Cook
2019-10-23 15:01:44 +02:00
parent db85c8f275
commit 684ec0d2e3
20486 changed files with 1642483 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
### Relevant Articles:
- [Get Log Output in JSON](https://www.baeldung.com/java-log-json-output)
- [SLF4J Warning: Class Path Contains Multiple SLF4J Bindings](https://www.baeldung.com/slf4j-classpath-multiple-bindings)
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>logback</artifactId>
<version>0.1-SNAPSHOT</version>
<name>logback</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.contrib</groupId>
<artifactId>logback-json-classic</artifactId>
<version>${logback.contrib.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback.contrib</groupId>
<artifactId>logback-jackson</artifactId>
<version>${logback.contrib.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>${docx4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<logback.version>1.2.3</logback.version>
<logback.contrib.version>0.1.5</logback.contrib.version>
<docx4j.version>3.3.5</docx4j.version>
</properties>
</project>
@@ -0,0 +1,14 @@
package com.baeldung.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Example {
private static final Logger logger = LoggerFactory.getLogger(Example.class);
public static void main(String[] args) {
logger.info("Example log from {}", Example.class.getSimpleName());
}
}
@@ -0,0 +1,39 @@
package com.baeldung.logback;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class MapAppender extends AppenderBase<ILoggingEvent> {
private final ConcurrentMap<String, ILoggingEvent> eventMap
= new ConcurrentHashMap<>();
private String prefix;
@Override
protected void append(final ILoggingEvent event) {
if (prefix == null || "".equals(prefix)) {
addError("Prefix is not set for MapAppender.");
return;
}
eventMap.put(prefix + System.currentTimeMillis(), event);
}
public String getPrefix() {
return prefix;
}
public void setPrefix(final String prefix) {
this.prefix = prefix;
}
public Map<String, ILoggingEvent> getEventMap() {
return eventMap;
}
}
@@ -0,0 +1,18 @@
<configuration>
<appender name="map" class="com.baeldung.logback.MapAppender">
<prefix>test</prefix>
</appender>
<appender name="out" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="map"/>
<appender-ref ref="out"/>
</root>
</configuration>
@@ -0,0 +1,45 @@
package com.baeldung.logback;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JSONLayoutIntegrationTest {
private static Logger logger;
private ByteArrayOutputStream consoleOutput = new ByteArrayOutputStream();
private PrintStream ps = new PrintStream(consoleOutput);
@Before
public void setUp() {
// Redirect console output to our stream
System.setOut(ps);
logger = LoggerFactory.getLogger("jsonLogger");
}
@Test
public void whenLogLayoutInJSON_thenOutputIsCorrectJSON() {
logger.debug("Debug message");
String currentLog = consoleOutput.toString();
assertTrue(!currentLog.isEmpty() && isValidJSON(currentLog));
}
public static boolean isValidJSON(String jsonInString) {
try {
final ObjectMapper mapper = new ObjectMapper();
mapper.readTree(jsonInString);
return true;
} catch (IOException e) {
return false;
}
}
}
@@ -0,0 +1,89 @@
package com.baeldung.logback;
import ch.qos.logback.classic.Level;
import org.junit.Test;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;
public class LogbackIntegrationTest {
@Test
public void givenLogHierarchy_MessagesFiltered() {
ch.qos.logback.classic.Logger parentLogger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback");
parentLogger.setLevel(Level.INFO);
Logger childlogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger("com.baeldung.logback.tests");
parentLogger.warn("This message is logged because WARN > INFO.");
// This request is disabled, because DEBUG < INFO.
parentLogger.debug("This message is not logged because DEBUG < INFO.");
childlogger.info("INFO == INFO");
childlogger.debug("DEBUG < INFO");
}
@Test
public void givenRootLevel_MessagesFiltered() {
ch.qos.logback.classic.Logger logger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback");
logger.debug("Hi there!");
Logger rootLogger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
logger.debug("This message is logged because DEBUG == DEBUG.");
rootLogger.setLevel(Level.ERROR);
logger.warn("This message is not logged because WARN < ERROR.");
logger.error("This is logged.");
}
@Test
public void givenParameters_ValuesLogged() {
Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(LogbackIntegrationTest.class);
String message = "This is a String";
Integer zero = 0;
try {
logger.debug("Logging message: {}", message);
logger.debug("Going to divide {} by {}", 42, zero);
int result = 42 / zero;
} catch (Exception e) {
logger.error("Error dividing {} by {} ", 42, zero, e);
}
}
@Test
public void givenConfig_MessageFiltered() {
Logger foobar = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.foobar");
Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback");
Logger testslogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback.tests");
foobar.debug("This is logged from foobar");
logger.debug("This is not logged from logger");
logger.info("This is logged from logger");
testslogger.info("This is not logged from tests");
testslogger.warn("This is logged from tests");
}
}
@@ -0,0 +1,33 @@
package com.baeldung.logback;
import ch.qos.logback.classic.Logger;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.assertEquals;
public class MapAppenderIntegrationTest {
private Logger rootLogger;
@Before
public void setUp() throws Exception {
rootLogger = (Logger) LoggerFactory.getLogger("ROOT");
}
@Test
public void whenLoggerEmitsLoggingEvent_thenAppenderReceivesEvent() throws Exception {
rootLogger.info("Test from {}", this.getClass().getSimpleName());
MapAppender appender = (MapAppender) rootLogger.getAppender("map");
assertEquals(appender.getEventMap().size(), 1);
}
@Test
public void givenNoPrefixSet_whenLoggerEmitsEvent_thenAppenderReceivesNoEvent() throws Exception {
rootLogger.info("Test from {}", this.getClass().getSimpleName());
MapAppender appender = (MapAppender) rootLogger.getAppender("badMap");
assertEquals(appender.getEventMap().size(), 0);
}
}
@@ -0,0 +1,60 @@
package com.baeldung.logback;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.BasicStatusManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class MapAppenderUnitTest {
private LoggerContext ctx;
private MapAppender mapAppender = new MapAppender();
private LoggingEvent event;
@Before
public void setUp() throws Exception {
ctx = new LoggerContext();
ctx.setName("test context");
ctx.setStatusManager(new BasicStatusManager());
mapAppender.setContext(ctx);
mapAppender.setPrefix("prefix");
event = new LoggingEvent("fqcn", ctx.getLogger("logger"), Level.INFO, "Test message for logback appender", null, new Object[0]);
ctx.start();
}
@After
public void tearDown() throws Exception {
ctx.stop();
mapAppender.stop();
}
@Test
public void whenPrefixIsNull_thenMapAppenderDoesNotLog() throws Exception {
mapAppender.setPrefix(null);
mapAppender.append(event);
assertTrue(mapAppender.getEventMap().isEmpty());
}
@Test
public void whenPrefixIsEmpty_thenMapAppenderDoesNotLog() throws Exception {
mapAppender.setPrefix("");
mapAppender.append(event);
assertTrue(mapAppender.getEventMap().isEmpty());
}
@Test
public void whenLogMessageIsEmitted_thenMapAppenderReceivesMessage() throws Exception {
mapAppender.append(event);
assertEquals(mapAppender.getEventMap().size(), 1);
mapAppender.getEventMap().forEach((k, v) -> assertTrue(k.startsWith("prefix")));
}
}
@@ -0,0 +1,32 @@
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>tests.log</file>
<append>true</append>
<!-- set immediateFlush to false for much higher logging throughput -->
<immediateFlush>true</immediateFlush>
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.baeldung.logback" level="INFO" />
<logger name="com.baeldung.logback.tests" level="WARN">
<appender-ref ref="FILE" />
</logger>
</configuration>
@@ -0,0 +1,31 @@
<configuration debug="false">
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<appender name="map" class="com.baeldung.logback.MapAppender">
<prefix>test</prefix>
</appender>
<appender name="badMap" class="com.baeldung.logback.MapAppender" />
# JSON appender
<appender name="json" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter
class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
<prettyPrint>true</prettyPrint>
</jsonFormatter>
<timestampFormat>yyyy-MM-dd' 'HH:mm:ss.SSS</timestampFormat>
</layout>
</appender>
<logger name="jsonLogger" level="TRACE">
<appender-ref ref="json" />
</logger>
<root level="debug">
<appender-ref ref="map" />
<appender-ref ref="badMap" />
</root>
</configuration>