diff --git a/log4j2/pom.xml b/log4j2/pom.xml
new file mode 100644
index 0000000000..83904f2075
--- /dev/null
+++ b/log4j2/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+ log4j2
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ..
+
+
+
+
+
+ org.apache.logging.log4j
+ log4j-core
+ 2.7
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.8.4
+
+
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+ 2.8.4
+
+
+
+
+ com.h2database
+ h2
+ 1.4.192
+
+
+ org.apache.commons
+ commons-dbcp2
+ 2.1.1
+
+
+
+
+ org.apache.logging.log4j
+ log4j-core
+ 2.7
+ test-jar
+ test
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ 1.8
+ 1.8
+
+
+
+
+
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/AsyncFileAppenderUsingJsonLayoutTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/AsyncFileAppenderUsingJsonLayoutTest.java
new file mode 100644
index 0000000000..0472c2219e
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/AsyncFileAppenderUsingJsonLayoutTest.java
@@ -0,0 +1,32 @@
+package com.baeldung.logging.log4j2.tests;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(JUnit4.class)
+public class AsyncFileAppenderUsingJsonLayoutTest {
+ @Rule
+ public LoggerContextRule contextRule =
+ new LoggerContextRule("log4j2-async-file-appender_json-layout.xml");
+
+ @Test
+ public void givenLoggerWithAsyncConfig_shouldLogToJsonFile()
+ throws Exception {
+ Logger logger = contextRule.getLogger(getClass().getSimpleName());
+ final int count = 88;
+ for (int i = 0; i < count; i++) {
+ logger.info("This is async JSON message #{} at INFO level.", count);
+ }
+ long logEventsCount = Files.lines(Paths.get("target/logfile.json")).count();
+ assertTrue(logEventsCount > 0 && logEventsCount <= count);
+ }
+}
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/ConsoleAppenderUsingDefaultLayoutTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/ConsoleAppenderUsingDefaultLayoutTest.java
new file mode 100644
index 0000000000..9831030d02
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/ConsoleAppenderUsingDefaultLayoutTest.java
@@ -0,0 +1,21 @@
+package com.baeldung.logging.log4j2.tests;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConsoleAppenderUsingDefaultLayoutTest {
+ @Test
+ public void givenLoggerWithDefaultConfig_shouldLogToConsole()
+ throws Exception {
+ Logger logger = LogManager.getLogger(getClass());
+ Exception e = new RuntimeException("This is only a test!");
+ logger.info("This is a simple message at INFO level. " +
+ "It will be hidden.");
+ logger.error("This is a simple message at ERROR level. " +
+ "This is the minimum visible level.", e);
+ }
+}
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/ConsoleAppenderUsingPatternLayoutWithColorsTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/ConsoleAppenderUsingPatternLayoutWithColorsTest.java
new file mode 100644
index 0000000000..86b005538f
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/ConsoleAppenderUsingPatternLayoutWithColorsTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.logging.log4j2.tests;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConsoleAppenderUsingPatternLayoutWithColorsTest {
+ @Rule
+ public LoggerContextRule contextRule =
+ new LoggerContextRule("log4j2-console-appender_pattern-layout.xml");
+
+ @Test
+ public void givenLoggerWithConsoleConfig_shouldLogToConsoleInColors()
+ throws Exception {
+ Logger logger = contextRule.getLogger(getClass().getSimpleName());
+ logger.trace("This is a colored message at TRACE level.");
+ logger.debug("This is a colored message at DEBUG level. " +
+ "This is the minimum visible level.");
+ logger.info("This is a colored message at INFO level.");
+ logger.warn("This is a colored message at WARN level.");
+ Exception e = new RuntimeException("This is only a test!");
+ logger.error("This is a colored message at ERROR level.", e);
+ logger.fatal("This is a colored message at FATAL level.");
+ }
+
+ @Test
+ public void givenLoggerWithConsoleConfig_shouldFilterByMarker() throws Exception {
+ Logger logger = contextRule.getLogger("ConnTrace");
+ Marker appError = MarkerManager.getMarker("APP_ERROR");
+ logger.error(appError, "This marker message at ERROR level should be hidden.");
+ Marker connectionTrace = MarkerManager.getMarker("CONN_TRACE");
+ logger.trace(connectionTrace, "This is a marker message at TRACE level.");
+ }
+
+ @Test
+ public void givenLoggerWithConsoleConfig_shouldFilterByThreadContext() throws Exception {
+ Logger logger = contextRule.getLogger("UserAudit");
+ ThreadContext.put("userId", "1000");
+ logger.info("This is a log-visible user login. Maybe from an admin account?");
+ ThreadContext.put("userId", "1001");
+ logger.info("This is a log-invisible user login.");
+ boolean b = true;
+ }
+}
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/FailoverSyslogConsoleAppenderTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/FailoverSyslogConsoleAppenderTest.java
new file mode 100644
index 0000000000..0653394e5a
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/FailoverSyslogConsoleAppenderTest.java
@@ -0,0 +1,27 @@
+package com.baeldung.logging.log4j2.tests;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class FailoverSyslogConsoleAppenderTest {
+ @Rule
+ public LoggerContextRule contextRule =
+ new LoggerContextRule("log4j2-failover-syslog-console-appender_pattern-layout.xml");
+
+ @Test
+ public void givenLoggerWithFailoverConfig_shouldLog() throws Exception {
+ Logger logger = contextRule.getLogger(getClass().getSimpleName());
+ logger.trace("This is a syslog message at TRACE level.");
+ logger.debug("This is a syslog message at DEBUG level.");
+ logger.info("This is a syslog message at INFO level. This is the minimum visible level.");
+ logger.warn("This is a syslog message at WARN level.");
+ Exception e = new RuntimeException("This is only a test!");
+ logger.error("This is a syslog message at ERROR level.", e);
+ logger.fatal("This is a syslog message at FATAL level.");
+ }
+}
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/JDBCAppenderTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/JDBCAppenderTest.java
new file mode 100644
index 0000000000..1b8d33e2bf
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/JDBCAppenderTest.java
@@ -0,0 +1,51 @@
+package com.baeldung.logging.log4j2.tests;
+
+import com.baeldung.logging.log4j2.tests.jdbc.ConnectionFactory;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(JUnit4.class)
+public class JDBCAppenderTest {
+ @Rule
+ public LoggerContextRule contextRule = new LoggerContextRule("log4j2-jdbc-appender.xml");
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ Connection connection = ConnectionFactory.getConnection();
+ connection.createStatement()
+ .execute("CREATE TABLE logs(" +
+ "when TIMESTAMP," +
+ "logger VARCHAR(255)," +
+ "level VARCHAR(255)," +
+ "message VARCHAR(4096)," +
+ "throwable TEXT)");
+ //connection.commit();
+ }
+
+ @Test
+ public void givenLoggerWithJdbcConfig_shouldLogToDataSource() throws Exception {
+ Logger logger = contextRule.getLogger(getClass().getSimpleName());
+ final int count = 88;
+ for (int i = 0; i < count; i++) {
+ logger.info("This is JDBC message #{} at INFO level.", count);
+ }
+ Connection connection = ConnectionFactory.getConnection();
+ ResultSet resultSet = connection.createStatement()
+ .executeQuery("SELECT COUNT(*) AS ROW_COUNT FROM logs");
+ int logCount = 0;
+ if (resultSet.next()) {
+ logCount = resultSet.getInt("ROW_COUNT");
+ }
+ assertTrue(logCount == count);
+ }
+}
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/RollingFileAppenderUsingXMLLayoutTest.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/RollingFileAppenderUsingXMLLayoutTest.java
new file mode 100644
index 0000000000..3ab69d263c
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/RollingFileAppenderUsingXMLLayoutTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.logging.log4j2.tests;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertTrue;
+
+@RunWith(JUnit4.class)
+public class RollingFileAppenderUsingXMLLayoutTest {
+ @Rule
+ public LoggerContextRule contextRule =
+ new LoggerContextRule("log4j2-rolling-file-appender_xml-layout.xml");
+
+ @Test
+ public void givenLoggerWithRollingFileConfig_shouldLogToXMLFile() throws Exception {
+ Logger logger = contextRule.getLogger(getClass().getSimpleName());
+ final int count = 88;
+ for (int i = 0; i < count; i++) {
+ logger.info("This is rolling file XML message #{} at INFO level.", i);
+ }
+ String[] logEvents = Files.readAllLines(Paths.get("target/logfile.xml")).stream()
+ .collect(Collectors.joining(System.lineSeparator()))
+ .split("\\n\\n+");
+ assertTrue(logEvents.length == 39);
+ }
+}
diff --git a/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java
new file mode 100644
index 0000000000..73b323f335
--- /dev/null
+++ b/log4j2/src/test/java/com/baeldung/logging/log4j2/tests/jdbc/ConnectionFactory.java
@@ -0,0 +1,25 @@
+package com.baeldung.logging.log4j2.tests.jdbc;
+
+import org.apache.commons.dbcp2.BasicDataSource;
+import org.h2.Driver;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public class ConnectionFactory {
+ private interface Singleton {
+ ConnectionFactory INSTANCE = new ConnectionFactory();
+ }
+
+ private BasicDataSource dataSource;
+
+ private ConnectionFactory() {
+ dataSource = new BasicDataSource();
+ dataSource.setDriver(new Driver());
+ dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
+ }
+
+ public static Connection getConnection() throws SQLException {
+ return Singleton.INSTANCE.dataSource.getConnection();
+ }
+}
diff --git a/log4j2/src/test/resources/log4j2-async-file-appender_json-layout.xml b/log4j2/src/test/resources/log4j2-async-file-appender_json-layout.xml
new file mode 100644
index 0000000000..c291eacd59
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2-async-file-appender_json-layout.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j2/src/test/resources/log4j2-console-appender_pattern-layout.xml b/log4j2/src/test/resources/log4j2-console-appender_pattern-layout.xml
new file mode 100644
index 0000000000..d6621f9166
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2-console-appender_pattern-layout.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j2/src/test/resources/log4j2-failover-syslog-console-appender_pattern-layout.xml b/log4j2/src/test/resources/log4j2-failover-syslog-console-appender_pattern-layout.xml
new file mode 100644
index 0000000000..62ba37f28c
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2-failover-syslog-console-appender_pattern-layout.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j2/src/test/resources/log4j2-includes/console-appender_pattern-layout_colored.xml b/log4j2/src/test/resources/log4j2-includes/console-appender_pattern-layout_colored.xml
new file mode 100644
index 0000000000..c2b9c65430
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2-includes/console-appender_pattern-layout_colored.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/log4j2/src/test/resources/log4j2-jdbc-appender.xml b/log4j2/src/test/resources/log4j2-jdbc-appender.xml
new file mode 100644
index 0000000000..6b50f7d5a4
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2-jdbc-appender.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j2/src/test/resources/log4j2-rolling-file-appender_xml-layout.xml b/log4j2/src/test/resources/log4j2-rolling-file-appender_xml-layout.xml
new file mode 100644
index 0000000000..9de1a29186
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2-rolling-file-appender_xml-layout.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j2/src/test/resources/log4j2.xml b/log4j2/src/test/resources/log4j2.xml
new file mode 100644
index 0000000000..8f7608aa78
--- /dev/null
+++ b/log4j2/src/test/resources/log4j2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+