diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index a64a794acf7..8f1498f3f5b 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -30,7 +30,7 @@ jobs:
build:
if: github.actor != 'dependabot[bot]'
- uses: apache/logging-parent/.github/workflows/build-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/build-reusable.yaml@rel/11.3.0
secrets:
DV_ACCESS_TOKEN: ${{ startsWith(github.ref_name, 'release/') && '' || secrets.GE_ACCESS_TOKEN }}
with:
@@ -44,7 +44,7 @@ jobs:
deploy-snapshot:
needs: build
if: github.repository == 'apache/logging-log4j2' && github.ref_name == '2.24.x'
- uses: apache/logging-parent/.github/workflows/deploy-snapshot-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/deploy-snapshot-reusable.yaml@rel/11.3.0
# Secrets for deployments
secrets:
NEXUS_USERNAME: ${{ secrets.NEXUS_USER }}
@@ -57,7 +57,7 @@ jobs:
deploy-release:
needs: build
if: github.repository == 'apache/logging-log4j2' && startsWith(github.ref_name, 'release/')
- uses: apache/logging-parent/.github/workflows/deploy-release-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/deploy-release-reusable.yaml@rel/11.3.0
# Secrets for deployments
secrets:
GPG_SECRET_KEY: ${{ secrets.LOGGING_GPG_SECRET_KEY }}
diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml
index 8d3643c10e3..cc2dbcaaf85 100644
--- a/.github/workflows/codeql-analysis.yaml
+++ b/.github/workflows/codeql-analysis.yaml
@@ -30,7 +30,7 @@ permissions: read-all
jobs:
analyze:
- uses: apache/logging-parent/.github/workflows/codeql-analysis-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/codeql-analysis-reusable.yaml@rel/11.3.0
with:
java-version: |
8
diff --git a/.github/workflows/deploy-site.yaml b/.github/workflows/deploy-site.yaml
index 543e50e4436..580166e9250 100644
--- a/.github/workflows/deploy-site.yaml
+++ b/.github/workflows/deploy-site.yaml
@@ -33,7 +33,7 @@ jobs:
deploy-site-stg:
if: github.repository == 'apache/logging-log4j2' && github.ref_name == '2.x'
- uses: apache/logging-parent/.github/workflows/deploy-site-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/deploy-site-reusable.yaml@rel/11.3.0
# Secrets for committing the generated site
secrets:
GPG_SECRET_KEY: ${{ secrets.LOGGING_GPG_SECRET_KEY }}
@@ -53,7 +53,7 @@ jobs:
deploy-site-pro:
if: github.repository == 'apache/logging-log4j2' && github.ref_name == '2.x-site-pro'
- uses: apache/logging-parent/.github/workflows/deploy-site-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/deploy-site-reusable.yaml@rel/11.3.0
# Secrets for committing the generated site
secrets:
GPG_SECRET_KEY: ${{ secrets.LOGGING_GPG_SECRET_KEY }}
@@ -83,7 +83,7 @@ jobs:
deploy-site-rel:
needs: export-version
- uses: apache/logging-parent/.github/workflows/deploy-site-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/deploy-site-reusable.yaml@rel/11.3.0
# Secrets for committing the generated site
secrets:
GPG_SECRET_KEY: ${{ secrets.LOGGING_GPG_SECRET_KEY }}
diff --git a/.github/workflows/develocity-publish-build-scans.yaml b/.github/workflows/develocity-publish-build-scans.yaml
index eb8d2b3a84c..597d7777ca4 100644
--- a/.github/workflows/develocity-publish-build-scans.yaml
+++ b/.github/workflows/develocity-publish-build-scans.yaml
@@ -29,10 +29,12 @@ jobs:
actions: write
pull-requests: write
steps:
+
- name: Setup Build Scan link capture
- uses: gradle/develocity-actions/maven-setup@v1
+ uses: gradle/develocity-actions/maven-setup@9f1bf05334de7eb619731d5466c35a153742311d # 1.2
+
- name: Publish Build Scans
- uses: gradle/develocity-actions/maven-publish-build-scan@v1
+ uses: gradle/develocity-actions/maven-publish-build-scan@9f1bf05334de7eb619731d5466c35a153742311d # 1.2
with:
develocity-url: 'https://ge.apache.org'
develocity-access-key: ${{ secrets.GE_ACCESS_TOKEN }}
diff --git a/.github/workflows/merge-dependabot.yaml b/.github/workflows/merge-dependabot.yaml
index 7fd1f9572a2..c0bda2b032f 100644
--- a/.github/workflows/merge-dependabot.yaml
+++ b/.github/workflows/merge-dependabot.yaml
@@ -31,7 +31,7 @@ jobs:
build:
if: github.repository == 'apache/logging-log4j2' && github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]'
# Temporary use `develocity` branch
- uses: apache/logging-parent/.github/workflows/build-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/build-reusable.yaml@rel/11.3.0
secrets:
DV_ACCESS_TOKEN: ${{ secrets.GE_ACCESS_TOKEN }}
with:
@@ -43,7 +43,7 @@ jobs:
merge-dependabot:
needs: build
- uses: apache/logging-parent/.github/workflows/merge-dependabot-reusable.yaml@rel/11.2.0
+ uses: apache/logging-parent/.github/workflows/merge-dependabot-reusable.yaml@rel/11.3.0
with:
java-version: 17
permissions:
diff --git a/BUILDING.adoc b/BUILDING.adoc
index 27d76641b68..98166cae282 100644
--- a/BUILDING.adoc
+++ b/BUILDING.adoc
@@ -85,6 +85,13 @@ You either need to have a user-level configuration in `~/.m2/toolchains.xml` or
./mvnw verify -Pjava8-tests,!java8-incompat-fixes
----
+[#docker]
+=== Docker tests
+
+Certain tests use Docker to spawn necessary external services.
+Docker tests are configured using the `docker` Maven profile, which is activated by default for the CI environment.
+You can locally enable this profile by passing a `-P docker` argument to your `./mvnw` commands.
+
[#website]
== Building the website
diff --git a/log4j-appserver/pom.xml b/log4j-appserver/pom.xml
index df0ce0067df..0b9c10b0dd2 100644
--- a/log4j-appserver/pom.xml
+++ b/log4j-appserver/pom.xml
@@ -52,22 +52,32 @@
org.apache.tomcat.juli;transitive=false,
org.eclipse.jetty.util;transitive=false
+
+
+ 9.4.56.v20240826
+ 10.0.27
+
org.eclipse.jetty
jetty-util
+ ${jetty.version}
provided
+
org.apache.tomcat
tomcat-juli
+ ${tomcat-juli.version}
provided
+
org.apache.logging.log4j
log4j-api
+
diff --git a/log4j-core-test/pom.xml b/log4j-core-test/pom.xml
index e23fc2c476a..f770ea88703 100644
--- a/log4j-core-test/pom.xml
+++ b/log4j-core-test/pom.xml
@@ -174,12 +174,12 @@
test
- org.codehaus.groovy
+ org.apache.groovy
groovy-dateutil
test
- org.codehaus.groovy
+ org.apache.groovy
groovy-jsr223
test
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java
index f17b3b2a55a..5001ad2d449 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.logging.log4j.core.config;
+import static java.util.Objects.requireNonNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -32,21 +33,28 @@
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
+import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.core.net.UrlConnectionFactory;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
public class ConfigurationSourceTest {
- private static final Path JAR_FILE = Paths.get("target", "test-classes", "jarfile.jar");
- private static final Path CONFIG_FILE = Paths.get("target", "test-classes", "log4j2-console.xml");
- private static final byte[] buffer = new byte[1024];
+ /**
+ * The path inside the jar created by {@link #prepareJarConfigURL} containing the configuration.
+ */
+ public static final String PATH_IN_JAR = "/config/console.xml";
+
+ private static final String CONFIG_FILE = "/config/ConfigurationSourceTest.xml";
+
+ @TempDir
+ private Path tempDir;
@Test
- public void testJira_LOG4J2_2770_byteArray() throws Exception {
+ void testJira_LOG4J2_2770_byteArray() throws Exception {
final ConfigurationSource configurationSource =
new ConfigurationSource(new ByteArrayInputStream(new byte[] {'a', 'b'}));
assertNotNull(configurationSource.resetInputStream());
@@ -54,20 +62,19 @@ public void testJira_LOG4J2_2770_byteArray() throws Exception {
/**
* Checks if the usage of 'jar:' URLs does not increase the file descriptor
- * count and the jar file can be deleted.
- *
- * @throws Exception
+ * count, and the jar file can be deleted.
*/
@Test
- public void testNoJarFileLeak() throws Exception {
- final URL jarConfigURL = prepareJarConfigURL();
+ void testNoJarFileLeak() throws Exception {
+ final Path jarFile = prepareJarConfigURL(tempDir);
+ final URL jarConfigURL = new URL("jar:" + jarFile.toUri().toURL() + "!" + PATH_IN_JAR);
final long expected = getOpenFileDescriptorCount();
UrlConnectionFactory.createConnection(jarConfigURL).getInputStream().close();
// This can only fail on UNIX
assertEquals(expected, getOpenFileDescriptorCount());
// This can only fail on Windows
try {
- Files.delete(JAR_FILE);
+ Files.delete(jarFile);
} catch (IOException e) {
fail(e);
}
@@ -75,7 +82,8 @@ public void testNoJarFileLeak() throws Exception {
@Test
public void testLoadConfigurationSourceFromJarFile() throws Exception {
- final URL jarConfigURL = prepareJarConfigURL();
+ final Path jarFile = prepareJarConfigURL(tempDir);
+ final URL jarConfigURL = new URL("jar:" + jarFile.toUri().toURL() + "!" + PATH_IN_JAR);
final long expectedFdCount = getOpenFileDescriptorCount();
ConfigurationSource configSource = ConfigurationSource.fromUri(jarConfigURL.toURI());
assertNotNull(configSource);
@@ -90,7 +98,7 @@ public void testLoadConfigurationSourceFromJarFile() throws Exception {
assertEquals(expectedFdCount, getOpenFileDescriptorCount());
// This can only fail on Windows
try {
- Files.delete(JAR_FILE);
+ Files.delete(jarFile);
} catch (IOException e) {
fail(e);
}
@@ -104,22 +112,18 @@ private long getOpenFileDescriptorCount() {
return 0L;
}
- public static URL prepareJarConfigURL() throws IOException {
- if (!Files.exists(JAR_FILE)) {
- final Manifest manifest = new Manifest();
- manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
- try (final OutputStream os = Files.newOutputStream(JAR_FILE);
- final JarOutputStream jar = new JarOutputStream(os, manifest);
- final InputStream config = Files.newInputStream(CONFIG_FILE)) {
- final JarEntry jarEntry = new JarEntry("config/console.xml");
- jar.putNextEntry(jarEntry);
- int len;
- while ((len = config.read(buffer)) != -1) {
- jar.write(buffer, 0, len);
- }
- jar.closeEntry();
- }
+ public static Path prepareJarConfigURL(Path dir) throws IOException {
+ Path jarFile = dir.resolve("jarFile.jar");
+ final Manifest manifest = new Manifest();
+ manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ try (final OutputStream os = Files.newOutputStream(jarFile);
+ final JarOutputStream jar = new JarOutputStream(os, manifest);
+ final InputStream config =
+ requireNonNull(ConfigurationSourceTest.class.getResourceAsStream(CONFIG_FILE))) {
+ final JarEntry jarEntry = new JarEntry("config/console.xml");
+ jar.putNextEntry(jarEntry);
+ IOUtils.copy(config, os);
}
- return new URL("jar:" + JAR_FILE.toUri().toURL() + "!/config/console.xml");
+ return jarFile;
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java
deleted file mode 100644
index 6782948a43d..00000000000
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/HttpThreadContextMapFilterTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.filter;
-
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.Base64;
-import java.util.Enumeration;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.config.Configurator;
-import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.junit.Assert;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
-import org.junitpioneer.jupiter.RetryingTest;
-
-/**
- * Unit test for simple App.
- */
-public class HttpThreadContextMapFilterTest implements MutableThreadContextMapFilter.FilterConfigUpdateListener {
-
- private static final String BASIC = "Basic ";
- private static final String expectedCreds = "log4j:log4j";
- private static Server server;
- private static final Base64.Decoder decoder = Base64.getDecoder();
- private static int port;
- static final String CONFIG = "log4j2-mutableFilter.xml";
- static LoggerContext loggerContext = null;
- static final File targetFile = new File("target/test-classes/testConfig.json");
- static final Path target = targetFile.toPath();
- CountDownLatch updated = new CountDownLatch(1);
-
- @BeforeAll
- public static void startServer() throws Exception {
- try {
- server = new Server(0);
- final ServletContextHandler context = new ServletContextHandler();
- final ServletHolder defaultServ = new ServletHolder("default", TestServlet.class);
- defaultServ.setInitParameter("resourceBase", System.getProperty("user.dir"));
- defaultServ.setInitParameter("dirAllowed", "true");
- context.addServlet(defaultServ, "/");
- server.setHandler(context);
-
- // Start Server
- server.start();
- port = ((ServerConnector) server.getConnectors()[0]).getLocalPort();
- try {
- Files.deleteIfExists(target);
- } catch (IOException ioe) {
- // Ignore this.
- }
- } catch (Throwable ex) {
- ex.printStackTrace();
- throw ex;
- }
- }
-
- @AfterAll
- public static void stopServer() throws Exception {
- if (server != null) {
- server.stop();
- }
- }
-
- @AfterEach
- public void after() {
- try {
- Files.deleteIfExists(target);
- } catch (IOException ioe) {
- // Ignore this.
- }
- if (loggerContext != null) {
- loggerContext.stop();
- loggerContext = null;
- }
- }
-
- @RetryingTest(maxAttempts = 5, suspendForMs = 10)
- public void filterTest() throws Exception {
- System.setProperty("log4j2.Configuration.allowedProtocols", "http");
- System.setProperty("logging.auth.username", "log4j");
- System.setProperty("logging.auth.password", "log4j");
- System.setProperty("configLocation", "http://localhost:" + port + "/testConfig.json");
- ThreadContext.put("loginId", "rgoers");
- Path source = new File("target/test-classes/emptyConfig.json").toPath();
- Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
- final long fileTime = targetFile.lastModified() - 2000;
- assertTrue(targetFile.setLastModified(fileTime));
- loggerContext = Configurator.initialize(null, CONFIG);
- assertNotNull(loggerContext);
- final Appender app = loggerContext.getConfiguration().getAppender("List");
- assertNotNull(app);
- assertTrue(app instanceof ListAppender);
- final MutableThreadContextMapFilter filter =
- (MutableThreadContextMapFilter) loggerContext.getConfiguration().getFilter();
- assertNotNull(filter);
- filter.registerListener(this);
- final Logger logger = loggerContext.getLogger("Test");
- logger.debug("This is a test");
- Assertions.assertEquals(0, ((ListAppender) app).getEvents().size());
- source = new File("target/test-classes/filterConfig.json").toPath();
- Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
- assertNotEquals(fileTime, targetFile.lastModified());
- if (!updated.await(5, TimeUnit.SECONDS)) {
- fail("File update was not detected");
- }
- updated = new CountDownLatch(1);
- logger.debug("This is a test");
- Assertions.assertEquals(1, ((ListAppender) app).getEvents().size());
- Assertions.assertTrue(Files.deleteIfExists(target));
- if (!updated.await(5, TimeUnit.SECONDS)) {
- fail("File update for delete was not detected");
- }
- }
-
- public static class TestServlet extends DefaultServlet {
-
- private static final long serialVersionUID = -2885158530511450659L;
-
- @Override
- protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
- throws ServletException, IOException {
- final Enumeration headers = request.getHeaders(HttpHeader.AUTHORIZATION.toString());
- if (headers == null) {
- response.sendError(401, "No Auth header");
- return;
- }
- while (headers.hasMoreElements()) {
- final String authData = headers.nextElement();
- Assert.assertTrue("Not a Basic auth header", authData.startsWith(BASIC));
- final String credentials = new String(decoder.decode(authData.substring(BASIC.length())));
- if (!expectedCreds.equals(credentials)) {
- response.sendError(401, "Invalid credentials");
- return;
- }
- }
- if (request.getServletPath().equals("/testConfig.json")) {
- final File file = new File("target/test-classes/testConfig.json");
- if (!file.exists()) {
- response.sendError(404, "File not found");
- return;
- }
- final long modifiedSince = request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString());
- final long lastModified = (file.lastModified() / 1000) * 1000;
- if (modifiedSince > 0 && lastModified <= modifiedSince) {
- response.setStatus(304);
- return;
- }
- response.setDateHeader(HttpHeader.LAST_MODIFIED.toString(), lastModified);
- response.setContentLengthLong(file.length());
- Files.copy(file.toPath(), response.getOutputStream());
- response.getOutputStream().flush();
- response.setStatus(200);
- } else {
- response.sendError(400, "Unsupported request");
- }
- }
- }
-
- @Override
- public void onEvent() {
- updated.countDown();
- }
-}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilterTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilterTest.java
index 598ce46ac29..a2d3919d1dd 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilterTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilterTest.java
@@ -16,94 +16,228 @@
*/
package org.apache.logging.log4j.core.filter;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.logging.log4j.core.net.WireMockUtil.createMapping;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-import java.io.File;
-import java.io.IOException;
+import com.github.tomakehurst.wiremock.client.BasicCredentials;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
-import java.util.concurrent.CountDownLatch;
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.test.TestProperties;
+import org.apache.logging.log4j.test.junit.SetTestProperty;
+import org.apache.logging.log4j.test.junit.UsingTestProperties;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Assertions;
-import org.junitpioneer.jupiter.RetryingTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
/**
* Unit test for simple App.
*/
-public class MutableThreadContextMapFilterTest implements MutableThreadContextMapFilter.FilterConfigUpdateListener {
+@SetTestProperty(key = "log4j2.configurationAllowedProtocols", value = "http,https")
+@SetTestProperty(key = "log4j2.configurationPassword", value = "log4j")
+@SetTestProperty(key = "log4j2.configurationUsername", value = "log4j")
+@UsingTestProperties
+@WireMockTest
+class MutableThreadContextMapFilterTest implements MutableThreadContextMapFilter.FilterConfigUpdateListener {
- static final String CONFIG = "log4j2-mutableFilter.xml";
- static LoggerContext loggerContext = null;
- static File targetFile = new File("target/test-classes/testConfig.json");
- static Path target = targetFile.toPath();
- CountDownLatch updated = new CountDownLatch(1);
+ private static final BasicCredentials CREDENTIALS = new BasicCredentials("log4j", "log4j");
+ private static final String FILE_NAME = "testConfig.json";
+ private static final String URL_PATH = "/" + FILE_NAME;
+ private static final String JSON = "application/json";
+
+ private static final byte[] EMPTY_CONFIG = ("{" //
+ + " \"configs\":{}" //
+ + "}")
+ .getBytes(UTF_8);
+ private static final byte[] FILTER_CONFIG = ("{" //
+ + " \"configs\": {" //
+ + " \"loginId\": [\"rgoers\", \"adam\"]," //
+ + " \"corpAcctNumber\": [\"30510263\"]" //
+ + " }" //
+ + "}")
+ .getBytes(UTF_8);
+
+ private static final String CONFIG = "filter/MutableThreadContextMapFilterTest.xml";
+ private static LoggerContext loggerContext = null;
+ private final ReentrantLock lock = new ReentrantLock();
+ private final Condition filterUpdated = lock.newCondition();
+ private final Condition resultVerified = lock.newCondition();
+ private Exception exception;
@AfterEach
- public void after() {
- try {
- Files.deleteIfExists(target);
- } catch (IOException ioe) {
- // Ignore this.
- }
+ void cleanup() {
+ exception = null;
ThreadContext.clearMap();
- loggerContext.stop();
- loggerContext = null;
+ if (loggerContext != null) {
+ loggerContext.stop();
+ loggerContext = null;
+ }
}
- @RetryingTest(maxAttempts = 5, suspendForMs = 10)
- public void filterTest() throws Exception {
- System.setProperty("configLocation", "target/test-classes/testConfig.json");
- ThreadContext.put("loginId", "rgoers");
- Path source = new File("target/test-classes/emptyConfig.json").toPath();
- Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
- final long fileTime = targetFile.lastModified() - 1000;
- assertTrue(targetFile.setLastModified(fileTime));
- loggerContext = Configurator.initialize(null, CONFIG);
- assertNotNull(loggerContext);
- final Appender app = loggerContext.getConfiguration().getAppender("List");
- assertNotNull(app);
- assertTrue(app instanceof ListAppender);
- final MutableThreadContextMapFilter filter =
- (MutableThreadContextMapFilter) loggerContext.getConfiguration().getFilter();
+ @Test
+ void file_location_works(TestProperties properties, @TempDir Path dir) throws Exception {
+ // Set up the test file.
+ Instant now = Instant.now().truncatedTo(ChronoUnit.SECONDS);
+ Instant before = now.minus(1, ChronoUnit.MINUTES);
+ Instant after = now.plus(1, ChronoUnit.MINUTES);
+ Path testConfig = dir.resolve("testConfig.json");
+ properties.setProperty("configLocation", testConfig.toString());
+ try (final InputStream inputStream = new ByteArrayInputStream(EMPTY_CONFIG)) {
+ Files.copy(inputStream, testConfig);
+ Files.setLastModifiedTime(testConfig, FileTime.from(before));
+ }
+ // Setup Log4j
+ ConfigurationSource source =
+ ConfigurationSource.fromResource(CONFIG, getClass().getClassLoader());
+ Configuration configuration = ConfigurationFactory.getInstance().getConfiguration(null, source);
+ configuration.initialize(); // To create the components
+ final ListAppender app = configuration.getAppender("LIST");
+ assertThat(app).isNotNull();
+ final MutableThreadContextMapFilter filter = (MutableThreadContextMapFilter) configuration.getFilter();
assertNotNull(filter);
filter.registerListener(this);
- final Logger logger = loggerContext.getLogger("Test");
- logger.debug("This is a test");
- Assertions.assertEquals(0, ((ListAppender) app).getEvents().size());
- source = new File("target/test-classes/filterConfig.json").toPath();
- String msg = null;
- boolean copied = false;
- for (int i = 0; i < 5 && !copied; ++i) {
- Thread.sleep(100 + (100 * i));
- try {
- Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
- copied = true;
- } catch (Exception ex) {
- msg = ex.getMessage();
+
+ lock.lock();
+ try {
+ // Starts the configuration
+ loggerContext = Configurator.initialize(getClass().getClassLoader(), configuration);
+ assertNotNull(loggerContext);
+
+ final Logger logger = loggerContext.getLogger(MutableThreadContextMapFilterTest.class);
+
+ assertThat(filterUpdated.await(20, TimeUnit.SECONDS))
+ .as("Initial configuration was loaded")
+ .isTrue();
+ ThreadContext.put("loginId", "rgoers");
+ logger.debug("This is a test");
+ assertThat(app.getEvents()).isEmpty();
+
+ // Prepare the second test case: updated config
+ try (final InputStream inputStream = new ByteArrayInputStream(FILTER_CONFIG)) {
+ Files.copy(inputStream, testConfig, StandardCopyOption.REPLACE_EXISTING);
+ Files.setLastModifiedTime(testConfig, FileTime.from(after));
}
+ resultVerified.signalAll();
+
+ assertThat(filterUpdated.await(20, TimeUnit.SECONDS))
+ .as("Updated configuration was loaded")
+ .isTrue();
+ logger.debug("This is a test");
+ assertThat(app.getEvents()).hasSize(1);
+
+ // Prepare the third test case: removed config
+ Files.delete(testConfig);
+ resultVerified.signalAll();
+
+ assertThat(filterUpdated.await(20, TimeUnit.SECONDS))
+ .as("Configuration removal was detected")
+ .isTrue();
+ logger.debug("This is a test");
+ assertThat(app.getEvents()).hasSize(1);
+ resultVerified.signalAll();
+ } finally {
+ lock.unlock();
}
- assertTrue(copied, "File not copied: " + msg);
- assertNotEquals(fileTime, targetFile.lastModified());
- if (!updated.await(5, TimeUnit.SECONDS)) {
- fail("File update was not detected");
+ assertThat(exception).as("Asynchronous exception").isNull();
+ }
+
+ @Test
+ void http_location_works(TestProperties properties, WireMockRuntimeInfo info) throws Exception {
+ WireMock wireMock = info.getWireMock();
+ // Setup WireMock
+ // The HTTP Last-Modified header has a precision of 1 second
+ ZonedDateTime now = LocalDateTime.now().atZone(ZoneOffset.UTC);
+ ZonedDateTime before = now.minusMinutes(1);
+ ZonedDateTime after = now.plusMinutes(1);
+ properties.setProperty("configLocation", info.getHttpBaseUrl() + URL_PATH);
+ // Setup Log4j
+ ConfigurationSource source =
+ ConfigurationSource.fromResource(CONFIG, getClass().getClassLoader());
+ Configuration configuration = ConfigurationFactory.getInstance().getConfiguration(null, source);
+ configuration.initialize(); // To create the components
+ final ListAppender app = configuration.getAppender("LIST");
+ assertThat(app).isNotNull();
+ final MutableThreadContextMapFilter filter = (MutableThreadContextMapFilter) configuration.getFilter();
+ assertNotNull(filter);
+ filter.registerListener(this);
+ lock.lock();
+ try {
+ // Prepare the first test case: original empty config
+ wireMock.importStubMappings(createMapping(URL_PATH, CREDENTIALS, EMPTY_CONFIG, JSON, before));
+ // Starts the configuration
+ loggerContext = Configurator.initialize(getClass().getClassLoader(), configuration);
+ assertNotNull(loggerContext);
+
+ final Logger logger = loggerContext.getLogger(MutableThreadContextMapFilterTest.class);
+
+ assertThat(filterUpdated.await(2, TimeUnit.SECONDS))
+ .as("Initial configuration was loaded")
+ .isTrue();
+ ThreadContext.put("loginId", "rgoers");
+ logger.debug("This is a test");
+ assertThat(app.getEvents()).isEmpty();
+
+ // Prepare the second test case: updated config
+ wireMock.removeMappings();
+ wireMock.importStubMappings(createMapping(URL_PATH, CREDENTIALS, FILTER_CONFIG, JSON, after));
+ resultVerified.signalAll();
+
+ assertThat(filterUpdated.await(2, TimeUnit.SECONDS))
+ .as("Updated configuration was loaded")
+ .isTrue();
+ logger.debug("This is a test");
+ assertThat(app.getEvents()).hasSize(1);
+
+ // Prepare the third test case: removed config
+ wireMock.removeMappings();
+ resultVerified.signalAll();
+
+ assertThat(filterUpdated.await(2, TimeUnit.SECONDS))
+ .as("Configuration removal was detected")
+ .isTrue();
+ logger.debug("This is a test");
+ assertThat(app.getEvents()).hasSize(1);
+ resultVerified.signalAll();
+ } finally {
+ lock.unlock();
}
- logger.debug("This is a test");
- Assertions.assertEquals(1, ((ListAppender) app).getEvents().size());
+ assertThat(exception).as("Asynchronous exception").isNull();
}
@Override
public void onEvent() {
- updated.countDown();
+ lock.lock();
+ try {
+ filterUpdated.signalAll();
+ resultVerified.await();
+ } catch (final InterruptedException e) {
+ exception = e;
+ } finally {
+ lock.unlock();
+ }
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java
index e6bb7d59281..265c538da88 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java
@@ -16,20 +16,24 @@
*/
package org.apache.logging.log4j.core.net;
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static java.util.Objects.requireNonNull;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
import static javax.servlet.http.HttpServletResponse.SC_OK;
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+import static org.apache.logging.log4j.core.config.ConfigurationSourceTest.PATH_IN_JAR;
+import static org.apache.logging.log4j.core.net.WireMockUtil.createMapping;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
+import com.github.tomakehurst.wiremock.client.BasicCredentials;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import com.sun.management.UnixOperatingSystemMXBean;
-import java.io.File;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
@@ -38,101 +42,102 @@
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
-import java.util.Base64;
-import java.util.Enumeration;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.ConfigurationSourceTest;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
+import org.apache.logging.log4j.core.util.AuthorizationProvider;
+import org.apache.logging.log4j.test.junit.SetTestProperty;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
+import org.junit.jupiter.api.io.TempDir;
import org.junitpioneer.jupiter.RetryingTest;
/**
* Tests the UrlConnectionFactory
*/
-public class UrlConnectionFactoryTest {
+@WireMockTest
+@SetTestProperty(key = "log4j2.configurationAllowedProtocols", value = "jar,http")
+class UrlConnectionFactoryTest {
private static final Logger LOGGER = LogManager.getLogger(UrlConnectionFactoryTest.class);
- private static final String BASIC = "Basic ";
- private static final String expectedCreds = "testuser:password";
- private static Server server;
- private static final Base64.Decoder decoder = Base64.getDecoder();
- private static int port;
- private static final int BUF_SIZE = 1024;
- @BeforeAll
- public static void startServer() throws Exception {
- try {
- server = new Server(0);
- final ServletContextHandler context = new ServletContextHandler();
- final ServletHolder defaultServ = new ServletHolder("default", TestServlet.class);
- defaultServ.setInitParameter("resourceBase", System.getProperty("user.dir"));
- defaultServ.setInitParameter("dirAllowed", "true");
- context.addServlet(defaultServ, "/");
- server.setHandler(context);
-
- // Start Server
- server.start();
- port = ((ServerConnector) server.getConnectors()[0]).getLocalPort();
- } catch (Throwable ex) {
- ex.printStackTrace();
- throw ex;
+ private static final String URL_PATH = "/log4j2-config.xml";
+ private static final BasicCredentials CREDENTIALS = new BasicCredentials("testUser", "password");
+ private static final byte[] CONFIG_FILE_BODY;
+ private static final String CONTENT_TYPE = "application/xml";
+
+ static {
+ try (InputStream input = requireNonNull(
+ UrlConnectionFactoryTest.class.getClassLoader().getResourceAsStream("log4j2-config.xml"))) {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ IOUtils.copy(input, output);
+ CONFIG_FILE_BODY = output.toByteArray();
+ } catch (IOException e) {
+ throw new AssertionError(e);
}
}
- @AfterAll
- public static void stopServer() throws Exception {
- server.stop();
+ @AfterEach
+ void cleanup(WireMockRuntimeInfo info) {
+ info.getWireMock().removeMappings();
}
@Test
- public void testBadCrdentials() throws Exception {
- System.setProperty("log4j2.Configuration.username", "foo");
- System.setProperty("log4j2.Configuration.password", "bar");
- System.setProperty("log4j2.Configuration.allowedProtocols", "http");
- final URI uri = new URI("http://localhost:" + port + "/log4j2-config.xml");
+ @SetTestProperty(key = "log4j2.configurationUsername", value = "foo")
+ @SetTestProperty(key = "log4j2.configurationPassword", value = "bar")
+ void testBadCredentials(WireMockRuntimeInfo info) throws Exception {
+ WireMock wireMock = info.getWireMock();
+ // RFC 1123 format rounds to full seconds
+ ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.SECONDS);
+ wireMock.importStubMappings(createMapping(URL_PATH, CREDENTIALS, CONFIG_FILE_BODY, CONTENT_TYPE, now));
+ final URI uri = new URI(info.getHttpBaseUrl() + URL_PATH);
final ConfigurationSource source = ConfigurationSource.fromUri(uri);
assertNull(source, "A ConfigurationSource should not have been returned");
}
@Test
- public void withAuthentication() throws Exception {
- System.setProperty("log4j2.Configuration.username", "testuser");
- System.setProperty("log4j2.Configuration.password", "password");
- System.setProperty("log4j2.Configuration.allowedProtocols", "http");
- final URI uri = new URI("http://localhost:" + port + "/log4j2-config.xml");
+ @SetTestProperty(key = "log4j2.configurationUsername", value = "testUser")
+ @SetTestProperty(key = "log4j2.configurationPassword", value = "password")
+ public void withAuthentication(WireMockRuntimeInfo info) throws Exception {
+ WireMock wireMock = info.getWireMock();
+ // RFC 1123 format rounds to full seconds
+ ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.SECONDS);
+ wireMock.importStubMappings(createMapping(URL_PATH, CREDENTIALS, CONFIG_FILE_BODY, CONTENT_TYPE, now));
+ final URI uri = new URI(info.getHttpBaseUrl() + URL_PATH);
final ConfigurationSource source = ConfigurationSource.fromUri(uri);
assertNotNull(source, "No ConfigurationSource returned");
final InputStream is = source.getInputStream();
assertNotNull(is, "No data returned");
is.close();
final long lastModified = source.getLastModified();
+ assertThat(lastModified).isEqualTo(now.toInstant().toEpochMilli());
int result = verifyNotModified(uri, lastModified);
assertEquals(SC_NOT_MODIFIED, result, "File was modified");
- final File file = new File("target/classes/log4j2-config.xml");
- if (!file.setLastModified(System.currentTimeMillis())) {
- fail("Unable to set last modified time");
- }
+
+ wireMock.removeMappings();
+ now = now.plusMinutes(5);
+ wireMock.importStubMappings(createMapping(URL_PATH, CREDENTIALS, CONFIG_FILE_BODY, CONTENT_TYPE, now));
result = verifyNotModified(uri, lastModified);
assertEquals(SC_OK, result, "File was not modified");
}
private int verifyNotModified(final URI uri, final long lastModifiedMillis) throws Exception {
- final HttpURLConnection urlConnection =
- UrlConnectionFactory.createConnection(uri.toURL(), lastModifiedMillis, null, null);
+ AuthorizationProvider provider = ConfigurationFactory.authorizationProvider(PropertiesUtil.getProperties());
+ HttpURLConnection urlConnection =
+ UrlConnectionFactory.createConnection(uri.toURL(), lastModifiedMillis, null, provider);
urlConnection.connect();
try {
@@ -145,20 +150,39 @@ private int verifyNotModified(final URI uri, final long lastModifiedMillis) thro
@RetryingTest(maxAttempts = 5, suspendForMs = 1000)
@DisabledOnOs(value = OS.WINDOWS, disabledReason = "Fails frequently on Windows (#2011)")
- public void testNoJarFileLeak() throws Exception {
- ConfigurationSourceTest.prepareJarConfigURL();
- final URL url = new File("target/test-classes/jarfile.jar").toURI().toURL();
+ @SetTestProperty(key = "log4j2.configurationUsername", value = "testUser")
+ @SetTestProperty(key = "log4j2.configurationPassword", value = "password")
+ void testNoJarFileLeak(@TempDir Path dir, WireMockRuntimeInfo info) throws Exception {
+ Path jarFile = ConfigurationSourceTest.prepareJarConfigURL(dir);
// Retrieve using 'file:'
- URL jarUrl = new URL("jar:" + url.toString() + "!/config/console.xml");
+ URL jarUrl = new URL("jar:" + jarFile.toUri().toURL() + "!" + PATH_IN_JAR);
long expected = getOpenFileDescriptorCount();
UrlConnectionFactory.createConnection(jarUrl).getInputStream().close();
assertEquals(expected, getOpenFileDescriptorCount());
+
+ // Prepare mock
+ ByteArrayOutputStream body = new ByteArrayOutputStream();
+ try (InputStream inputStream = Files.newInputStream(jarFile)) {
+ IOUtils.copy(inputStream, body);
+ }
+ WireMock wireMock = info.getWireMock();
+ wireMock.register(WireMock.get("/jarFile.jar")
+ .willReturn(
+ aResponse().withStatus(200).withBodyFile("jarFile.jar").withBody(body.toByteArray())));
// Retrieve using 'http:'
- jarUrl = new URL("jar:http://localhost:" + port + "/jarfile.jar!/config/console.xml");
- final File tmpDir = new File(System.getProperty("java.io.tmpdir"));
- expected = tmpDir.list().length;
+ jarUrl = new URL("jar:" + info.getHttpBaseUrl() + "/jarFile.jar!" + PATH_IN_JAR);
+ // URLConnection leaves JAR files in the temporary directory
+ Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));
+ List expectedFiles;
+ try (Stream stream = Files.list(tmpDir)) {
+ expectedFiles = stream.collect(Collectors.toList());
+ }
UrlConnectionFactory.createConnection(jarUrl).getInputStream().close();
- assertEquals(expected, tmpDir.list().length, "File descriptor leak");
+ List actualFiles;
+ try (Stream stream = Files.list(tmpDir)) {
+ actualFiles = stream.collect(Collectors.toList());
+ }
+ assertThat(actualFiles).containsExactlyElementsOf(expectedFiles);
}
private long getOpenFileDescriptorCount() {
@@ -168,53 +192,4 @@ private long getOpenFileDescriptorCount() {
}
return 0L;
}
-
- public static class TestServlet extends DefaultServlet {
-
- private static final long serialVersionUID = -2885158530511450659L;
-
- @Override
- protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
- throws ServletException, IOException {
- final Enumeration headers = request.getHeaders(HttpHeader.AUTHORIZATION.toString());
- if (headers == null) {
- response.sendError(SC_UNAUTHORIZED, "No Auth header");
- return;
- }
- while (headers.hasMoreElements()) {
- final String authData = headers.nextElement();
- assertTrue(authData.startsWith(BASIC), "Not a Basic auth header");
- final String credentials = new String(decoder.decode(authData.substring(BASIC.length())));
- if (!expectedCreds.equals(credentials)) {
- response.sendError(SC_UNAUTHORIZED, "Invalid credentials");
- return;
- }
- }
- final String servletPath = request.getServletPath();
- if (servletPath != null) {
- File file = new File("target/classes" + servletPath);
- if (!file.exists()) {
- file = new File("target/test-classes" + servletPath);
- }
- if (!file.exists()) {
- response.sendError(SC_NOT_FOUND);
- return;
- }
- final long modifiedSince = request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString());
- final long lastModified = (file.lastModified() / 1000) * 1000;
- LOGGER.debug("LastModified: {}, modifiedSince: {}", lastModified, modifiedSince);
- if (modifiedSince > 0 && lastModified <= modifiedSince) {
- response.setStatus(SC_NOT_MODIFIED);
- return;
- }
- response.setDateHeader(HttpHeader.LAST_MODIFIED.toString(), lastModified);
- response.setContentLengthLong(file.length());
- Files.copy(file.toPath(), response.getOutputStream());
- response.getOutputStream().flush();
- response.setStatus(SC_OK);
- } else {
- response.sendError(SC_BAD_REQUEST, "Unsupported request");
- }
- }
- }
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/WireMockUtil.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/WireMockUtil.java
new file mode 100644
index 00000000000..f8655742320
--- /dev/null
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/net/WireMockUtil.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.net;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.absent;
+import static com.github.tomakehurst.wiremock.client.WireMock.after;
+import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
+import static com.github.tomakehurst.wiremock.client.WireMock.before;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToDateTime;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.notContaining;
+import static com.github.tomakehurst.wiremock.stubbing.StubImport.stubImport;
+import static com.google.common.net.HttpHeaders.AUTHORIZATION;
+import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
+import static com.google.common.net.HttpHeaders.IF_MODIFIED_SINCE;
+import static com.google.common.net.HttpHeaders.LAST_MODIFIED;
+
+import com.github.tomakehurst.wiremock.client.BasicCredentials;
+import com.github.tomakehurst.wiremock.stubbing.StubImport;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class WireMockUtil {
+
+ private static final DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC);
+
+ /**
+ * Establishes a set of mapping to serve a file
+ *
+ * @param urlPath The URL path of the served file
+ * @param credentials The credentials to use for authentication
+ * @param body The body of the file
+ * @param contentType The MIME content type of the file
+ * @param lastModified The last modification date of the file
+ * @return A set of mappings
+ */
+ public static StubImport createMapping(
+ String urlPath, BasicCredentials credentials, byte[] body, String contentType, ZonedDateTime lastModified) {
+ int idx = urlPath.lastIndexOf('/');
+ String fileName = idx == -1 ? urlPath : urlPath.substring(idx + 1);
+ return stubImport()
+ // Lack of authentication data
+ .stub(get(anyUrl())
+ .withHeader(AUTHORIZATION, absent())
+ .willReturn(aResponse().withStatus(401).withStatusMessage("Not Authenticated")))
+ // Wrong authentication data
+ .stub(get(anyUrl())
+ .withHeader(AUTHORIZATION, notContaining(credentials.asAuthorizationHeaderValue()))
+ .willReturn(aResponse().withStatus(403).withStatusMessage("Not Authorized")))
+ // Serves the file
+ .stub(get(urlPath)
+ .withBasicAuth(credentials.username, credentials.password)
+ .withHeader(IF_MODIFIED_SINCE, before(lastModified).or(absent()))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withBodyFile(fileName)
+ .withBody(body)
+ .withHeader(LAST_MODIFIED, formatter.format(lastModified))
+ .withHeader(CONTENT_TYPE, contentType)))
+ // The file was not updated since lastModified
+ .stub(get(urlPath)
+ .withBasicAuth(credentials.username, credentials.password)
+ .withHeader(IF_MODIFIED_SINCE, after(lastModified).or(equalToDateTime(lastModified)))
+ .willReturn(
+ aResponse().withStatus(304).withHeader(LAST_MODIFIED, formatter.format(lastModified))))
+ .build();
+ }
+}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/HttpWatcherTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/HttpWatcherTest.java
new file mode 100644
index 00000000000..774f36d5aa6
--- /dev/null
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/HttpWatcherTest.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.util;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
+import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import com.github.tomakehurst.wiremock.stubbing.StubMapping;
+import java.net.URL;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationListener;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.HttpWatcher;
+import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.apache.logging.log4j.core.net.UrlConnectionFactory;
+import org.apache.logging.log4j.test.junit.SetTestProperty;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test the WatchManager
+ */
+@SetTestProperty(key = UrlConnectionFactory.ALLOWED_PROTOCOLS, value = "http,https")
+@WireMockTest
+class HttpWatcherTest {
+
+ private static final DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC);
+ private static final String XML = "application/xml";
+
+ @Test
+ void testModified(final WireMockRuntimeInfo info) throws Exception {
+ final WireMock wireMock = info.getWireMock();
+
+ final BlockingQueue queue = new LinkedBlockingQueue<>();
+ List listeners = singletonList(new TestConfigurationListener(queue, "log4j-test1.xml"));
+ // HTTP Last-Modified is in seconds
+ Instant now = Instant.now().truncatedTo(ChronoUnit.SECONDS);
+ Instant previous = now.minus(5, ChronoUnit.MINUTES);
+ final URL url = new URL(info.getHttpBaseUrl() + "/log4j-test1.xml");
+ final Configuration configuration = createConfiguration(url);
+
+ final StubMapping stubMapping = wireMock.register(get("/log4j-test1.xml")
+ .willReturn(aResponse()
+ .withBodyFile("log4j-test1.xml")
+ .withStatus(200)
+ .withHeader("Last-Modified", formatter.format(previous))
+ .withHeader("Content-Type", XML)));
+ Watcher watcher = new HttpWatcher(configuration, null, listeners, previous.toEpochMilli());
+ watcher.watching(new Source(url));
+ try {
+ assertThat(watcher.isModified()).as("File was modified").isTrue();
+ assertThat(watcher.getLastModified()).as("File modification time").isEqualTo(previous.toEpochMilli());
+ // Check if listeners are correctly called
+ // Note: listeners are called asynchronously
+ watcher.modified();
+ String str = queue.poll(1, TimeUnit.SECONDS);
+ assertThat(str).isEqualTo("log4j-test1.xml");
+ ConfigurationSource configurationSource = configuration.getConfigurationSource();
+ // Check that the last modified time of the ConfigurationSource was modified as well
+ // See: https://github.com/apache/logging-log4j2/issues/2937
+ assertThat(configurationSource.getLastModified())
+ .as("Last modification time of current ConfigurationSource")
+ .isEqualTo(0L);
+ configurationSource = configurationSource.resetInputStream();
+ assertThat(configurationSource.getLastModified())
+ .as("Last modification time of next ConfigurationSource")
+ .isEqualTo(previous.toEpochMilli());
+ } finally {
+ wireMock.removeStubMapping(stubMapping);
+ }
+ }
+
+ @Test
+ void testNotModified(final WireMockRuntimeInfo info) throws Exception {
+ final WireMock wireMock = info.getWireMock();
+
+ final BlockingQueue queue = new LinkedBlockingQueue<>();
+ final List listeners =
+ singletonList(new TestConfigurationListener(queue, "log4j-test2.xml"));
+ // HTTP Last-Modified is in seconds
+ Instant now = Instant.now().truncatedTo(ChronoUnit.SECONDS);
+ Instant previous = now.minus(5, ChronoUnit.MINUTES);
+ final URL url = new URL(info.getHttpBaseUrl() + "/log4j-test2.xml");
+ final Configuration configuration = createConfiguration(url);
+
+ final StubMapping stubMapping = wireMock.register(get("/log4j-test2.xml")
+ .willReturn(aResponse()
+ .withStatus(304)
+ .withHeader("Last-Modified", formatter.format(now) + " GMT")
+ .withHeader("Content-Type", XML)));
+ Watcher watcher = new HttpWatcher(configuration, null, listeners, previous.toEpochMilli());
+ watcher.watching(new Source(url));
+ try {
+ assertThat(watcher.isModified()).as("File was modified").isFalse();
+ // If the file was not modified, neither should be the last modification time
+ assertThat(watcher.getLastModified()).isEqualTo(previous.toEpochMilli());
+ // Check that the last modified time of the ConfigurationSource was not modified either
+ ConfigurationSource configurationSource = configuration.getConfigurationSource();
+ assertThat(configurationSource.getLastModified())
+ .as("Last modification time of current ConfigurationSource")
+ .isEqualTo(0L);
+ configurationSource = configurationSource.resetInputStream();
+ assertThat(configurationSource.getLastModified())
+ .as("Last modification time of next ConfigurationSource")
+ .isEqualTo(0L);
+ } finally {
+ wireMock.removeStubMapping(stubMapping);
+ }
+ }
+
+ // Creates a configuration with a predefined configuration source
+ private static Configuration createConfiguration(URL url) {
+ ConfigurationSource configurationSource = new ConfigurationSource(new Source(url), new byte[0], 0L);
+ return new AbstractConfiguration(null, configurationSource) {};
+ }
+
+ private static class TestConfigurationListener implements ConfigurationListener {
+ private final Queue queue;
+ private final String name;
+
+ public TestConfigurationListener(final Queue queue, final String name) {
+ this.queue = queue;
+ this.name = name;
+ }
+
+ @Override
+ public void onChange(final Reconfigurable reconfigurable) {
+ // System.out.println("Reconfiguration detected for " + name);
+ queue.add(name);
+ }
+ }
+}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java
deleted file mode 100644
index c433f834863..00000000000
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.logging.log4j.core.util;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.get;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
-import com.github.tomakehurst.wiremock.client.WireMock;
-import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
-import com.github.tomakehurst.wiremock.junit5.WireMockTest;
-import com.github.tomakehurst.wiremock.stubbing.StubMapping;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Queue;
-import java.util.TimeZone;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.ConfigurationListener;
-import org.apache.logging.log4j.core.config.ConfigurationScheduler;
-import org.apache.logging.log4j.core.config.DefaultConfiguration;
-import org.apache.logging.log4j.core.config.HttpWatcher;
-import org.apache.logging.log4j.core.config.Reconfigurable;
-import org.apache.logging.log4j.core.net.UrlConnectionFactory;
-import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
-import org.apache.logging.log4j.test.junit.SetTestProperty;
-import org.apache.logging.log4j.util.PropertiesUtil;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test the WatchManager
- */
-@SetTestProperty(key = UrlConnectionFactory.ALLOWED_PROTOCOLS, value = "http,https")
-@WireMockTest
-public class WatchHttpTest {
-
- private static final String FORCE_RUN_KEY = WatchHttpTest.class.getSimpleName() + ".forceRun";
- private final String file = "log4j-test1.xml";
- private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
- private static FastDateFormat formatter = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss", UTC);
- private static final String XML = "application/xml";
-
- private static final boolean IS_WINDOWS = PropertiesUtil.getProperties().isOsWindows();
-
- @Test
- public void testWatchManager(final WireMockRuntimeInfo info) throws Exception {
- assumeTrue(!IS_WINDOWS || Boolean.getBoolean(FORCE_RUN_KEY));
- final WireMock wireMock = info.getWireMock();
-
- final BlockingQueue queue = new LinkedBlockingQueue<>();
- final List listeners = new ArrayList<>();
- listeners.add(new TestConfigurationListener(queue, "log4j-test1.xml"));
- final Calendar now = Calendar.getInstance(UTC);
- final Calendar previous = now;
- previous.add(Calendar.MINUTE, -5);
- final Configuration configuration = new DefaultConfiguration();
- final URL url = new URL(info.getHttpBaseUrl() + "/log4j-test1.xml");
- final StubMapping stubMapping = wireMock.register(get(urlPathEqualTo("/log4j-test1.xml"))
- .willReturn(aResponse()
- .withBodyFile(file)
- .withStatus(200)
- .withHeader("Last-Modified", formatter.format(previous) + " GMT")
- .withHeader("Content-Type", XML)));
- final ConfigurationScheduler scheduler = new ConfigurationScheduler();
- scheduler.incrementScheduledItems();
- final WatchManager watchManager = new WatchManager(scheduler);
- watchManager.setIntervalSeconds(1);
- scheduler.start();
- watchManager.start();
- try {
- watchManager.watch(
- new Source(url), new HttpWatcher(configuration, null, listeners, previous.getTimeInMillis()));
- final String str = queue.poll(3, TimeUnit.SECONDS);
- assertNotNull("File change not detected", str);
- } finally {
- watchManager.stop();
- scheduler.stop();
- wireMock.removeStubMapping(stubMapping);
- }
- }
-
- @Test
- public void testNotModified(final WireMockRuntimeInfo info) throws Exception {
- assumeTrue(!IS_WINDOWS || Boolean.getBoolean(FORCE_RUN_KEY));
- final WireMock wireMock = info.getWireMock();
-
- final BlockingQueue queue = new LinkedBlockingQueue<>();
- final List listeners = new ArrayList<>();
- listeners.add(new TestConfigurationListener(queue, "log4j-test2.xml"));
- final TimeZone timeZone = TimeZone.getTimeZone("UTC");
- final Calendar now = Calendar.getInstance(timeZone);
- final Calendar previous = now;
- previous.add(Calendar.MINUTE, -5);
- final Configuration configuration = new DefaultConfiguration();
- final URL url = new URL(info.getHttpBaseUrl() + "/log4j-test2.xml");
- final StubMapping stubMapping = wireMock.register(get(urlPathEqualTo("/log4j-test2.xml"))
- .willReturn(aResponse()
- .withBodyFile(file)
- .withStatus(304)
- .withHeader("Last-Modified", formatter.format(now) + " GMT")
- .withHeader("Content-Type", XML)));
- final ConfigurationScheduler scheduler = new ConfigurationScheduler();
- scheduler.incrementScheduledItems();
- final WatchManager watchManager = new WatchManager(scheduler);
- watchManager.setIntervalSeconds(1);
- scheduler.start();
- watchManager.start();
- try {
- watchManager.watch(
- new Source(url), new HttpWatcher(configuration, null, listeners, previous.getTimeInMillis()));
- final String str = queue.poll(2, TimeUnit.SECONDS);
- assertNull("File changed.", str);
- } finally {
- watchManager.stop();
- scheduler.stop();
- wireMock.removeStubMapping(stubMapping);
- }
- }
-
- private static class TestConfigurationListener implements ConfigurationListener {
- private final Queue queue;
- private final String name;
-
- public TestConfigurationListener(final Queue queue, final String name) {
- this.queue = queue;
- this.name = name;
- }
-
- @Override
- public void onChange(final Reconfigurable reconfigurable) {
- // System.out.println("Reconfiguration detected for " + name);
- queue.add(name);
- }
- }
-}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchManagerTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchManagerTest.java
index 68b3baaca60..49269d7134f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchManagerTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/util/WatchManagerTest.java
@@ -18,6 +18,12 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.io.File;
import java.io.FileOutputStream;
@@ -30,6 +36,9 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.core.config.ConfigurationScheduler;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
@@ -40,106 +49,110 @@
*/
@DisabledOnOs(OS.WINDOWS)
@EnabledIfSystemProperty(named = "WatchManagerTest.forceRun", matches = "true")
-public class WatchManagerTest {
+class WatchManagerTest {
private final String testFile = "target/testWatchFile";
private final String originalFile = "target/test-classes/log4j-test1.xml";
private final String newFile = "target/test-classes/log4j-test1.yaml";
- @Test
- public void testWatchManager() throws Exception {
- final ConfigurationScheduler scheduler = new ConfigurationScheduler();
+ private ConfigurationScheduler scheduler;
+ private WatchManager watchManager;
+
+ @BeforeEach
+ void setUp() {
+ scheduler = new ConfigurationScheduler();
scheduler.incrementScheduledItems();
- final WatchManager watchManager = new WatchManager(scheduler);
+ watchManager = new WatchManager(scheduler);
watchManager.setIntervalSeconds(1);
scheduler.start();
watchManager.start();
- try {
- final File sourceFile = new File(originalFile);
- Path source = Paths.get(sourceFile.toURI());
- try (final FileOutputStream targetStream = new FileOutputStream(testFile)) {
- Files.copy(source, targetStream);
- }
- final File updateFile = new File(newFile);
- final File targetFile = new File(testFile);
- final BlockingQueue queue = new LinkedBlockingQueue<>();
- watchManager.watchFile(targetFile, new TestWatcher(queue));
- Thread.sleep(1000);
- source = Paths.get(updateFile.toURI());
- Files.copy(source, Paths.get(targetFile.toURI()), StandardCopyOption.REPLACE_EXISTING);
- Thread.sleep(1000);
- final File f = queue.poll(1, TimeUnit.SECONDS);
- assertNotNull(f, "File change not detected");
- } finally {
- watchManager.stop();
- scheduler.stop();
- }
+ }
+
+ @AfterEach
+ void tearDown() {
+ watchManager.stop();
+ scheduler.stop();
+ watchManager = null;
+ scheduler = null;
}
@Test
- public void testWatchManagerReset() throws Exception {
- final ConfigurationScheduler scheduler = new ConfigurationScheduler();
- scheduler.incrementScheduledItems();
- final WatchManager watchManager = new WatchManager(scheduler);
- watchManager.setIntervalSeconds(1);
- scheduler.start();
- watchManager.start();
- try {
- final File sourceFile = new File(originalFile);
- Path source = Paths.get(sourceFile.toURI());
- try (final FileOutputStream targetStream = new FileOutputStream(testFile)) {
- Files.copy(source, targetStream);
- }
- final File updateFile = new File(newFile);
- final File targetFile = new File(testFile);
- final BlockingQueue queue = new LinkedBlockingQueue<>();
- watchManager.watchFile(targetFile, new TestWatcher(queue));
- watchManager.stop();
- Thread.sleep(1000);
- source = Paths.get(updateFile.toURI());
- Files.copy(source, Paths.get(targetFile.toURI()), StandardCopyOption.REPLACE_EXISTING);
- watchManager.reset();
- watchManager.start();
- Thread.sleep(1000);
- final File f = queue.poll(1, TimeUnit.SECONDS);
- assertNull(f, "File change detected");
- } finally {
- watchManager.stop();
- scheduler.stop();
+ void testWatchManager() throws Exception {
+ final File sourceFile = new File(originalFile);
+ Path source = Paths.get(sourceFile.toURI());
+ try (final FileOutputStream targetStream = new FileOutputStream(testFile)) {
+ Files.copy(source, targetStream);
}
+ final File updateFile = new File(newFile);
+ final File targetFile = new File(testFile);
+ final BlockingQueue queue = new LinkedBlockingQueue<>();
+ watchManager.watchFile(targetFile, new TestWatcher(queue));
+ Thread.sleep(1000);
+ source = Paths.get(updateFile.toURI());
+ Files.copy(source, Paths.get(targetFile.toURI()), StandardCopyOption.REPLACE_EXISTING);
+ Thread.sleep(1000);
+ final File f = queue.poll(1, TimeUnit.SECONDS);
+ assertNotNull(f, "File change not detected");
}
@Test
- public void testWatchManagerResetFile() throws Exception {
- final ConfigurationScheduler scheduler = new ConfigurationScheduler();
- scheduler.incrementScheduledItems();
- final WatchManager watchManager = new WatchManager(scheduler);
- watchManager.setIntervalSeconds(1);
- scheduler.start();
+ void testWatchManagerReset() throws Exception {
+ final File sourceFile = new File(originalFile);
+ Path source = Paths.get(sourceFile.toURI());
+ try (final FileOutputStream targetStream = new FileOutputStream(testFile)) {
+ Files.copy(source, targetStream);
+ }
+ final File updateFile = new File(newFile);
+ final File targetFile = new File(testFile);
+ final BlockingQueue queue = new LinkedBlockingQueue<>();
+ watchManager.watchFile(targetFile, new TestWatcher(queue));
+ watchManager.stop();
+ Thread.sleep(1000);
+ source = Paths.get(updateFile.toURI());
+ Files.copy(source, Paths.get(targetFile.toURI()), StandardCopyOption.REPLACE_EXISTING);
+ watchManager.reset();
watchManager.start();
- try {
- final File sourceFile = new File(originalFile);
- Path source = Paths.get(sourceFile.toURI());
- try (final FileOutputStream targetStream = new FileOutputStream(testFile)) {
- Files.copy(source, targetStream);
- }
- final File updateFile = new File(newFile);
- final File targetFile = new File(testFile);
- final BlockingQueue queue = new LinkedBlockingQueue<>();
- watchManager.watchFile(targetFile, new TestWatcher(queue));
- watchManager.stop();
- Thread.sleep(1000);
- source = Paths.get(updateFile.toURI());
- Files.copy(source, Paths.get(targetFile.toURI()), StandardCopyOption.REPLACE_EXISTING);
- watchManager.reset(targetFile);
- watchManager.start();
- Thread.sleep(1000);
- final File f = queue.poll(1, TimeUnit.SECONDS);
- assertNull(f, "File change detected");
- } finally {
- watchManager.stop();
- scheduler.stop();
+ Thread.sleep(1000);
+ final File f = queue.poll(1, TimeUnit.SECONDS);
+ assertNull(f, "File change detected");
+ }
+
+ @Test
+ void testWatchManagerResetFile() throws Exception {
+ final File sourceFile = new File(originalFile);
+ Path source = Paths.get(sourceFile.toURI());
+ try (final FileOutputStream targetStream = new FileOutputStream(testFile)) {
+ Files.copy(source, targetStream);
}
+ final File updateFile = new File(newFile);
+ final File targetFile = new File(testFile);
+ final BlockingQueue queue = new LinkedBlockingQueue<>();
+ watchManager.watchFile(targetFile, new TestWatcher(queue));
+ watchManager.stop();
+ Thread.sleep(1000);
+ source = Paths.get(updateFile.toURI());
+ Files.copy(source, Paths.get(targetFile.toURI()), StandardCopyOption.REPLACE_EXISTING);
+ watchManager.reset(targetFile);
+ watchManager.start();
+ Thread.sleep(1000);
+ final File f = queue.poll(1, TimeUnit.SECONDS);
+ assertNull(f, "File change detected");
+ }
+
+ /**
+ * Verify the
+ */
+ @Test
+ void testWatchManagerCallsWatcher() {
+ Watcher watcher = mock(Watcher.class);
+ when(watcher.isModified()).thenReturn(false);
+ watchManager.watch(new Source(ConfigurationSource.NULL_SOURCE), watcher);
+ verify(watcher, timeout(2000)).isModified();
+ verify(watcher, never()).modified();
+ when(watcher.isModified()).thenReturn(true);
+ clearInvocations(watcher);
+ verify(watcher, timeout(2000)).isModified();
+ verify(watcher).modified();
}
private static class TestWatcher implements FileWatcher {
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml b/log4j-core-test/src/test/resources/config/ConfigurationSourceTest.xml
similarity index 70%
rename from log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml
rename to log4j-core-test/src/test/resources/config/ConfigurationSourceTest.xml
index 4b740bc947e..54c7f846f3f 100644
--- a/log4j-mongodb/src/test/resources/log4j2-mongodb-map-message.xml
+++ b/log4j-core-test/src/test/resources/config/ConfigurationSourceTest.xml
@@ -15,16 +15,18 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
-
-
-
+
+
+
-
-
+
+
diff --git a/log4j-core-test/src/test/resources/emptyConfig.json b/log4j-core-test/src/test/resources/emptyConfig.json
deleted file mode 100644
index 37086f2b1f6..00000000000
--- a/log4j-core-test/src/test/resources/emptyConfig.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "configs": {
- }
-}
\ No newline at end of file
diff --git a/log4j-core-test/src/test/resources/log4j2-mutableFilter.xml b/log4j-core-test/src/test/resources/filter/MutableThreadContextMapFilterTest.xml
similarity index 61%
rename from log4j-core-test/src/test/resources/log4j2-mutableFilter.xml
rename to log4j-core-test/src/test/resources/filter/MutableThreadContextMapFilterTest.xml
index 2f4e391d139..34eb059c4e0 100644
--- a/log4j-core-test/src/test/resources/log4j2-mutableFilter.xml
+++ b/log4j-core-test/src/test/resources/filter/MutableThreadContextMapFilterTest.xml
@@ -15,21 +15,21 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-
+
+
-
-
-
-
-
+
-
-
-
-
-
+
+
diff --git a/log4j-core-test/src/test/resources/filterConfig.json b/log4j-core-test/src/test/resources/filterConfig.json
deleted file mode 100644
index 91c8143ec2b..00000000000
--- a/log4j-core-test/src/test/resources/filterConfig.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "configs": {
- "loginId": ["rgoers", "adam"],
- "corpAcctNumber": ["30510263"]
- }
-}
\ No newline at end of file
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index ee8e7c6a3cd..88f66ac364d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -93,7 +93,7 @@ public class LoggerContext extends AbstractLifeCycle
private volatile Configuration configuration = new DefaultConfiguration();
private static final String EXTERNAL_CONTEXT_KEY = "__EXTERNAL_CONTEXT_KEY__";
- private ConcurrentMap externalMap = new ConcurrentHashMap<>();
+ private final ConcurrentMap externalMap = new ConcurrentHashMap<>();
private String contextName;
private volatile URI configLocation;
private Cancellable shutdownCallback;
@@ -128,9 +128,7 @@ public LoggerContext(final String name, final Object externalContext) {
*/
public LoggerContext(final String name, final Object externalContext, final URI configLocn) {
this.contextName = name;
- if (externalContext == null) {
- externalMap.remove(EXTERNAL_CONTEXT_KEY);
- } else {
+ if (externalContext != null) {
externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
}
this.configLocation = configLocn;
@@ -149,9 +147,7 @@ public LoggerContext(final String name, final Object externalContext, final URI
justification = "The configLocn comes from a secure source (Log4j properties)")
public LoggerContext(final String name, final Object externalContext, final String configLocn) {
this.contextName = name;
- if (externalContext == null) {
- externalMap.remove(EXTERNAL_CONTEXT_KEY);
- } else {
+ if (externalContext != null) {
externalMap.put(EXTERNAL_CONTEXT_KEY, externalContext);
}
if (configLocn != null) {
@@ -172,7 +168,7 @@ public void addShutdownListener(final LoggerContextShutdownAware listener) {
if (listeners == null) {
synchronized (this) {
if (listeners == null) {
- listeners = new CopyOnWriteArrayList();
+ listeners = new CopyOnWriteArrayList<>();
}
}
}
@@ -283,7 +279,7 @@ public void start() {
* @param config The new Configuration.
*/
public void start(final Configuration config) {
- LOGGER.debug("Starting LoggerContext[name={}, {}] with configuration {}...", getName(), this, config);
+ LOGGER.info("Starting {}[name={}] with configuration {}...", getClass().getSimpleName(), getName(), config);
if (configLock.tryLock()) {
try {
if (this.isInitialized() || this.isStopped()) {
@@ -297,7 +293,7 @@ public void start(final Configuration config) {
}
}
setConfiguration(config);
- LOGGER.debug("LoggerContext[name={}, {}] started OK with configuration {}.", getName(), this, config);
+ LOGGER.info("{}[name={}] started with configuration {}.", getClass().getSimpleName(), getName(), config);
}
private void setUpShutdownHook() {
@@ -312,7 +308,6 @@ private void setUpShutdownHook() {
this.shutdownCallback = ((ShutdownCallbackRegistry) factory).addShutdownCallback(new Runnable() {
@Override
public void run() {
- @SuppressWarnings("resource")
final LoggerContext context = LoggerContext.this;
LOGGER.debug(
SHUTDOWN_HOOK_MARKER,
@@ -714,7 +709,7 @@ public void setConfigLocation(final URI configLocation) {
*/
private void reconfigure(final URI configURI) {
final Object externalContext = externalMap.get(EXTERNAL_CONTEXT_KEY);
- final ClassLoader cl = ClassLoader.class.isInstance(externalContext) ? (ClassLoader) externalContext : null;
+ final ClassLoader cl = externalContext instanceof ClassLoader ? (ClassLoader) externalContext : null;
LOGGER.debug(
"Reconfiguration started for context[name={}] at URI {} ({}) with optional ClassLoader: {}",
contextName,
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index 3c5069f7661..4b160f98ef9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -281,9 +281,9 @@ protected void initializeWatchers(
watchManager.setIntervalSeconds(monitorIntervalSeconds);
if (configSource.getFile() != null) {
final Source cfgSource = new Source(configSource);
- final long lastModifeid = configSource.getFile().lastModified();
+ final long lastModified = configSource.getFile().lastModified();
final ConfigurationFileWatcher watcher =
- new ConfigurationFileWatcher(this, reconfigurable, listeners, lastModifeid);
+ new ConfigurationFileWatcher(this, reconfigurable, listeners, lastModified);
watchManager.watch(cfgSource, watcher);
} else if (configSource.getURL() != null) {
monitorSource(reconfigurable, configSource);
@@ -318,9 +318,13 @@ public void start() {
if (getState() == State.INITIALIZING) {
initialize();
}
- LOGGER.debug("Starting configuration {}", this);
+ LOGGER.info("Starting configuration {}...", this);
this.setStarting();
if (watchManager.getIntervalSeconds() >= 0) {
+ LOGGER.info(
+ "Start watching for changes to {} every {} seconds",
+ getConfigurationSource(),
+ watchManager.getIntervalSeconds());
watchManager.start();
}
if (hasAsyncLoggers()) {
@@ -338,7 +342,7 @@ public void start() {
root.start(); // LOG4J2-336
}
super.start();
- LOGGER.debug("Started configuration {} OK.", this);
+ LOGGER.info("Configuration {} started.", this);
}
private boolean hasAsyncLoggers() {
@@ -358,9 +362,9 @@ private boolean hasAsyncLoggers() {
*/
@Override
public boolean stop(final long timeout, final TimeUnit timeUnit) {
+ LOGGER.info("Stopping configuration {}...", this);
this.setStopping();
super.stop(timeout, timeUnit, false);
- LOGGER.trace("Stopping {}...", this);
// Stop the components that are closest to the application first:
// 1. Notify all LoggerConfigs' ReliabilityStrategy that the configuration will be stopped.
@@ -456,7 +460,7 @@ public boolean stop(final long timeout, final TimeUnit timeUnit) {
advertiser.unadvertise(advertisement);
}
setStopped();
- LOGGER.debug("Stopped {} OK", this);
+ LOGGER.info("Configuration {} stopped.", this);
return true;
}
@@ -484,6 +488,7 @@ public void setup() {
// default does nothing, subclasses do work.
}
+ @SuppressWarnings("deprecation")
protected Level getDefaultStatus() {
final PropertiesUtil properties = PropertiesUtil.getProperties();
String statusLevel = properties.getStringProperty(StatusLogger.DEFAULT_STATUS_LISTENER_LEVEL);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
index fbcf278a07b..0368c5d705c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
@@ -33,10 +33,12 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
+import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.net.UrlConnectionFactory;
import org.apache.logging.log4j.core.util.FileUtils;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.Source;
+import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.Constants;
import org.apache.logging.log4j.util.LoaderUtil;
@@ -45,6 +47,8 @@
*/
public class ConfigurationSource {
+ private static final Logger LOGGER = StatusLogger.getLogger();
+
/**
* ConfigurationSource to use with Configurations that do not require a "real" configuration source.
*/
@@ -58,7 +62,7 @@ public class ConfigurationSource {
private final InputStream stream;
private volatile byte[] data;
- private volatile Source source;
+ private final Source source;
private final long lastModified;
// Set when the configuration has been updated so reset can use it for the next lastModified timestamp.
private volatile long modifiedMillis;
@@ -80,7 +84,7 @@ public ConfigurationSource(final InputStream stream, final File file) {
} catch (Exception ex) {
// There is a problem with the file. It will be handled somewhere else.
}
- this.lastModified = modified;
+ this.modifiedMillis = this.lastModified = modified;
}
/**
@@ -100,7 +104,7 @@ public ConfigurationSource(final InputStream stream, final Path path) {
} catch (Exception ex) {
// There is a problem with the file. It will be handled somewhere else.
}
- this.lastModified = modified;
+ this.modifiedMillis = this.lastModified = modified;
}
/**
@@ -111,10 +115,7 @@ public ConfigurationSource(final InputStream stream, final Path path) {
* @param url the URL where the input stream originated
*/
public ConfigurationSource(final InputStream stream, final URL url) {
- this.stream = Objects.requireNonNull(stream, "stream is null");
- this.data = null;
- this.lastModified = 0;
- this.source = new Source(url);
+ this(stream, url, 0);
}
/**
@@ -128,7 +129,7 @@ public ConfigurationSource(final InputStream stream, final URL url) {
public ConfigurationSource(final InputStream stream, final URL url, final long lastModified) {
this.stream = Objects.requireNonNull(stream, "stream is null");
this.data = null;
- this.lastModified = lastModified;
+ this.modifiedMillis = this.lastModified = lastModified;
this.source = new Source(url);
}
@@ -154,19 +155,15 @@ public ConfigurationSource(final Source source, final byte[] data, final long la
Objects.requireNonNull(source, "source is null");
this.data = Objects.requireNonNull(data, "data is null");
this.stream = new ByteArrayInputStream(data);
- this.lastModified = lastModified;
+ this.modifiedMillis = this.lastModified = lastModified;
this.source = source;
}
private ConfigurationSource(final byte[] data, final URL url, final long lastModified) {
this.data = Objects.requireNonNull(data, "data is null");
this.stream = new ByteArrayInputStream(data);
- this.lastModified = lastModified;
- if (url == null) {
- this.data = data;
- } else {
- this.source = new Source(url);
- }
+ this.modifiedMillis = this.lastModified = lastModified;
+ this.source = url == null ? null : new Source(url);
}
/**
@@ -199,16 +196,8 @@ public File getFile() {
return source == null ? null : source.getFile();
}
- private boolean isFile() {
- return source == null ? false : source.getFile() != null;
- }
-
- private boolean isURL() {
- return source == null ? false : source.getURI() != null;
- }
-
private boolean isLocation() {
- return source == null ? false : source.getLocation() != null;
+ return source != null && source.getLocation() != null;
}
/**
@@ -222,11 +211,11 @@ public URL getURL() {
}
/**
- * @deprecated Not used internally, no replacement. TODO remove and make source final.
+ * @deprecated Not used internally, no replacement.
*/
@Deprecated
- public void setSource(final Source source) {
- this.source = source;
+ public void setSource(final Source ignored) {
+ LOGGER.warn("Ignoring call of deprecated method `ConfigurationSource#setSource()`.");
}
public void setData(final byte[] data) {
@@ -280,16 +269,23 @@ public InputStream getInputStream() {
*/
public ConfigurationSource resetInputStream() throws IOException {
if (source != null && data != null) {
- return new ConfigurationSource(source, data, this.lastModified);
- } else if (isFile()) {
- return new ConfigurationSource(new FileInputStream(getFile()), getFile());
- } else if (isURL() && data != null) {
+ return new ConfigurationSource(source, data, modifiedMillis);
+ }
+ File file = getFile();
+ if (file != null) {
+ return new ConfigurationSource(Files.newInputStream(file.toPath()), getFile());
+ }
+ URL url = getURL();
+ if (url != null && data != null) {
// Creates a ConfigurationSource without accessing the URL since the data was provided.
- return new ConfigurationSource(data, getURL(), modifiedMillis == 0 ? lastModified : modifiedMillis);
- } else if (isURL()) {
- return fromUri(getURI());
- } else if (data != null) {
- return new ConfigurationSource(data, null, lastModified);
+ return new ConfigurationSource(data, url, modifiedMillis);
+ }
+ URI uri = getURI();
+ if (uri != null) {
+ return fromUri(uri);
+ }
+ if (data != null) {
+ return new ConfigurationSource(data, null, modifiedMillis);
}
return null;
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java
index 08e840d93bf..b6d7f57d663 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/HttpWatcher.java
@@ -16,16 +16,19 @@
*/
package org.apache.logging.log4j.core.config;
+import static java.util.Objects.requireNonNull;
+import static org.apache.logging.log4j.core.util.internal.HttpInputStreamUtil.readStream;
+import static org.apache.logging.log4j.util.Strings.toRootUpperCase;
+
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
+import java.time.Instant;
import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAliases;
-import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
-import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
import org.apache.logging.log4j.core.util.AbstractWatcher;
import org.apache.logging.log4j.core.util.AuthorizationProvider;
import org.apache.logging.log4j.core.util.Source;
@@ -44,7 +47,6 @@ public class HttpWatcher extends AbstractWatcher {
private final Logger LOGGER = StatusLogger.getLogger();
- private final SslConfiguration sslConfiguration;
private AuthorizationProvider authorizationProvider;
private URL url;
private volatile long lastModifiedMillis;
@@ -57,7 +59,6 @@ public HttpWatcher(
final List configurationListeners,
final long lastModifiedMillis) {
super(configuration, reconfigurable, configurationListeners);
- sslConfiguration = SslConfigurationFactory.getSslConfiguration();
this.lastModifiedMillis = lastModifiedMillis;
}
@@ -103,34 +104,50 @@ private boolean refreshConfiguration() {
try {
final LastModifiedSource source = new LastModifiedSource(url.toURI(), lastModifiedMillis);
final HttpInputStreamUtil.Result result = HttpInputStreamUtil.getInputStream(source, authorizationProvider);
+ // Update lastModifiedMillis
+ // https://github.com/apache/logging-log4j2/issues/2937
+ lastModifiedMillis = source.getLastModified();
+ // The result of the HTTP/HTTPS request is already logged at `DEBUG` by `HttpInputStreamUtil`
+ // We only log the important events at `INFO` or more.
switch (result.getStatus()) {
case NOT_MODIFIED: {
- LOGGER.debug("Configuration Not Modified");
return false;
}
case SUCCESS: {
final ConfigurationSource configSource = getConfiguration().getConfigurationSource();
try {
- configSource.setData(HttpInputStreamUtil.readStream(result.getInputStream()));
+ // In this case `result.getInputStream()` is not null.
+ configSource.setData(readStream(requireNonNull(result.getInputStream())));
configSource.setModifiedMillis(source.getLastModified());
- LOGGER.debug("Content was modified for {}", url.toString());
+ LOGGER.info(
+ "{} resource at {} was modified on {}",
+ () -> toRootUpperCase(url.getProtocol()),
+ () -> url.toExternalForm(),
+ () -> Instant.ofEpochMilli(source.getLastModified()));
return true;
} catch (final IOException e) {
- LOGGER.error("Error accessing configuration at {}: {}", url, e.getMessage());
+ // Dead code since result.getInputStream() is a ByteArrayInputStream
+ LOGGER.error("Error accessing configuration at {}", url.toExternalForm(), e);
return false;
}
}
case NOT_FOUND: {
- LOGGER.info("Unable to locate configuration at {}", url.toString());
+ LOGGER.warn(
+ "{} resource at {} was not found",
+ () -> toRootUpperCase(url.getProtocol()),
+ () -> url.toExternalForm());
return false;
}
default: {
- LOGGER.warn("Unexpected error accessing configuration at {}", url.toString());
+ LOGGER.warn(
+ "Unexpected error retrieving {} resource at {}",
+ () -> toRootUpperCase(url.getProtocol()),
+ () -> url.toExternalForm());
return false;
}
}
} catch (final URISyntaxException ex) {
- LOGGER.error("Bad configuration URL: {}, {}", url.toString(), ex.getMessage());
+ LOGGER.error("Bad configuration file URL {}", url.toExternalForm(), ex);
return false;
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
index 48502de22e5..31e42d843f4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
@@ -18,9 +18,9 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.ByteArrayInputStream;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -73,7 +73,6 @@ public class XmlConfiguration extends AbstractConfiguration implements Reconfigu
justification = "The `newDocumentBuilder` method disables DTD processing.")
public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSource configSource) {
super(loggerContext, configSource);
- final File configFile = configSource.getFile();
byte[] buffer = null;
try {
@@ -175,7 +174,7 @@ public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSo
*
* @param xIncludeAware enabled XInclude
* @return a new DocumentBuilder
- * @throws ParserConfigurationException
+ * @throws ParserConfigurationException if a DocumentBuilder cannot be created, which satisfies the configuration requested.
*/
static DocumentBuilder newDocumentBuilder(final boolean xIncludeAware) throws ParserConfigurationException {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -241,7 +240,7 @@ public void setup() {
return;
}
constructHierarchy(rootNode, rootElement);
- if (status.size() > 0) {
+ if (!status.isEmpty()) {
for (final Status s : status) {
LOGGER.error("Error processing element {} ({}): {}", s.name, s.element, s.errorType);
}
@@ -295,7 +294,7 @@ private void constructHierarchy(final Node node, final Element element) {
}
final String text = buffer.toString().trim();
- if (text.length() > 0 || (!node.hasChildren() && !node.isRoot())) {
+ if (!text.isEmpty() || (!node.hasChildren() && !node.isRoot())) {
node.setValue(text);
}
}
@@ -337,7 +336,8 @@ private Map processAttributes(final Node node, final Element ele
@Override
public String toString() {
- return getClass().getSimpleName() + "[location=" + getConfigurationSource() + "]";
+ return getClass().getSimpleName() + "[location=" + getConfigurationSource() + ", lastModified="
+ + Instant.ofEpochMilli(getConfigurationSource().getLastModified()) + "]";
}
/**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java
index 3ceb4599b76..c7c9137715c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MutableThreadContextMapFilter.java
@@ -20,9 +20,9 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
-import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -65,6 +65,9 @@
@PerformanceSensitive("allocation")
public class MutableThreadContextMapFilter extends AbstractFilter {
+ private static final String HTTP = "http";
+ private static final String HTTPS = "https";
+
private static final ObjectMapper MAPPER =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
private static final KeyValuePair[] EMPTY_ARRAY = {};
@@ -364,23 +367,29 @@ private class FileMonitor implements Runnable {
@Override
public void run() {
final ConfigResult result = getConfig(source, authorizationProvider);
- if (result.status == Status.SUCCESS) {
- filter = ThreadContextMapFilter.createFilter(result.pairs, "or", getOnMatch(), getOnMismatch());
- LOGGER.info("Filter configuration was updated: {}", filter.toString());
- for (FilterConfigUpdateListener listener : listeners) {
- listener.onEvent();
- }
- } else if (result.status == Status.NOT_FOUND) {
- if (!(filter instanceof NoOpFilter)) {
- LOGGER.info("Filter configuration was removed");
+ switch (result.status) {
+ case SUCCESS:
+ filter = ThreadContextMapFilter.createFilter(result.pairs, "or", getOnMatch(), getOnMismatch());
+ LOGGER.info("MutableThreadContextMapFilter configuration was updated: {}", filter.toString());
+ break;
+ case NOT_FOUND:
+ if (!(filter instanceof NoOpFilter)) {
+ LOGGER.info("MutableThreadContextMapFilter configuration was removed");
+ filter = new NoOpFilter();
+ }
+ break;
+ case EMPTY:
+ LOGGER.debug("MutableThreadContextMapFilter configuration is empty");
filter = new NoOpFilter();
+ break;
+ }
+ switch (result.status) {
+ case SUCCESS:
+ case NOT_FOUND:
+ case EMPTY:
for (FilterConfigUpdateListener listener : listeners) {
listener.onEvent();
}
- }
- } else if (result.status == Status.EMPTY) {
- LOGGER.debug("Filter configuration is empty");
- filter = new NoOpFilter();
}
}
}
@@ -389,7 +398,7 @@ public void run() {
value = "PATH_TRAVERSAL_IN",
justification = "The location of the file comes from a configuration value.")
private static LastModifiedSource getSource(final String configLocation) {
- LastModifiedSource source = null;
+ LastModifiedSource source;
try {
final URI uri = new URI(configLocation);
if (uri.getScheme() != null) {
@@ -408,14 +417,15 @@ private static ConfigResult getConfig(
final LastModifiedSource source, final AuthorizationProvider authorizationProvider) {
final File inputFile = source.getFile();
InputStream inputStream = null;
- HttpInputStreamUtil.Result result = null;
+ HttpInputStreamUtil.Result result;
final long lastModified = source.getLastModified();
+ URI uri = source.getURI();
if (inputFile != null && inputFile.exists()) {
try {
final long modified = inputFile.lastModified();
if (modified > lastModified) {
source.setLastModified(modified);
- inputStream = new FileInputStream(inputFile);
+ inputStream = Files.newInputStream(inputFile.toPath());
result = new HttpInputStreamUtil.Result(Status.SUCCESS);
} else {
result = new HttpInputStreamUtil.Result(Status.NOT_MODIFIED);
@@ -423,7 +433,7 @@ private static ConfigResult getConfig(
} catch (Exception ex) {
result = new HttpInputStreamUtil.Result(Status.ERROR);
}
- } else if (source.getURI() != null) {
+ } else if (uri != null && (HTTP.equalsIgnoreCase(uri.getScheme()) || HTTPS.equalsIgnoreCase(uri.getScheme()))) {
try {
result = HttpInputStreamUtil.getInputStream(source, authorizationProvider);
inputStream = result.getInputStream();
@@ -440,7 +450,7 @@ private static ConfigResult getConfig(
final KeyValuePairConfig keyValuePairConfig = MAPPER.readValue(inputStream, KeyValuePairConfig.class);
if (keyValuePairConfig != null) {
final Map configs = keyValuePairConfig.getConfigs();
- if (configs != null && configs.size() > 0) {
+ if (configs != null && !configs.isEmpty()) {
final List pairs = new ArrayList<>();
for (Map.Entry entry : configs.entrySet()) {
final String key = entry.getKey();
@@ -452,7 +462,7 @@ private static ConfigResult getConfig(
}
}
}
- if (pairs.size() > 0) {
+ if (!pairs.isEmpty()) {
configResult.pairs = pairs.toArray(EMPTY_ARRAY);
configResult.status = Status.SUCCESS;
} else {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
index 15e9009b75c..7165bfe6f17 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
@@ -20,6 +20,7 @@
import aQute.bnd.annotation.Resolution;
import aQute.bnd.annotation.spi.ServiceConsumer;
import java.io.File;
+import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -49,8 +50,9 @@
@ServiceConsumer(value = WatchEventService.class, resolution = Resolution.OPTIONAL, cardinality = Cardinality.MULTIPLE)
public class WatchManager extends AbstractLifeCycle {
- private final class ConfigurationMonitor {
+ private static final class ConfigurationMonitor {
private final Watcher watcher;
+ // Only used for logging
private volatile long lastModifiedMillis;
public ConfigurationMonitor(final long lastModifiedMillis, final Watcher watcher) {
@@ -76,7 +78,6 @@ private static class LocalUUID {
private static final long LOW_MASK = 0xffffffffL;
private static final long MID_MASK = 0xffff00000000L;
private static final long HIGH_MASK = 0xfff000000000000L;
- private static final int NODE_SIZE = 8;
private static final int SHIFT_2 = 16;
private static final int SHIFT_4 = 32;
private static final int SHIFT_6 = 48;
@@ -84,8 +85,6 @@ private static class LocalUUID {
private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L;
private static final AtomicInteger COUNT = new AtomicInteger(0);
private static final long TYPE1 = 0x1000L;
- private static final byte VARIANT = (byte) 0x80;
- private static final int SEQUENCE_MASK = 0x3FFF;
public static UUID get() {
final long time =
@@ -112,15 +111,11 @@ public void run() {
final ConfigurationMonitor monitor = entry.getValue();
if (monitor.getWatcher().isModified()) {
final long lastModified = monitor.getWatcher().getLastModified();
- if (logger.isInfoEnabled()) {
- logger.info(
- "Source '{}' was modified on {} ({}), previous modification was on {} ({})",
- source,
- millisToString(lastModified),
- lastModified,
- millisToString(monitor.lastModifiedMillis),
- monitor.lastModifiedMillis);
- }
+ logger.info(
+ "Configuration source at {} was modified on {}, previous modification was on {}",
+ () -> source,
+ () -> Instant.ofEpochMilli(lastModified),
+ () -> Instant.ofEpochMilli(monitor.lastModifiedMillis));
monitor.lastModifiedMillis = lastModified;
monitor.getWatcher().modified();
}
@@ -200,7 +195,7 @@ public Map getWatchers() {
}
public boolean hasEventListeners() {
- return eventServiceList.size() > 0;
+ return !eventServiceList.isEmpty();
}
private String millisToString(final long millis) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java
index c146958f9fe..2c25ed2d255 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/internal/HttpInputStreamUtil.java
@@ -16,17 +16,24 @@
*/
package org.apache.logging.log4j.core.util.internal;
+import static org.apache.logging.log4j.util.Strings.toRootUpperCase;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
+import java.time.Instant;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.ConfigurationException;
import org.apache.logging.log4j.core.net.UrlConnectionFactory;
import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
import org.apache.logging.log4j.core.util.AuthorizationProvider;
+import org.apache.logging.log4j.core.util.Source;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Supplier;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
/**
* Utility method for reading data from an HTTP InputStream.
@@ -36,10 +43,21 @@ public final class HttpInputStreamUtil {
private static final Logger LOGGER = StatusLogger.getLogger();
private static final int NOT_MODIFIED = 304;
private static final int NOT_AUTHORIZED = 401;
+ private static final int FORBIDDEN = 403;
private static final int NOT_FOUND = 404;
private static final int OK = 200;
private static final int BUF_SIZE = 1024;
+ /**
+ * Retrieves an HTTP resource if it has been modified.
+ *
+ * Side effects: if the request is successful, the last modified time of the {@code source}
+ * parameter is modified.
+ *
+ * @param source The location of the HTTP resource
+ * @param authorizationProvider The authentication data for the HTTP request
+ * @return A {@link Result} object containing the status code and body of the response
+ */
public static Result getInputStream(
final LastModifiedSource source, final AuthorizationProvider authorizationProvider) {
final Result result = new Result();
@@ -55,12 +73,16 @@ public static Result getInputStream(
final int code = connection.getResponseCode();
switch (code) {
case NOT_MODIFIED: {
- LOGGER.debug("Configuration not modified");
+ LOGGER.debug(
+ "{} resource {}: not modified since {}",
+ formatProtocol(source),
+ () -> source,
+ () -> Instant.ofEpochMilli(lastModified));
result.status = Status.NOT_MODIFIED;
return result;
}
case NOT_FOUND: {
- LOGGER.debug("Unable to access {}: Not Found", source.toString());
+ LOGGER.debug("{} resource {}: not found", formatProtocol(source), () -> source);
result.status = Status.NOT_FOUND;
return result;
}
@@ -68,45 +90,65 @@ public static Result getInputStream(
try (final InputStream is = connection.getInputStream()) {
source.setLastModified(connection.getLastModified());
LOGGER.debug(
- "Content was modified for {}. previous lastModified: {}, new lastModified: {}",
- source.toString(),
- lastModified,
- connection.getLastModified());
+ "{} resource {}: last modified on {}",
+ formatProtocol(source),
+ () -> source,
+ () -> Instant.ofEpochMilli(connection.getLastModified()));
result.status = Status.SUCCESS;
- result.inputStream = new ByteArrayInputStream(readStream(is));
+ result.bytes = readStream(is);
return result;
} catch (final IOException e) {
try (final InputStream es = connection.getErrorStream()) {
- LOGGER.info(
- "Error accessing configuration at {}: {}", source.toString(), readStream(es));
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug(
+ "Error accessing {} resource at {}: {}",
+ formatProtocol(source).get(),
+ source,
+ readStream(es),
+ e);
+ }
} catch (final IOException ioe) {
- LOGGER.error(
- "Error accessing configuration at {}: {}", source.toString(), e.getMessage());
+ LOGGER.debug(
+ "Error accessing {} resource at {}",
+ formatProtocol(source),
+ () -> source,
+ () -> e);
}
- throw new ConfigurationException("Unable to access " + source.toString(), e);
+ throw new ConfigurationException("Unable to access " + source, e);
}
}
case NOT_AUTHORIZED: {
- throw new ConfigurationException("Authorization failed");
+ throw new ConfigurationException("Authentication required for " + source);
+ }
+ case FORBIDDEN: {
+ throw new ConfigurationException("Access denied to " + source);
}
default: {
if (code < 0) {
- LOGGER.info("Invalid response code returned");
+ LOGGER.debug("{} resource {}: invalid response code", formatProtocol(source), source);
} else {
- LOGGER.info("Unexpected response code returned {}", code);
+ LOGGER.debug(
+ "{} resource {}: unexpected response code {}",
+ formatProtocol(source),
+ source,
+ code);
}
- throw new ConfigurationException("Unable to access " + source.toString());
+ throw new ConfigurationException("Unable to access " + source);
}
}
} finally {
connection.disconnect();
}
} catch (IOException e) {
- LOGGER.warn("Error accessing {}: {}", source.toString(), e.getMessage());
- throw new ConfigurationException("Unable to access " + source.toString(), e);
+ LOGGER.debug("Error accessing {} resource at {}", formatProtocol(source), source, e);
+ throw new ConfigurationException("Unable to access " + source, e);
}
}
+ private static Supplier formatProtocol(Source source) {
+ return () -> toRootUpperCase(source.getURI().getScheme());
+ }
+
public static byte[] readStream(final InputStream is) throws IOException {
final ByteArrayOutputStream result = new ByteArrayOutputStream();
final byte[] buffer = new byte[BUF_SIZE];
@@ -117,19 +159,29 @@ public static byte[] readStream(final InputStream is) throws IOException {
return result.toByteArray();
}
+ @NullMarked
public static class Result {
- private InputStream inputStream;
+ private byte @Nullable [] bytes = null;
private Status status;
- public Result() {}
+ public Result() {
+ this(Status.ERROR);
+ }
public Result(final Status status) {
this.status = status;
}
- public InputStream getInputStream() {
- return inputStream;
+ /**
+ * Returns the data if the status is {@link Status#SUCCESS}.
+ *
+ * In any other case the result is {@code null}.
+ *
+ * @return The contents of the HTTP response or null if empty.
+ */
+ public @Nullable InputStream getInputStream() {
+ return bytes != null ? new ByteArrayInputStream(bytes) : null;
}
public Status getStatus() {
diff --git a/log4j-layout-template-json-test/pom.xml b/log4j-layout-template-json-test/pom.xml
index 7031fd4d80b..51bc8a9660b 100644
--- a/log4j-layout-template-json-test/pom.xml
+++ b/log4j-layout-template-json-test/pom.xml
@@ -43,6 +43,14 @@
org.apache.logging.log4j.layout.template.json.test
org.apache.logging.log4j.core
+
+ 8.15.1
+
@@ -85,6 +93,7 @@
co.elastic.clients
elasticsearch-java
+ ${elastic.version}
test
@@ -129,23 +138,6 @@
-
-
- org.apache.maven.plugins
- maven-failsafe-plugin
-
- true
-
-
-
-
- integration-test
- verify
-
-
-
-
-
org.apache.maven.plugins
maven-surefire-plugin
@@ -170,15 +162,29 @@
docker
+
- false
+
+ linux
+
+
+ env.CI
+ true
+
- 8.10.2
+
+
+ false
+ false
+
- -Xms750m -Xmx750m
+ -Xms750m -Xmx750m
+
@@ -188,7 +194,6 @@
io.fabric8
docker-maven-plugin
- all
true
true
@@ -199,10 +204,11 @@
single-node
false
- ${elastic.java-opts}
+ ${elastic.javaOpts}
- 9200:9200
+
+ localhost:elasticsearch.port:9200
custom
@@ -214,7 +220,11 @@
cyan
- recovered \[0\] indices into cluster_state
+
+
+ 9200
+
+
@@ -232,11 +242,13 @@
logstash
- ${elastic.java-opts}
+ ${elastic.javaOpts}
- 12222:12222
- 12345:12345
+
+ localhost:logstash.gelf.port:12222
+
+ localhost:logstash.tcp.port:12345
[LS]
@@ -248,54 +260,71 @@
--pipeline.batch.size
1
-e
- input {
+ "logstash"
+ use_tcp => true
+ use_udp => false
+ port => 12222
+ type => "gelf"
}
+
+ # Documentation: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-tcp.html
tcp {
- port => 12345
- codec => json
- type => "tcp"
+ port => 12345
+ codec => json
+ type => "tcp"
}
+
}
filter {
if [type] == "gelf" {
# These are GELF/Syslog logging levels as defined in RFC 3164.
- # Map the integer level to its human readable format.
+ # Map the integer level to its human-readable format.
+ # Documentation: https://www.elastic.co/guide/en/logstash/current/plugins-filters-translate.html
translate {
- field => "[level]"
- destination => "[levelName]"
- dictionary => {
- "0" => "EMERG"
- "1" => "ALERT"
- "2" => "CRITICAL"
- "3" => "ERROR"
- "4" => "WARN"
- "5" => "NOTICE"
- "6" => "INFO"
- "7" => "DEBUG"
+ source => "[level]"
+ target => "[levelName]"
+ dictionary => {
+ "0" => "EMERG"
+ "1" => "ALERT"
+ "2" => "CRITICAL"
+ "3" => "ERROR"
+ "4" => "WARN"
+ "5" => "NOTICE"
+ "6" => "INFO"
+ "7" => "DEBUG"
}
}
}
}
+ # Documentation: https://www.elastic.co/guide/en/logstash/current/plugins-filters-elasticsearch.html
output {
# (Un)comment for debugging purposes
- # stdout { codec => rubydebug }
+ # stdout { codec => rubydebug }
elasticsearch {
- hosts => ["http://elasticsearch:9200"]
- index => "log4j"
+ hosts => ["http://elasticsearch:9200"]
+ index => "log4j"
}
- }
+ }
+
+ ]]>
- Successfully started Logstash API endpoint
+
+ localhost
+
+ 12222
+ 12345
+
+
@@ -327,6 +356,11 @@
**/*IT.java
+
+ ${elasticsearch.port}
+ ${logstash.gelf.port}
+ ${logstash.tcp.port}
+
diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java
index abb86f8ebc0..17b83629755 100644
--- a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java
+++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/LogstashIT.java
@@ -16,6 +16,9 @@
*/
package org.apache.logging.log4j.layout.template.json;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.HealthStatus;
@@ -32,6 +35,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
+import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
@@ -41,6 +45,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -53,13 +58,11 @@
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.layout.GelfLayout;
-import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.EventTemplateAdditionalField;
import org.apache.logging.log4j.layout.template.json.util.ThreadLocalRecyclerFactory;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.status.StatusLogger;
-import org.assertj.core.api.Assertions;
-import org.awaitility.Awaitility;
+import org.apache.logging.log4j.util.Strings;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@@ -71,14 +74,14 @@
@Execution(ExecutionMode.SAME_THREAD)
class LogstashIT {
+ private static final String LOG_PREFIX = LogstashIT.class.getSimpleName() + ' ';
+
private static final StatusLogger LOGGER = StatusLogger.getLogger();
private static final DefaultConfiguration CONFIGURATION = new DefaultConfiguration();
private static final Charset CHARSET = StandardCharsets.UTF_8;
- private static final String HOST_NAME = NetUtils.getLocalHostname();
-
private static final String SERVICE_NAME = "LogstashIT";
private static final String EVENT_DATASET = SERVICE_NAME + ".log";
@@ -88,7 +91,7 @@ class LogstashIT {
.setCharset(CHARSET)
.setCompressionType(GelfLayout.CompressionType.OFF)
.setIncludeNullDelimiter(true)
- .setHost(HOST_NAME)
+ .setHost(MavenHardcodedConstants.HOST_NAME)
.build();
private static final JsonTemplateLayout JSON_TEMPLATE_GELF_LAYOUT = JsonTemplateLayout.newBuilder()
@@ -99,13 +102,12 @@ class LogstashIT {
.setEventTemplateAdditionalFields(new EventTemplateAdditionalField[] {
EventTemplateAdditionalField.newBuilder()
.setKey("host")
- .setValue(HOST_NAME)
+ .setValue(MavenHardcodedConstants.HOST_NAME)
.build()
})
.build();
- // Note that EcsLayout doesn't support charset configuration, though it uses
- // UTF-8 internally.
+ // Note that `EcsLayout` doesn't support charset configuration, though it uses UTF-8 internally.
private static final EcsLayout ECS_LAYOUT = EcsLayout.newBuilder()
.setConfiguration(CONFIGURATION)
.setServiceName(SERVICE_NAME)
@@ -140,44 +142,85 @@ class LogstashIT {
private static ElasticsearchClient ES_CLIENT;
/**
- * Constants hardcoded in docker-maven-plugin configuration, do not change!
+ * Constants hardcoded in `docker-maven-plugin` configuration, do not change!
*/
private static final class MavenHardcodedConstants {
private MavenHardcodedConstants() {}
- private static final int LS_GELF_INPUT_PORT = 12222;
+ private static final String HOST_NAME = "localhost";
- private static final int LS_TCP_INPUT_PORT = 12345;
+ private static final int LS_GELF_INPUT_PORT = readPort("log4j.logstash.gelf.port");
- private static final int ES_PORT = 9200;
+ private static final int LS_TCP_INPUT_PORT = readPort("log4j.logstash.tcp.port");
+
+ private static final int ES_PORT = readPort("log4j.elasticsearch.port");
private static final String ES_INDEX_NAME = "log4j";
+
+ private static int readPort(final String propertyName) {
+ final String propertyValue = System.getProperty(propertyName);
+ final int port;
+ final String errorMessage = String.format(
+ "was expecting a valid port number in the system property `%s`, found: `%s`",
+ propertyName, propertyValue);
+ try {
+ if (Strings.isBlank(propertyValue) || (port = Integer.parseInt(propertyValue)) < 0 || port >= 0xFFFF) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+ } catch (final NumberFormatException error) {
+ throw new IllegalArgumentException(errorMessage, error);
+ }
+ return port;
+ }
}
@BeforeAll
- public static void initClient() throws IOException {
+ public static void initEsClient() {
- LOGGER.info("instantiating the ES client");
- REST_CLIENT = RestClient.builder(
- HttpHost.create(String.format("http://%s:%d", HOST_NAME, MavenHardcodedConstants.ES_PORT)))
- .build();
+ LOGGER.info(LOG_PREFIX + "instantiating the ES client");
+ final String hostUri =
+ String.format("http://%s:%d", MavenHardcodedConstants.HOST_NAME, MavenHardcodedConstants.ES_PORT);
+ REST_CLIENT = RestClient.builder(HttpHost.create(hostUri)).build();
ES_TRANSPORT = new RestClientTransport(REST_CLIENT, new JacksonJsonpMapper());
ES_CLIENT = new ElasticsearchClient(ES_TRANSPORT);
- LOGGER.info("verifying the ES connection");
- HealthResponse healthResponse = ES_CLIENT.cluster().health();
- Assertions.assertThat(healthResponse.status()).isNotEqualTo(HealthStatus.Red);
+ LOGGER.info(LOG_PREFIX + "verifying the ES connection to `{}`", hostUri);
+ await("ES cluster health")
+ .pollDelay(100, TimeUnit.MILLISECONDS)
+ .atMost(1, TimeUnit.MINUTES)
+ .untilAsserted(() -> {
+ final HealthResponse healthResponse = ES_CLIENT.cluster().health();
+ assertThat(healthResponse.status()).isNotEqualTo(HealthStatus.Red);
+ });
+ }
+
+ @BeforeAll
+ public static void waitForLsInputSockets() {
+ waitForSocketBinding(MavenHardcodedConstants.LS_GELF_INPUT_PORT, "Logstash GELF input");
+ waitForSocketBinding(MavenHardcodedConstants.LS_TCP_INPUT_PORT, "Logstash TCP input");
+ }
+
+ private static void waitForSocketBinding(final int port, final String name) {
+ LOGGER.info(LOG_PREFIX + "verifying socket binding at port {} for {}", port, name);
+ await("socket binding at port " + port)
+ .pollDelay(100, TimeUnit.MILLISECONDS)
+ .atMost(1, TimeUnit.MINUTES)
+ .untilAsserted(() -> {
+ try (final Socket socket = new Socket(MavenHardcodedConstants.HOST_NAME, port)) {
+ assertThat(socket.isConnected()).isTrue();
+ }
+ });
}
@BeforeEach
void deleteIndex() throws IOException {
- LOGGER.info("deleting the ES index");
+ LOGGER.info(LOG_PREFIX + "deleting the ES index");
try {
DeleteIndexResponse deleteIndexResponse = ES_CLIENT
.indices()
.delete(DeleteIndexRequest.of(builder -> builder.index(MavenHardcodedConstants.ES_INDEX_NAME)));
- Assertions.assertThat(deleteIndexResponse.acknowledged()).isTrue();
+ assertThat(deleteIndexResponse.acknowledged()).isTrue();
} catch (ElasticsearchException error) {
if (!error.getMessage().contains("index_not_found_exception")) {
throw new RuntimeException(error);
@@ -209,15 +252,15 @@ private static void testEvents(final List logEvents) throws IOExceptio
try {
// Append events.
- LOGGER.info("appending events");
+ LOGGER.info(LOG_PREFIX + "appending events");
logEvents.forEach(appender::append);
- LOGGER.info("completed appending events");
+ LOGGER.info(LOG_PREFIX + "completed appending events");
// Wait all messages to arrive.
- Awaitility.await()
+ await("message delivery")
.atMost(Duration.ofSeconds(60))
.pollDelay(Duration.ofSeconds(2))
- .until(() -> checkDocumentCount(LOG_EVENT_COUNT));
+ .untilAsserted(() -> assertDocumentCount(LOG_EVENT_COUNT));
// Verify indexed messages.
final Set expectedMessages = logEvents.stream()
@@ -227,7 +270,7 @@ private static void testEvents(final List logEvents) throws IOExceptio
.map(source -> (String) source.get(ES_INDEX_MESSAGE_FIELD_NAME))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
- Assertions.assertThat(actualMessages).isEqualTo(expectedMessages);
+ assertThat(actualMessages).isEqualTo(expectedMessages);
} finally {
appender.stop();
@@ -280,16 +323,16 @@ void test_newlines() throws IOException {
try {
// Append the event.
- LOGGER.info("appending events");
+ LOGGER.info(LOG_PREFIX + "appending events");
appender.append(logEvent1);
appender.append(logEvent2);
- LOGGER.info("completed appending events");
+ LOGGER.info(LOG_PREFIX + "completed appending events");
// Wait the message to arrive.
- Awaitility.await()
+ await("message delivery")
.atMost(Duration.ofSeconds(60))
.pollDelay(Duration.ofSeconds(2))
- .until(() -> checkDocumentCount(2));
+ .untilAsserted(() -> assertDocumentCount(2));
// Verify indexed messages.
final Set expectedMessages = Stream.of(logEvent1, logEvent2)
@@ -299,7 +342,7 @@ void test_newlines() throws IOException {
.map(source -> (String) source.get(ES_INDEX_MESSAGE_FIELD_NAME))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
- Assertions.assertThat(actualMessages).isEqualTo(expectedMessages);
+ assertThat(actualMessages).isEqualTo(expectedMessages);
} finally {
appender.stop();
@@ -336,7 +379,7 @@ void test_GelfLayout() throws IOException {
Collections.emptySet());
// Compare persisted sources.
- Assertions.assertThat(actualSourceByKey).isEqualTo(expectedSourceByKey);
+ assertThat(actualSourceByKey).isEqualTo(expectedSourceByKey);
}
@Test
@@ -370,7 +413,7 @@ void test_EcsLayout() throws IOException {
excludedKeys);
// Compare persisted sources.
- Assertions.assertThat(actualSourceByKey).isEqualTo(expectedSourceByKey);
+ assertThat(actualSourceByKey).isEqualTo(expectedSourceByKey);
}
private static Map appendAndCollect(
@@ -384,15 +427,15 @@ private static Map appendAndCollect(
try {
// Append the event.
- LOGGER.info("appending events");
+ LOGGER.info(LOG_PREFIX + "appending events");
logEvents.forEach(appender::append);
- LOGGER.info("completed appending events");
+ LOGGER.info(LOG_PREFIX + "completed appending events");
// Wait the message to arrive.
- Awaitility.await()
+ await("message delivery")
.atMost(Duration.ofSeconds(60))
.pollDelay(Duration.ofSeconds(2))
- .until(() -> checkDocumentCount(LOG_EVENT_COUNT));
+ .untilAsserted(() -> assertDocumentCount(LOG_EVENT_COUNT));
// Retrieve the persisted messages.
return queryDocuments().stream().collect(Collectors.toMap(keyMapper, (final Map source) -> {
@@ -406,10 +449,10 @@ private static Map appendAndCollect(
}
private static SocketAppender createStartedAppender(final Layout> layout, final int port) {
- LOGGER.info("creating the appender");
+ LOGGER.info(LOG_PREFIX + "creating the appender");
final SocketAppender appender = SocketAppender.newBuilder()
.setConfiguration(CONFIGURATION)
- .setHost(HOST_NAME)
+ .setHost(MavenHardcodedConstants.HOST_NAME)
.setPort(port)
.setReconnectDelayMillis(100)
.setName("LogstashItAppender")
@@ -422,12 +465,27 @@ private static SocketAppender createStartedAppender(final Layout> layout, fina
return appender;
}
- private static boolean checkDocumentCount(int expectedCount) throws IOException {
- final CountResponse countResponse =
- ES_CLIENT.count(builder -> builder.index(MavenHardcodedConstants.ES_INDEX_NAME));
+ private static void assertDocumentCount(final int expectedCount) throws IOException {
+ final CountResponse countResponse;
+ try {
+ countResponse = ES_CLIENT.count(builder -> builder.index(MavenHardcodedConstants.ES_INDEX_NAME));
+ }
+ // Try to enrich the failure with the available list of indices
+ catch (final ElasticsearchException error) {
+ try {
+ if (error.getMessage().contains("index_not_found_exception")) {
+ final Set indexNames =
+ ES_CLIENT.cluster().health().indices().keySet();
+ final String message = String.format("Could not find index! Available index names: %s", indexNames);
+ throw new AssertionError(message, error);
+ }
+ } catch (final Exception suppressed) {
+ error.addSuppressed(suppressed);
+ }
+ throw error;
+ }
final long actualCount = countResponse.count();
- Assertions.assertThat(actualCount).isLessThanOrEqualTo(expectedCount);
- return actualCount == expectedCount;
+ assertThat(actualCount).isEqualTo(expectedCount);
}
private static List
+
+
+
+
+
+ docker
+
+
+
+
+ linux
+
+
+ env.CI
+ true
+
+
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ all
+ true
+ true
+
+
+ mongo
+ mongo:latest
+
+
+
+ localhost:mongo.port:27017
+
+
+
+
+
+
+
+ start-mongo
+
+ start
+
+
+
+ stop-mongo
+
+ stop
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+
+
+ org.slf4j
+ slf4j-nop
+ ${slf4j2.version}
+
+
+
+
+
+ integration-test
+ verify
+
+
+ true
+
+ **/*IT.java
+
+
+
+ OFF
+
+ ${mongo.port}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/AbstractMongoDbCappedTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/AbstractMongoDbCappedIT.java
similarity index 84%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/AbstractMongoDbCappedTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/AbstractMongoDbCappedIT.java
index 07e39339941..56cf3a89bee 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/AbstractMongoDbCappedTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/AbstractMongoDbCappedIT.java
@@ -23,17 +23,16 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.bson.Document;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-public abstract class AbstractMongoDbCappedTest {
+abstract class AbstractMongoDbCappedIT {
- @Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(AbstractMongoDbCappedTest.class);
+ protected void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(AbstractMongoDbCappedIT.class);
logger.info("Hello log");
final MongoDatabase database = mongoClient.getDatabase(MongoDbTestConstants.DATABASE_NAME);
Assertions.assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDbTestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
Assertions.assertNotNull(collection);
final Document first = collection.find().first();
Assertions.assertNotNull(first);
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAdditionalFieldsTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAdditionalFieldsIT.java
similarity index 88%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAdditionalFieldsTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAdditionalFieldsIT.java
index c74172925f5..f63ecf4ecfd 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAdditionalFieldsTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAdditionalFieldsIT.java
@@ -26,21 +26,25 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Test;
@UsingMongoDb
-@LoggerContextSource("log4j2-mongodb-additional-fields.xml")
-public class MongoDbAdditionalFieldsTest {
+@LoggerContextSource("MongoDbAdditionalFields.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbAdditionalFieldsIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDbAdditionalFieldsTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDbAdditionalFieldsIT.class);
logger.info("Hello log 1");
logger.info("Hello log 2", new RuntimeException("Hello ex 2"));
final MongoDatabase database = mongoClient.getDatabase(MongoDbTestConstants.DATABASE_NAME);
assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDbTestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
assertNotNull(collection);
final FindIterable found = collection.find();
final Document first = found.first();
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthFailureTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthFailureIT.java
similarity index 77%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthFailureTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthFailureIT.java
index 3247dc28c06..5a44aa5456e 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthFailureTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbAuthFailureIT.java
@@ -25,20 +25,25 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Test;
@UsingMongoDb
-@LoggerContextSource("log4j2-mongodb-auth-failure.xml")
-public class MongoDbAuthFailureTest {
+@LoggerContextSource("MongoDbAuthFailureIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbAuthFailureIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDbAuthFailureTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDbAuthFailureIT.class);
logger.info("Hello log");
final MongoDatabase database = mongoClient.getDatabase(MongoDbTestConstants.DATABASE_NAME);
assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDbTestConstants.DATABASE_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
+ ;
assertNotNull(collection);
final Document first = collection.find().first();
assertNull(first);
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedIntTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedIntIT.java
similarity index 64%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedIntTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedIntIT.java
index 500964aff08..887132ded40 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedIntTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedIntIT.java
@@ -16,11 +16,21 @@
*/
package org.apache.logging.log4j.mongodb;
+import com.mongodb.client.MongoClient;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
+import org.junit.jupiter.api.Test;
@UsingMongoDb
-@LoggerContextSource("log4j2-mongodb-capped-int.xml")
-public class MongoDbCappedIntTest extends AbstractMongoDbCappedTest {
+@LoggerContextSource("MongoDbCappedIntIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbCappedIntIT extends AbstractMongoDbCappedIT {
- // test is in superclass
+ @Test
+ @Override
+ protected void test(LoggerContext ctx, MongoClient mongoClient) {
+ super.test(ctx, mongoClient);
+ }
}
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedLongTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedLongIT.java
similarity index 64%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedLongTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedLongIT.java
index 34f921fe7bf..bb6b4e65722 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedLongTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbCappedLongIT.java
@@ -16,11 +16,21 @@
*/
package org.apache.logging.log4j.mongodb;
+import com.mongodb.client.MongoClient;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
+import org.junit.jupiter.api.Test;
@UsingMongoDb
-@LoggerContextSource("log4j2-mongodb-capped-long.xml")
-public class MongoDbCappedLongTest extends AbstractMongoDbCappedTest {
+@LoggerContextSource("MongoDbCappedLongIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbCappedLongIT extends AbstractMongoDbCappedIT {
- // test is in superclass
+ @Test
+ @Override
+ protected void test(LoggerContext ctx, MongoClient mongoClient) {
+ super.test(ctx, mongoClient);
+ }
}
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbIT.java
similarity index 84%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbIT.java
index 5c4bbb750c1..d0f43cc70fd 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbIT.java
@@ -26,21 +26,25 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Test;
@UsingMongoDb
-@LoggerContextSource("log4j2-mongodb.xml")
-public class MongoDbTest {
+@LoggerContextSource("MongoDbIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDbTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDbIT.class);
logger.info("Hello log 1");
logger.info("Hello log 2", new RuntimeException("Hello ex 2"));
final MongoDatabase database = mongoClient.getDatabase(MongoDbTestConstants.DATABASE_NAME);
assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDbTestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
assertNotNull(collection);
final FindIterable found = collection.find();
final Document first = found.first();
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageIT.java
similarity index 81%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageIT.java
index 2733554dbd3..b285529c0ce 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbMapMessageIT.java
@@ -23,24 +23,28 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.message.MapMessage;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@UsingMongoDb
-@LoggerContextSource("log4j2-mongodb-map-message.xml")
-public class MongoDbMapMessageTest {
+@LoggerContextSource("MongoDbMapMessageIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbMapMessageIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDbMapMessageTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDbMapMessageIT.class);
final MapMessage, Object> mapMessage = new MapMessage<>();
mapMessage.with("SomeName", "SomeValue");
mapMessage.with("SomeInt", 1);
logger.info(mapMessage);
final MongoDatabase database = mongoClient.getDatabase(MongoDbTestConstants.DATABASE_NAME);
Assertions.assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDbTestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
Assertions.assertNotNull(collection);
final Document first = collection.find().first();
Assertions.assertNotNull(first);
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolver.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolver.java
index 4b1f394b765..1246d48e496 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolver.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolver.java
@@ -18,67 +18,19 @@
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
-import de.flapdoodle.embed.mongo.commands.ServerAddress;
-import de.flapdoodle.embed.mongo.distribution.Version;
-import de.flapdoodle.embed.mongo.packageresolver.Command;
-import de.flapdoodle.embed.mongo.transitions.Mongod;
-import de.flapdoodle.embed.mongo.transitions.PackageOfCommandDistribution;
-import de.flapdoodle.embed.mongo.transitions.RunningMongodProcess;
-import de.flapdoodle.embed.mongo.types.DistributionBaseUrl;
-import de.flapdoodle.embed.process.config.store.FileSet;
-import de.flapdoodle.embed.process.config.store.FileType;
-import de.flapdoodle.embed.process.config.store.Package;
-import de.flapdoodle.embed.process.distribution.Distribution;
-import de.flapdoodle.embed.process.io.ProcessOutput;
-import de.flapdoodle.embed.process.io.Processors;
-import de.flapdoodle.embed.process.io.StreamProcessor;
-import de.flapdoodle.embed.process.types.Name;
-import de.flapdoodle.embed.process.types.ProcessConfig;
-import de.flapdoodle.os.OSType;
-import de.flapdoodle.reverse.TransitionWalker.ReachedState;
-import de.flapdoodle.reverse.transitions.Derive;
-import de.flapdoodle.reverse.transitions.Start;
-import java.util.Objects;
import java.util.function.Supplier;
-import org.apache.commons.lang3.NotImplementedException;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.test.TestProperties;
import org.apache.logging.log4j.test.junit.ExtensionContextAnchor;
-import org.apache.logging.log4j.test.junit.TestPropertySource;
import org.apache.logging.log4j.test.junit.TypeBasedParameterResolver;
+import org.apache.logging.log4j.util.PropertiesUtil;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
-public class MongoDbResolver extends TypeBasedParameterResolver implements BeforeAllCallback {
+class MongoDbResolver extends TypeBasedParameterResolver implements BeforeAllCallback {
- private static final Logger LOGGER = StatusLogger.getLogger();
- private static final String LOGGING_TARGET_PROPERTY = "log4j2.mongoDbLoggingTarget";
-
- private static final int BUILDER_TIMEOUT_MILLIS = 30000;
-
- private static ProcessOutput getProcessOutput(final LoggingTarget loggingTarget, final String label) {
- if (loggingTarget != null) {
- switch (loggingTarget) {
- case STATUS_LOGGER:
- return ProcessOutput.builder()
- .output(Processors.named(
- "[" + label + " output]", new StatusLoggerStreamProcessor(Level.INFO)))
- .error(Processors.named(
- "[" + label + " error]", new StatusLoggerStreamProcessor(Level.ERROR)))
- .commands(new StatusLoggerStreamProcessor(Level.DEBUG))
- .build();
- case CONSOLE:
- return ProcessOutput.namedConsole(label);
- default:
- }
- }
- throw new NotImplementedException(Objects.toString(loggingTarget));
- }
+ static final String PORT_PROPERTY = "log4j2.mongo.port";
public MongoDbResolver() {
super(MongoClient.class);
@@ -86,40 +38,7 @@ public MongoDbResolver() {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
- final TestProperties props = TestPropertySource.createProperties(context);
- final Mongod mongod = Mongod.builder()
- .processOutput(Derive.given(Name.class)
- .state(ProcessOutput.class)
- .deriveBy(name -> getProcessOutput(
- LoggingTarget.getLoggingTarget(LoggingTarget.STATUS_LOGGER), name.value())))
- .processConfig(Start.to(ProcessConfig.class)
- .initializedWith(ProcessConfig.defaults().withStopTimeoutInMillis(BUILDER_TIMEOUT_MILLIS))
- .withTransitionLabel("create default"))
- // workaround for https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo/issues/309
- .packageOfDistribution(new PackageOfCommandDistribution() {
-
- @Override
- protected Package packageOf(
- Command command, Distribution distribution, DistributionBaseUrl baseUrl) {
- if (distribution.platform().operatingSystem().type() == OSType.Windows) {
- final Package relativePackage =
- commandPackageResolver().apply(command).packageFor(distribution);
- final FileSet.Builder fileSetBuilder = FileSet.builder()
- .addEntry(FileType.Library, "ssleay32.dll")
- .addEntry(FileType.Library, "libeay32.dll");
- relativePackage.fileSet().entries().forEach(fileSetBuilder::addEntries);
- return Package.builder()
- .archiveType(relativePackage.archiveType())
- .fileSet(fileSetBuilder.build())
- .url(baseUrl.value() + relativePackage.url())
- .hint(relativePackage.hint())
- .build();
- }
- return super.packageOf(command, distribution, baseUrl);
- }
- })
- .build();
- ExtensionContextAnchor.setAttribute(MongoClientHolder.class, new MongoClientHolder(mongod, props), context);
+ ExtensionContextAnchor.setAttribute(MongoClientHolder.class, new MongoClientHolder(), context);
}
@Override
@@ -129,25 +48,13 @@ public MongoClient resolveParameter(ParameterContext parameterContext, Extension
.get();
}
- public enum LoggingTarget {
- CONSOLE,
- STATUS_LOGGER;
-
- public static LoggingTarget getLoggingTarget(final LoggingTarget defaultValue) {
- return LoggingTarget.valueOf(System.getProperty(LOGGING_TARGET_PROPERTY, defaultValue.name()));
- }
- }
-
private static final class MongoClientHolder implements CloseableResource, Supplier {
- private final ReachedState state;
private final MongoClient mongoClient;
- public MongoClientHolder(final Mongod mongod, final TestProperties props) {
- state = mongod.start(Version.Main.V7_0);
- final RunningMongodProcess mongodProcess = state.current();
- final ServerAddress addr = mongodProcess.getServerAddress();
- mongoClient = MongoClients.create(String.format("mongodb://%s:%d", addr.getHost(), addr.getPort()));
- props.setProperty(MongoDbTestConstants.PROP_NAME_PORT, addr.getPort());
+ public MongoClientHolder() {
+ mongoClient = MongoClients.create(String.format(
+ "mongodb://localhost:%d",
+ PropertiesUtil.getProperties().getIntegerProperty(MongoDbTestConstants.PROP_NAME_PORT, 27017)));
}
@Override
@@ -158,32 +65,6 @@ public MongoClient get() {
@Override
public void close() throws Exception {
mongoClient.close();
- state.close();
- }
- }
-
- private static final class StatusLoggerStreamProcessor implements StreamProcessor {
-
- private final Level level;
-
- public StatusLoggerStreamProcessor(Level level) {
- this.level = level;
- }
-
- @Override
- public void process(String line) {
- LOGGER.log(level, () -> stripLineEndings(line));
- }
-
- @Override
- public void onProcessed() {
- // noop
- }
-
- String stripLineEndings(String line) {
- // we still need to remove line endings that are passed on by
- // StreamToLineProcessor...
- return line.replaceAll("[\n\r]+", "");
}
}
}
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolverTest.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolverIT.java
similarity index 86%
rename from log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolverTest.java
rename to log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolverIT.java
index 199cabcb2fe..dd6a544ca95 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolverTest.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbResolverIT.java
@@ -20,6 +20,7 @@
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoIterable;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.junit.jupiter.api.Test;
/**
@@ -29,10 +30,12 @@
*
*/
@UsingMongoDb
-public class MongoDbResolverTest {
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDbResolverIT {
@Test
- public void testAccess(final MongoClient mongoClient) {
+ void testAccess(final MongoClient mongoClient) {
final MongoIterable databaseNames = mongoClient.listDatabaseNames();
assertNotNull(databaseNames);
assertNotNull(databaseNames.first());
diff --git a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestConstants.java b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestConstants.java
index ed5435599b9..95ed9ccbb5d 100644
--- a/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestConstants.java
+++ b/log4j-mongodb/src/test/java/org/apache/logging/log4j/mongodb/MongoDbTestConstants.java
@@ -18,7 +18,6 @@
public class MongoDbTestConstants {
- public static final String PROP_NAME_PORT = "MongoDBTestPort";
- static final String COLLECTION_NAME = "testCollection";
+ public static final String PROP_NAME_PORT = "log4j.mongo.port";
static final String DATABASE_NAME = "testDb";
}
diff --git a/log4j-mongodb/src/test/resources/MongoDbAdditionalFields.xml b/log4j-mongodb/src/test/resources/MongoDbAdditionalFields.xml
new file mode 100644
index 00000000000..96528f13911
--- /dev/null
+++ b/log4j-mongodb/src/test/resources/MongoDbAdditionalFields.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-mongodb/src/test/resources/MongoDbAuthFailureIT.xml b/log4j-mongodb/src/test/resources/MongoDbAuthFailureIT.xml
new file mode 100644
index 00000000000..23fbbdf3aca
--- /dev/null
+++ b/log4j-mongodb/src/test/resources/MongoDbAuthFailureIT.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb-capped-int.xml b/log4j-mongodb/src/test/resources/MongoDbCappedIntIT.xml
similarity index 70%
rename from log4j-mongodb/src/test/resources/log4j2-mongodb-capped-int.xml
rename to log4j-mongodb/src/test/resources/MongoDbCappedIntIT.xml
index 746b19914e7..bdaa8e3f40d 100644
--- a/log4j-mongodb/src/test/resources/log4j2-mongodb-capped-int.xml
+++ b/log4j-mongodb/src/test/resources/MongoDbCappedIntIT.xml
@@ -15,18 +15,22 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
+
-
+
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb-capped-long.xml b/log4j-mongodb/src/test/resources/MongoDbCappedLongIT.xml
similarity index 71%
rename from log4j-mongodb/src/test/resources/log4j2-mongodb-capped-long.xml
rename to log4j-mongodb/src/test/resources/MongoDbCappedLongIT.xml
index 941ea71c4e2..6e3b8d6aad8 100644
--- a/log4j-mongodb/src/test/resources/log4j2-mongodb-capped-long.xml
+++ b/log4j-mongodb/src/test/resources/MongoDbCappedLongIT.xml
@@ -15,19 +15,23 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
+
-
+
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb-additional-fields.xml b/log4j-mongodb/src/test/resources/MongoDbIT.xml
similarity index 68%
rename from log4j-mongodb/src/test/resources/log4j2-mongodb-additional-fields.xml
rename to log4j-mongodb/src/test/resources/MongoDbIT.xml
index d9d27461a00..9c9ab6037ee 100644
--- a/log4j-mongodb/src/test/resources/log4j2-mongodb-additional-fields.xml
+++ b/log4j-mongodb/src/test/resources/MongoDbIT.xml
@@ -15,19 +15,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
-
-
-
-
-
+
+
-
+
diff --git a/log4j-mongodb4/src/test/resources/log4j2-mongodb-map-message.xml b/log4j-mongodb/src/test/resources/MongoDbMapMessageIT.xml
similarity index 68%
rename from log4j-mongodb4/src/test/resources/log4j2-mongodb-map-message.xml
rename to log4j-mongodb/src/test/resources/MongoDbMapMessageIT.xml
index a84154e78da..dc6aa6846bd 100644
--- a/log4j-mongodb4/src/test/resources/log4j2-mongodb-map-message.xml
+++ b/log4j-mongodb/src/test/resources/MongoDbMapMessageIT.xml
@@ -15,16 +15,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
-
+
+
-
+
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb.xml b/log4j-mongodb/src/test/resources/log4j2-mongodb.xml
deleted file mode 100644
index 4f0865b2c46..00000000000
--- a/log4j-mongodb/src/test/resources/log4j2-mongodb.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/log4j-mongodb4/pom.xml b/log4j-mongodb4/pom.xml
index e4a9eefaeff..04639d0b535 100644
--- a/log4j-mongodb4/pom.xml
+++ b/log4j-mongodb4/pom.xml
@@ -35,55 +35,61 @@
org.apache.logging.log4j.core
- 4.11.3
+ 4.11.4
+ 1.7.36
+
org.mongodb
bson
${mongodb4.version}
+
org.mongodb
mongodb-driver-core
${mongodb4.version}
-
- org.mongodb
- mongodb-driver-legacy
- ${mongodb4.version}
-
+
org.mongodb
mongodb-driver-sync
${mongodb4.version}
+
+
org.apache.logging.log4j
log4j-api
+
org.apache.logging.log4j
log4j-core
+
org.mongodb
bson
+
org.mongodb
mongodb-driver-core
+
org.mongodb
mongodb-driver-sync
+
org.apache.logging.log4j
log4j-api-test
@@ -95,6 +101,7 @@
+
org.apache.logging.log4j
log4j-core-test
@@ -106,31 +113,19 @@
+
org.apache.commons
commons-lang3
test
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
-
- de.flapdoodle.embed
- de.flapdoodle.embed.process
- test
-
-
- de.flapdoodle.reverse
- de.flapdoodle.reverse
- test
-
+
org.junit.jupiter
junit-jupiter-api
test
+
@@ -140,8 +135,7 @@
org.apache.maven.plugins
maven-surefire-plugin
-
- 1
+ true
@@ -155,4 +149,110 @@
+
+
+
+ docker
+
+
+
+
+ linux
+
+
+ env.CI
+ true
+
+
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ all
+ true
+ true
+
+
+ mongo
+ mongo:latest
+
+
+
+ localhost:mongo.port:27017
+
+
+
+
+
+
+
+ start-mongo
+
+ start
+
+
+
+ stop-mongo
+
+ stop
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+
+
+ org.slf4j
+ slf4j-nop
+ ${slf4j.version}
+
+
+
+
+
+ integration-test
+ verify
+
+
+ true
+
+ **/*IT.java
+
+
+
+ OFF
+
+ ${mongo.port}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/AbstractMongoDb4CappedTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/AbstractMongoDb4CappedIT.java
similarity index 84%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/AbstractMongoDb4CappedTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/AbstractMongoDb4CappedIT.java
index 6f54e77c7e3..6be4f7f6852 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/AbstractMongoDb4CappedTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/AbstractMongoDb4CappedIT.java
@@ -23,17 +23,16 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.bson.Document;
import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-public abstract class AbstractMongoDb4CappedTest {
+abstract class AbstractMongoDb4CappedIT {
- @Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(AbstractMongoDb4CappedTest.class);
+ protected void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(AbstractMongoDb4CappedIT.class);
logger.info("Hello log");
final MongoDatabase database = mongoClient.getDatabase(MongoDb4TestConstants.DATABASE_NAME);
Assertions.assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDb4TestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
Assertions.assertNotNull(collection);
final Document first = collection.find().first();
Assertions.assertNotNull(first);
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AdditionalFieldsTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AdditionalFieldsIT.java
similarity index 88%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AdditionalFieldsTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AdditionalFieldsIT.java
index 27062452bf6..b5ccc77e735 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AdditionalFieldsTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AdditionalFieldsIT.java
@@ -26,21 +26,25 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Test;
@UsingMongoDb4
-@LoggerContextSource("log4j2-mongodb-additional-fields.xml")
-public class MongoDb4AdditionalFieldsTest {
+@LoggerContextSource("MongoDb4AdditionalFields.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4AdditionalFieldsIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDb4AdditionalFieldsTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDb4AdditionalFieldsIT.class);
logger.info("Hello log 1");
logger.info("Hello log 2", new RuntimeException("Hello ex 2"));
final MongoDatabase database = mongoClient.getDatabase(MongoDb4TestConstants.DATABASE_NAME);
assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDb4TestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
assertNotNull(collection);
final FindIterable found = collection.find();
final Document first = found.first();
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureIT.java
similarity index 76%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureIT.java
index 641305256c4..c5b5b15c6db 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4AuthFailureIT.java
@@ -25,20 +25,25 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Test;
@UsingMongoDb4
-@LoggerContextSource("log4j2-mongodb-auth-failure.xml")
-public class MongoDb4AuthFailureTest {
+@LoggerContextSource("MongoDb4AuthFailureIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4AuthFailureIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDb4AuthFailureTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDb4AuthFailureIT.class);
logger.info("Hello log");
final MongoDatabase database = mongoClient.getDatabase(MongoDb4TestConstants.DATABASE_NAME);
assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDb4TestConstants.DATABASE_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
+ ;
assertNotNull(collection);
final Document first = collection.find().first();
assertNull(first);
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedIntTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedIntIT.java
similarity index 64%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedIntTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedIntIT.java
index e01e0c0d63b..24add71aa5d 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedIntTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedIntIT.java
@@ -16,11 +16,21 @@
*/
package org.apache.logging.log4j.mongodb4;
+import com.mongodb.client.MongoClient;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
+import org.junit.jupiter.api.Test;
@UsingMongoDb4
-@LoggerContextSource("log4j2-mongodb-capped-int.xml")
-public class MongoDb4CappedIntTest extends AbstractMongoDb4CappedTest {
+@LoggerContextSource("MongoDb4CappedIntIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4CappedIntIT extends AbstractMongoDb4CappedIT {
- // test is in superclass
+ @Test
+ @Override
+ protected void test(LoggerContext ctx, MongoClient mongoClient) {
+ super.test(ctx, mongoClient);
+ }
}
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedLongTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedLongIT.java
similarity index 64%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedLongTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedLongIT.java
index 0a99dbf5b87..580c6c60fa6 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedLongTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4CappedLongIT.java
@@ -16,11 +16,21 @@
*/
package org.apache.logging.log4j.mongodb4;
+import com.mongodb.client.MongoClient;
+import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
+import org.junit.jupiter.api.Test;
@UsingMongoDb4
-@LoggerContextSource("log4j2-mongodb-capped-long.xml")
-public class MongoDb4CappedLongTest extends AbstractMongoDb4CappedTest {
+@LoggerContextSource("MongoDb4CappedLongIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4CappedLongIT extends AbstractMongoDb4CappedIT {
- // test is in superclass
+ @Test
+ @Override
+ protected void test(LoggerContext ctx, MongoClient mongoClient) {
+ super.test(ctx, mongoClient);
+ }
}
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Test.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4IT.java
similarity index 84%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Test.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4IT.java
index 140a9597505..ac0c550efca 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Test.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4IT.java
@@ -26,21 +26,25 @@
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Test;
@UsingMongoDb4
-@LoggerContextSource("log4j2-mongodb.xml")
-public class MongoDb4Test {
+@LoggerContextSource("MongoDb4IT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4IT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDb4Test.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDb4IT.class);
logger.info("Hello log 1");
logger.info("Hello log 2", new RuntimeException("Hello ex 2"));
final MongoDatabase database = mongoClient.getDatabase(MongoDb4TestConstants.DATABASE_NAME);
assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDb4TestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
assertNotNull(collection);
final FindIterable found = collection.find();
final Document first = found.first();
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageIT.java
similarity index 80%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageIT.java
index d8877392448..b7a384c23b1 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4MapMessageIT.java
@@ -23,24 +23,28 @@
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.message.MapMessage;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.bson.Document;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@UsingMongoDb4
-@LoggerContextSource("log4j2-mongodb-map-message.xml")
-public class MongoDb4MapMessageTest {
+@LoggerContextSource("MongoDb4MapMessageIT.xml")
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4MapMessageIT {
@Test
- public void test(final LoggerContext ctx, final MongoClient mongoClient) {
- final Logger logger = ctx.getLogger(MongoDb4MapMessageTest.class);
+ void test(final LoggerContext ctx, final MongoClient mongoClient) {
+ final Logger logger = ctx.getLogger(MongoDb4MapMessageIT.class);
final MapMessage, Object> mapMessage = new MapMessage<>();
mapMessage.with("SomeName", "SomeValue");
mapMessage.with("SomeInt", 1);
logger.info(mapMessage);
final MongoDatabase database = mongoClient.getDatabase(MongoDb4TestConstants.DATABASE_NAME);
Assertions.assertNotNull(database);
- final MongoCollection collection = database.getCollection(MongoDb4TestConstants.COLLECTION_NAME);
+ final MongoCollection collection =
+ database.getCollection(getClass().getSimpleName());
Assertions.assertNotNull(collection);
final Document first = collection.find().first();
Assertions.assertNotNull(first);
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Resolver.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Resolver.java
index 90c71606cfc..e7994f10297 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Resolver.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4Resolver.java
@@ -18,69 +18,19 @@
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
-import de.flapdoodle.embed.mongo.commands.ServerAddress;
-import de.flapdoodle.embed.mongo.distribution.Version;
-import de.flapdoodle.embed.mongo.packageresolver.Command;
-import de.flapdoodle.embed.mongo.transitions.Mongod;
-import de.flapdoodle.embed.mongo.transitions.PackageOfCommandDistribution;
-import de.flapdoodle.embed.mongo.transitions.RunningMongodProcess;
-import de.flapdoodle.embed.mongo.types.DistributionBaseUrl;
-import de.flapdoodle.embed.process.config.store.FileSet;
-import de.flapdoodle.embed.process.config.store.FileType;
-import de.flapdoodle.embed.process.config.store.Package;
-import de.flapdoodle.embed.process.distribution.Distribution;
-import de.flapdoodle.embed.process.io.ProcessOutput;
-import de.flapdoodle.embed.process.io.Processors;
-import de.flapdoodle.embed.process.io.StreamProcessor;
-import de.flapdoodle.embed.process.types.Name;
-import de.flapdoodle.embed.process.types.ProcessConfig;
-import de.flapdoodle.os.OSType;
-import de.flapdoodle.reverse.TransitionWalker.ReachedState;
-import de.flapdoodle.reverse.transitions.Derive;
-import de.flapdoodle.reverse.transitions.Start;
-import java.util.Objects;
import java.util.function.Supplier;
-import org.apache.commons.lang3.NotImplementedException;
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.test.TestProperties;
import org.apache.logging.log4j.test.junit.ExtensionContextAnchor;
-import org.apache.logging.log4j.test.junit.TestPropertySource;
import org.apache.logging.log4j.test.junit.TypeBasedParameterResolver;
+import org.apache.logging.log4j.util.PropertiesUtil;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
-public class MongoDb4Resolver extends TypeBasedParameterResolver implements BeforeAllCallback {
+class MongoDb4Resolver extends TypeBasedParameterResolver implements BeforeAllCallback {
- private static final Logger LOGGER = StatusLogger.getLogger();
- private static final String LOGGING_TARGET_PROPERTY = "log4j2.mongoDbLoggingTarget";
-
- private static final int BUILDER_TIMEOUT_MILLIS = 30000;
-
- private static ProcessOutput getProcessOutput(final LoggingTarget loggingTarget, final String label) {
- if (loggingTarget != null) {
- switch (loggingTarget) {
- case STATUS_LOGGER:
- // @formatter:off
- return ProcessOutput.builder()
- .output(Processors.named(
- "[" + label + " output]", new StatusLoggerStreamProcessor(Level.INFO)))
- .error(Processors.named(
- "[" + label + " error]", new StatusLoggerStreamProcessor(Level.ERROR)))
- .commands(new StatusLoggerStreamProcessor(Level.DEBUG))
- .build();
- // @formatter:on
- case CONSOLE:
- return ProcessOutput.namedConsole(label);
- default:
- }
- }
- throw new NotImplementedException(Objects.toString(loggingTarget));
- }
+ static final String PORT_PROPERTY = "log4j2.mongo.port";
public MongoDb4Resolver() {
super(MongoClient.class);
@@ -88,40 +38,7 @@ public MongoDb4Resolver() {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
- final TestProperties props = TestPropertySource.createProperties(context);
- final Mongod mongod = Mongod.builder()
- .processOutput(Derive.given(Name.class)
- .state(ProcessOutput.class)
- .deriveBy(name -> getProcessOutput(
- LoggingTarget.getLoggingTarget(LoggingTarget.STATUS_LOGGER), name.value())))
- .processConfig(Start.to(ProcessConfig.class)
- .initializedWith(ProcessConfig.defaults().withStopTimeoutInMillis(BUILDER_TIMEOUT_MILLIS))
- .withTransitionLabel("create default"))
- // workaround for https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo/issues/309
- .packageOfDistribution(new PackageOfCommandDistribution() {
-
- @Override
- protected Package packageOf(
- Command command, Distribution distribution, DistributionBaseUrl baseUrl) {
- if (distribution.platform().operatingSystem().type() == OSType.Windows) {
- final Package relativePackage =
- commandPackageResolver().apply(command).packageFor(distribution);
- final FileSet.Builder fileSetBuilder = FileSet.builder()
- .addEntry(FileType.Library, "ssleay32.dll")
- .addEntry(FileType.Library, "libeay32.dll");
- relativePackage.fileSet().entries().forEach(fileSetBuilder::addEntries);
- return Package.builder()
- .archiveType(relativePackage.archiveType())
- .fileSet(fileSetBuilder.build())
- .url(baseUrl.value() + relativePackage.url())
- .hint(relativePackage.hint())
- .build();
- }
- return super.packageOf(command, distribution, baseUrl);
- }
- })
- .build();
- ExtensionContextAnchor.setAttribute(MongoClientHolder.class, new MongoClientHolder(mongod, props), context);
+ ExtensionContextAnchor.setAttribute(MongoClientHolder.class, new MongoClientHolder(), context);
}
@Override
@@ -131,25 +48,13 @@ public MongoClient resolveParameter(ParameterContext parameterContext, Extension
.get();
}
- public enum LoggingTarget {
- CONSOLE,
- STATUS_LOGGER;
-
- public static LoggingTarget getLoggingTarget(final LoggingTarget defaultValue) {
- return LoggingTarget.valueOf(System.getProperty(LOGGING_TARGET_PROPERTY, defaultValue.name()));
- }
- }
-
private static final class MongoClientHolder implements CloseableResource, Supplier {
- private final ReachedState state;
private final MongoClient mongoClient;
- public MongoClientHolder(final Mongod mongod, final TestProperties props) {
- state = mongod.start(Version.Main.V7_0);
- final RunningMongodProcess mongodProcess = state.current();
- final ServerAddress addr = mongodProcess.getServerAddress();
- mongoClient = MongoClients.create(String.format("mongodb://%s:%d", addr.getHost(), addr.getPort()));
- props.setProperty(MongoDb4TestConstants.PROP_NAME_PORT, addr.getPort());
+ public MongoClientHolder() {
+ mongoClient = MongoClients.create(String.format(
+ "mongodb://localhost:%d",
+ PropertiesUtil.getProperties().getIntegerProperty(MongoDb4TestConstants.PROP_NAME_PORT, 27017)));
}
@Override
@@ -160,32 +65,6 @@ public MongoClient get() {
@Override
public void close() throws Exception {
mongoClient.close();
- state.close();
- }
- }
-
- private static final class StatusLoggerStreamProcessor implements StreamProcessor {
-
- private final Level level;
-
- public StatusLoggerStreamProcessor(Level level) {
- this.level = level;
- }
-
- @Override
- public void process(String line) {
- LOGGER.log(level, () -> stripLineEndings(line));
- }
-
- @Override
- public void onProcessed() {
- // noop
- }
-
- String stripLineEndings(String line) {
- // we still need to remove line endings that are passed on by
- // StreamToLineProcessor...
- return line.replaceAll("[\n\r]+", "");
}
}
}
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4ResolverTest.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4ResolverIT.java
similarity index 86%
rename from log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4ResolverTest.java
rename to log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4ResolverIT.java
index 9d0bebe5e0b..d63b07072bf 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4ResolverTest.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4ResolverIT.java
@@ -20,6 +20,7 @@
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoIterable;
+import org.apache.logging.log4j.test.junit.UsingStatusListener;
import org.junit.jupiter.api.Test;
/**
@@ -29,10 +30,12 @@
*
*/
@UsingMongoDb4
-public class MongoDb4ResolverTest {
+// Print debug status logger output upon failure
+@UsingStatusListener
+class MongoDb4ResolverIT {
@Test
- public void testAccess(final MongoClient mongoClient) {
+ void testAccess(final MongoClient mongoClient) {
final MongoIterable databaseNames = mongoClient.listDatabaseNames();
assertNotNull(databaseNames);
assertNotNull(databaseNames.first());
diff --git a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java
index 6f43c72527e..5245c686700 100644
--- a/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java
+++ b/log4j-mongodb4/src/test/java/org/apache/logging/log4j/mongodb4/MongoDb4TestConstants.java
@@ -18,7 +18,6 @@
public class MongoDb4TestConstants {
- public static final String PROP_NAME_PORT = "MongoDBTestPort";
- static final String COLLECTION_NAME = "testCollection";
+ public static final String PROP_NAME_PORT = "log4j.mongo.port";
static final String DATABASE_NAME = "testDb";
}
diff --git a/log4j-mongodb4/src/test/resources/MongoDb4AdditionalFields.xml b/log4j-mongodb4/src/test/resources/MongoDb4AdditionalFields.xml
new file mode 100644
index 00000000000..6892bcac508
--- /dev/null
+++ b/log4j-mongodb4/src/test/resources/MongoDb4AdditionalFields.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-mongodb4/src/test/resources/log4j2-mongodb-auth-failure.xml b/log4j-mongodb4/src/test/resources/MongoDb4AuthFailureIT.xml
similarity index 67%
rename from log4j-mongodb4/src/test/resources/log4j2-mongodb-auth-failure.xml
rename to log4j-mongodb4/src/test/resources/MongoDb4AuthFailureIT.xml
index 0674de4fa0c..fa8a46bbebe 100644
--- a/log4j-mongodb4/src/test/resources/log4j2-mongodb-auth-failure.xml
+++ b/log4j-mongodb4/src/test/resources/MongoDb4AuthFailureIT.xml
@@ -15,16 +15,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
+
+ connection="mongodb://log4jUser:12345678@localhost:${sys:log4j.mongo.port:-27017}/testDb.MongoDb4AuthFailureIT" />
-
+
diff --git a/log4j-mongodb4/src/test/resources/log4j2-mongodb-capped-int.xml b/log4j-mongodb4/src/test/resources/MongoDb4CappedIntIT.xml
similarity index 70%
rename from log4j-mongodb4/src/test/resources/log4j2-mongodb-capped-int.xml
rename to log4j-mongodb4/src/test/resources/MongoDb4CappedIntIT.xml
index 03aca2ebbea..2e9a11cb68a 100644
--- a/log4j-mongodb4/src/test/resources/log4j2-mongodb-capped-int.xml
+++ b/log4j-mongodb4/src/test/resources/MongoDb4CappedIntIT.xml
@@ -15,18 +15,22 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
+
-
+
diff --git a/log4j-mongodb4/src/test/resources/log4j2-mongodb-capped-long.xml b/log4j-mongodb4/src/test/resources/MongoDb4CappedLongIT.xml
similarity index 71%
rename from log4j-mongodb4/src/test/resources/log4j2-mongodb-capped-long.xml
rename to log4j-mongodb4/src/test/resources/MongoDb4CappedLongIT.xml
index ddde9bcb05e..b79a4dc59e8 100644
--- a/log4j-mongodb4/src/test/resources/log4j2-mongodb-capped-long.xml
+++ b/log4j-mongodb4/src/test/resources/MongoDb4CappedLongIT.xml
@@ -15,19 +15,23 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
+
-
+
diff --git a/log4j-mongodb/src/test/resources/log4j2-mongodb-auth-failure.xml b/log4j-mongodb4/src/test/resources/MongoDb4IT.xml
similarity index 68%
rename from log4j-mongodb/src/test/resources/log4j2-mongodb-auth-failure.xml
rename to log4j-mongodb4/src/test/resources/MongoDb4IT.xml
index e84603a0a52..6ab35f8765a 100644
--- a/log4j-mongodb/src/test/resources/log4j2-mongodb-auth-failure.xml
+++ b/log4j-mongodb4/src/test/resources/MongoDb4IT.xml
@@ -15,16 +15,19 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
-
+
+
-
+
diff --git a/log4j-mongodb4/src/test/resources/MongoDb4MapMessageIT.xml b/log4j-mongodb4/src/test/resources/MongoDb4MapMessageIT.xml
new file mode 100644
index 00000000000..8990a64afcc
--- /dev/null
+++ b/log4j-mongodb4/src/test/resources/MongoDb4MapMessageIT.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-mongodb4/src/test/resources/log4j2-mongodb-additional-fields.xml b/log4j-mongodb4/src/test/resources/log4j2-mongodb-additional-fields.xml
deleted file mode 100644
index eec98585cd9..00000000000
--- a/log4j-mongodb4/src/test/resources/log4j2-mongodb-additional-fields.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/log4j-mongodb4/src/test/resources/log4j2-mongodb.xml b/log4j-mongodb4/src/test/resources/log4j2-mongodb.xml
deleted file mode 100644
index b36a58affc9..00000000000
--- a/log4j-mongodb4/src/test/resources/log4j2-mongodb.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/log4j-parent/pom.xml b/log4j-parent/pom.xml
index 0bfb616f0f4..1faa00a7101 100644
--- a/log4j-parent/pom.xml
+++ b/log4j-parent/pom.xml
@@ -53,7 +53,6 @@
2.2.4
0.45.0
4.13.5
- 3.0.2
2.4
3.5.0
@@ -79,12 +78,9 @@
1.2.15
3.4.4
- 8.15.0
0.9.0
7.0.5
- 4.13.1
- 1.8.0
- 3.0.22
+ 4.0.22
33.3.0-jre
2.2.224
3.0
@@ -109,7 +105,6 @@
1.7.0
4.0.5
0.6.0
- 9.4.55.v20240627
3.5.12
1.37
2.40.1
@@ -135,7 +130,6 @@
2.7.18
5.3.39
2.0.3
- 10.0.27
1.7
2.35.2
2.10.0
@@ -178,7 +172,7 @@
- org.codehaus.groovy
+ org.apache.groovy
groovy-bom
${groovy.version}
pom
@@ -201,14 +195,6 @@
import
-
- org.eclipse.jetty
- jetty-bom
- ${jetty.version}
- pom
- import
-
-
org.junit
junit-bom
@@ -372,24 +358,6 @@
${commons-pool2.version}
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- ${flapdoodle-embed.version}
-
-
-
- de.flapdoodle.embed
- de.flapdoodle.embed.process
- ${flapdoodle-embed.version}
-
-
-
- de.flapdoodle.reverse
- de.flapdoodle.reverse
- ${flapdoodle-reverse.version}
-
-
com.conversantmedia
disruptor
@@ -402,12 +370,6 @@
${disruptor.version}
-
- co.elastic.clients
- elasticsearch-java
- ${elasticsearch-java.version}
-
-
org.zapodot
embedded-ldap-junit
@@ -814,12 +776,6 @@
${system-stubs.version}
-
- org.apache.tomcat
- tomcat-juli
- ${tomcat-juli.version}
-
-
org.apache.velocity
velocity
@@ -900,7 +856,7 @@
-
+
io.fabric8
docker-maven-plugin
@@ -999,21 +955,6 @@
org.codehaus.gmavenplus
gmavenplus-plugin
- ${gmavenplus-plugin.version}
-
-
- org.codehaus.groovy
- groovy-ant
- ${groovy.version}
- runtime
-
-
- org.codehaus.groovy
- groovy
- ${groovy.version}
- runtime
-
-
ban-static-transitive
diff --git a/pom.xml b/pom.xml
index ca216b5a2ed..dcd499d2d38 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
org.apache.logging
logging-parent
- 11.2.0
+ 11.3.0
diff --git a/src/changelog/.2.x.x/2229_mongodb_docker.xml b/src/changelog/.2.x.x/2229_mongodb_docker.xml
new file mode 100644
index 00000000000..1d5b36ed1ca
--- /dev/null
+++ b/src/changelog/.2.x.x/2229_mongodb_docker.xml
@@ -0,0 +1,8 @@
+
+
+
+ Switch MongoDB tests to use Docker.
+
diff --git a/src/changelog/.2.x.x/2937-http-watcher.xml b/src/changelog/.2.x.x/2937-http-watcher.xml
new file mode 100644
index 00000000000..ec3e1a14263
--- /dev/null
+++ b/src/changelog/.2.x.x/2937-http-watcher.xml
@@ -0,0 +1,8 @@
+
+
+
+ Fix reloading of the configuration from an HTTP(S) source
+
diff --git a/src/changelog/.2.x.x/2953_enable_docker_for_JTL.xml b/src/changelog/.2.x.x/2953_enable_docker_for_JTL.xml
new file mode 100644
index 00000000000..4d0f8d434f1
--- /dev/null
+++ b/src/changelog/.2.x.x/2953_enable_docker_for_JTL.xml
@@ -0,0 +1,8 @@
+
+
+
+ Enable Docker-based tests in CI for JSON Template Layout
+
diff --git a/src/changelog/.2.x.x/update_org_apache_logging_logging_parent.xml b/src/changelog/.2.x.x/update_org_apache_logging_logging_parent.xml
new file mode 100644
index 00000000000..5b17082960b
--- /dev/null
+++ b/src/changelog/.2.x.x/update_org_apache_logging_logging_parent.xml
@@ -0,0 +1,7 @@
+
+
+ Update `org.apache.logging:logging-parent` to version `11.3.0`
+