You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2024/09/01 20:49:27 UTC

(logging-log4j2) branch feature/main/move-conversant created (now 58bf2c842d)

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a change to branch feature/main/move-conversant
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


      at 58bf2c842d Document `DisruptorBlockingQueue` move

This branch includes the following new commits:

     new 790621c942 Move ConversantMedia disruptor support to new module
     new 58bf2c842d Document `DisruptorBlockingQueue` move

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(logging-log4j2) 01/02: Move ConversantMedia disruptor support to new module

Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch feature/main/move-conversant
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 790621c942b5e664be160732edd9743b0f4efede
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Mon Apr 1 23:54:22 2024 +0200

    Move ConversantMedia disruptor support to new module
    
    Moves `DisruptorBlockingQueue` to a separate module.
---
 .../.log4j-plugin-processing-activator             |   1 +
 {log4j-kit => log4j-conversant}/pom.xml            |  66 ++++++-------
 .../conversant}/DisruptorBlockingQueueFactory.java |   9 +-
 .../log4j/conversant/DisruptorProperties.java      |  46 +++++++---
 .../DisruptorRecyclerFactoryProvider.java          | 102 +++++++++++++++++++++
 .../logging/log4j/conversant/package-info.java     |  22 +++++
 .../test/DisruptorBlockingQueueFactoryTest.java    |  15 ++-
 .../test/DisruptorRecyclerFactoryProviderTest.java |  44 +++++++++
 .../DisruptorBlockingQueueFactoryTest.xml          |  26 +++---
 log4j-core-test/pom.xml                            |   7 +-
 log4j-core/pom.xml                                 |  33 +++----
 log4j-jctools/.log4j-plugin-processing-activator   |   1 +
 .../jctools/JCToolsBlockingQueueFactoryTest.java   |   9 +-
 .../resources/JCToolsBlockingQueueFactoryTest.xml  |  24 +++--
 ...ging.log4j.kit.recycler.RecyclerFactoryProvider |   6 --
 log4j-kit/pom.xml                                  |   1 +
 .../log4j/kit/recycler/RecyclerProperties.java     |   6 ++
 log4j-parent/pom.xml                               |   7 --
 log4j-perf-test/pom.xml                            |  12 +--
 pom.xml                                            |   7 ++
 20 files changed, 301 insertions(+), 143 deletions(-)

diff --git a/log4j-conversant/.log4j-plugin-processing-activator b/log4j-conversant/.log4j-plugin-processing-activator
new file mode 100644
index 0000000000..ba133f3696
--- /dev/null
+++ b/log4j-conversant/.log4j-plugin-processing-activator
@@ -0,0 +1 @@
+This file is here to activate the `plugin-processing` Maven profile.
diff --git a/log4j-kit/pom.xml b/log4j-conversant/pom.xml
similarity index 63%
copy from log4j-kit/pom.xml
copy to log4j-conversant/pom.xml
index c888f21c7a..4ed46a0784 100644
--- a/log4j-kit/pom.xml
+++ b/log4j-conversant/pom.xml
@@ -24,19 +24,26 @@
     <relativePath>../log4j-parent</relativePath>
   </parent>
 
-  <artifactId>log4j-kit</artifactId>
-  <name>Apache Log4j Kit</name>
-  <description>Helpers to implement Log4j 2.x API.</description>
+  <artifactId>log4j-conversant</artifactId>
+  <name>Apache Log4j Disruptor-based supplements</name>
+  <description>Provides ConversantMedia Disruptor-based data structure implementations for the Apache Log4j.</description>
 
   <properties>
-    <maven.javadoc.skip>false</maven.javadoc.skip>
-
-    <bnd-extra-package-options>
-      <!-- JSpecify is optional at runtime -->
-      org.jspecify.annotations.*;resolution:=optional
-    </bnd-extra-package-options>
+    <conversant.disruptor.version>1.2.21</conversant.disruptor.version>
   </properties>
 
+  <dependencyManagement>
+    <dependencies>
+
+      <dependency>
+        <groupId>com.conversantmedia</groupId>
+        <artifactId>disruptor</artifactId>
+        <version>${conversant.disruptor.version}</version>
+      </dependency>
+
+    </dependencies>
+  </dependencyManagement>
+
   <dependencies>
 
     <dependency>
@@ -46,59 +53,38 @@
     </dependency>
 
     <dependency>
-      <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-api</artifactId>
+      <groupId>com.conversantmedia</groupId>
+      <artifactId>disruptor</artifactId>
     </dependency>
 
     <dependency>
-      <groupId>org.assertj</groupId>
-      <artifactId>assertj-core</artifactId>
-      <scope>test</scope>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
     </dependency>
 
     <dependency>
-      <groupId>org.junit-pioneer</groupId>
-      <artifactId>junit-pioneer</artifactId>
-      <scope>test</scope>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-plugins</artifactId>
     </dependency>
 
     <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-api</artifactId>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
       <scope>test</scope>
     </dependency>
 
     <dependency>
       <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-params</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-      <groupId>org.javassist</groupId>
-      <artifactId>javassist</artifactId>
-      <version>3.30.2-GA</version>
+      <artifactId>junit-jupiter-api</artifactId>
       <scope>test</scope>
     </dependency>
 
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-api-test</artifactId>
+      <artifactId>log4j-core-test</artifactId>
       <scope>test</scope>
     </dependency>
 
   </dependencies>
 
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <argLine>--add-opens java.base/java.lang=ALL-UNNAMED
-            --add-opens java.base/java.util=ALL-UNNAMED</argLine>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
 </project>
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorBlockingQueueFactory.java
similarity index 84%
rename from log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
rename to log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorBlockingQueueFactory.java
index 4bd278b9da..dd8ce2a84c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/DisruptorBlockingQueueFactory.java
+++ b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorBlockingQueueFactory.java
@@ -14,24 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.core.async;
+package org.apache.logging.log4j.conversant;
 
 import com.conversantmedia.util.concurrent.DisruptorBlockingQueue;
 import com.conversantmedia.util.concurrent.SpinPolicy;
 import java.util.concurrent.BlockingQueue;
+import org.apache.logging.log4j.core.async.BlockingQueueFactory;
 import org.apache.logging.log4j.plugins.Configurable;
 import org.apache.logging.log4j.plugins.Plugin;
 import org.apache.logging.log4j.plugins.PluginAttribute;
 import org.apache.logging.log4j.plugins.PluginFactory;
 
 /**
- * Factory for creating instances of {@link DisruptorBlockingQueue}.
+ * A {@link BlockingQueueFactory} based on <a href="https://github.com/conversant/disruptor">Conversant Disruptor BlockingQueue</a>.
  *
- * @since 2.7
+ * @since 3.0.0
  */
 @Configurable(elementType = BlockingQueueFactory.ELEMENT_TYPE, printObject = true)
 @Plugin("DisruptorBlockingQueue")
-public class DisruptorBlockingQueueFactory implements BlockingQueueFactory {
+public final class DisruptorBlockingQueueFactory implements BlockingQueueFactory {
 
     private final SpinPolicy spinPolicy;
 
diff --git a/log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorProperties.java
similarity index 51%
copy from log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java
copy to log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorProperties.java
index 71dd1b2f19..34c6f32146 100644
--- a/log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java
+++ b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorProperties.java
@@ -14,40 +14,58 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.kit.recycler;
+package org.apache.logging.log4j.conversant;
 
+import com.conversantmedia.util.concurrent.SpinPolicy;
+import org.apache.logging.log4j.core.util.Integers;
 import org.apache.logging.log4j.kit.env.Log4jProperty;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.jspecify.annotations.NullMarked;
 import org.jspecify.annotations.Nullable;
 
-/**
- * A set of common configuration options for recyclers
- *
- * @param factory  The name of the recycler factory to use (cf. {@link RecyclerFactoryProvider#getName()}),
- * @param capacity The capacity of the recycler.
- */
 @NullMarked
 @Log4jProperty(name = "recycler")
-public record RecyclerProperties(@Nullable String factory, @Nullable Integer capacity) {
+public record DisruptorProperties(
+        @Nullable Integer capacity, @Log4jProperty(defaultValue = "WAITING") SpinPolicy spinPolicy) {
+
+    private static final int MIN_CAPACITY = 8;
+
     /**
      * The default recycler capacity: {@code max(2C+1, 8)}, {@code C} denoting the number of available processors
      */
     private static final int DEFAULT_CAPACITY =
-            Math.max(2 * Runtime.getRuntime().availableProcessors() + 1, 8);
+            Math.max(2 * Integers.ceilingNextPowerOfTwo(Runtime.getRuntime().availableProcessors()), MIN_CAPACITY);
 
-    public RecyclerProperties {
+    public DisruptorProperties {
         capacity = validateCapacity(capacity);
     }
 
     private static Integer validateCapacity(final @Nullable Integer capacity) {
         if (capacity != null) {
-            if (capacity >= 1) {
-                return capacity;
+            if (capacity < MIN_CAPACITY) {
+                StatusLogger.getLogger()
+                        .warn(
+                                "Invalid DisruptorBlockingQueue capacity {}, using minimum size {}.",
+                                capacity,
+                                MIN_CAPACITY);
+                return MIN_CAPACITY;
             }
-            StatusLogger.getLogger()
-                    .warn("Invalid recycler capacity {}, using default capacity {}.", capacity, DEFAULT_CAPACITY);
+            final int roundedCapacity = Integers.ceilingNextPowerOfTwo(capacity);
+            if (capacity != roundedCapacity) {
+                StatusLogger.getLogger()
+                        .warn(
+                                "Invalid DisruptorBlockingQueue size {}, using rounded size {}.",
+                                capacity,
+                                roundedCapacity);
+            }
+            return roundedCapacity;
         }
         return DEFAULT_CAPACITY;
     }
+
+    @Override
+    public Integer capacity() {
+        assert capacity != null;
+        return capacity;
+    }
 }
diff --git a/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorRecyclerFactoryProvider.java b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorRecyclerFactoryProvider.java
new file mode 100644
index 0000000000..5711ef0b1c
--- /dev/null
+++ b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/DisruptorRecyclerFactoryProvider.java
@@ -0,0 +1,102 @@
+/*
+ * 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.conversant;
+
+import static java.util.Objects.requireNonNull;
+
+import aQute.bnd.annotation.spi.ServiceProvider;
+import com.conversantmedia.util.concurrent.DisruptorBlockingQueue;
+import com.conversantmedia.util.concurrent.SpinPolicy;
+import java.util.Queue;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import org.apache.logging.log4j.kit.env.PropertyEnvironment;
+import org.apache.logging.log4j.kit.recycler.Recycler;
+import org.apache.logging.log4j.kit.recycler.RecyclerFactory;
+import org.apache.logging.log4j.kit.recycler.RecyclerFactoryProvider;
+import org.apache.logging.log4j.kit.recycler.support.AbstractRecycler;
+
+/**
+ * A {@link Recycler} factory provider implementation based on
+ * <a href="https://github.com/conversant/disruptor>Conversant's Disruptor BlockingQueue</a>.
+ *
+ * @since 3.0.0
+ */
+@ServiceProvider(value = RecyclerFactoryProvider.class)
+public final class DisruptorRecyclerFactoryProvider implements RecyclerFactoryProvider {
+
+    @Override
+    public int getOrder() {
+        return 600;
+    }
+
+    @Override
+    public String getName() {
+        return "disruptor";
+    }
+
+    @Override
+    public RecyclerFactory createForEnvironment(final PropertyEnvironment environment) {
+        requireNonNull(environment, "environment");
+        return new DisruptorRecyclerFactory(environment.getProperty(DisruptorProperties.class));
+    }
+
+    private static final class DisruptorRecyclerFactory implements RecyclerFactory {
+
+        private final int capacity;
+        private final SpinPolicy spinPolicy;
+
+        private DisruptorRecyclerFactory(final DisruptorProperties properties) {
+            this.capacity = properties.capacity();
+            this.spinPolicy = properties.spinPolicy();
+        }
+
+        @Override
+        public <V> Recycler<V> create(final Supplier<V> supplier, final Consumer<V> cleaner) {
+            requireNonNull(supplier, "supplier");
+            requireNonNull(cleaner, "cleaner");
+            final DisruptorBlockingQueue<V> queue = new DisruptorBlockingQueue<>(capacity, spinPolicy);
+            return new DisruptorRecycler<>(supplier, cleaner, queue);
+        }
+
+        private static final class DisruptorRecycler<V> extends AbstractRecycler<V> {
+
+            private final Consumer<V> cleaner;
+
+            private final Queue<V> queue;
+
+            private DisruptorRecycler(final Supplier<V> supplier, final Consumer<V> cleaner, final Queue<V> queue) {
+                super(supplier);
+                this.cleaner = cleaner;
+                this.queue = queue;
+            }
+
+            @Override
+            public V acquire() {
+                final V value = queue.poll();
+                return value != null ? value : createInstance();
+            }
+
+            @Override
+            public void release(final V value) {
+                requireNonNull(value, "value");
+                cleaner.accept(value);
+                queue.offer(value);
+            }
+        }
+    }
+}
diff --git a/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/package-info.java b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/package-info.java
new file mode 100644
index 0000000000..50f3f35e2a
--- /dev/null
+++ b/log4j-conversant/src/main/java/org/apache/logging/log4j/conversant/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+@Export
+@Version("3.0.0")
+package org.apache.logging.log4j.conversant;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
diff --git a/log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java b/log4j-conversant/src/test/java/org/apache/logging/log4j/conversant/test/DisruptorBlockingQueueFactoryTest.java
similarity index 87%
copy from log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java
copy to log4j-conversant/src/test/java/org/apache/logging/log4j/conversant/test/DisruptorBlockingQueueFactoryTest.java
index 03e96f05ba..31c0175d9b 100644
--- a/log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java
+++ b/log4j-conversant/src/test/java/org/apache/logging/log4j/conversant/test/DisruptorBlockingQueueFactoryTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.logging.log4j.jctools;
+package org.apache.logging.log4j.conversant.test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -30,14 +30,14 @@ import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.spi.ExtendedLogger;
 import org.junit.jupiter.api.Test;
 
-class JCToolsBlockingQueueFactoryTest {
+class DisruptorBlockingQueueFactoryTest {
 
     private static void exceptionTest(final LoggerContext context) throws InterruptedException {
         final ExtendedLogger logger = context.getLogger(AsyncAppender.class);
         final Exception parent = new IllegalStateException("Test");
         final Throwable child = new LoggingException("This is a test", parent);
         logger.error("This is a test", child);
-        final ListAppender appender = context.getConfiguration().getAppender("List");
+        final ListAppender appender = context.getConfiguration().getAppender("LIST");
         final List<String> messages;
         try {
             messages = appender.getMessages(1, 2, TimeUnit.SECONDS);
@@ -53,7 +53,7 @@ class JCToolsBlockingQueueFactoryTest {
         final ExtendedLogger logger = context.getLogger(AsyncAppender.class);
         logger.error("This is a test");
         logger.warn("Hello world!");
-        final ListAppender appender = context.getConfiguration().getAppender("List");
+        final ListAppender appender = context.getConfiguration().getAppender("LIST");
         final List<String> messages;
         try {
             messages = appender.getMessages(2, 2, TimeUnit.SECONDS);
@@ -62,13 +62,12 @@ class JCToolsBlockingQueueFactoryTest {
         }
         assertNotNull(messages);
         assertEquals(2, messages.size());
-        final String messagePrefix = JCToolsBlockingQueueFactoryTest.class.getName() + " rewriteTest ";
-        assertEquals(messagePrefix + "This is a test", messages.get(0));
-        assertEquals(messagePrefix + "Hello world!", messages.get(1));
+        assertEquals("This is a test", messages.get(0));
+        assertEquals("Hello world!", messages.get(1));
     }
 
     @Test
-    @LoggerContextSource("JCToolsBlockingQueueFactoryTest.xml")
+    @LoggerContextSource("DisruptorBlockingQueueFactoryTest.xml")
     public void testJcToolsBlockingQueue(final LoggerContext context) throws InterruptedException {
         rewriteTest(context);
         exceptionTest(context);
diff --git a/log4j-conversant/src/test/java/org/apache/logging/log4j/conversant/test/DisruptorRecyclerFactoryProviderTest.java b/log4j-conversant/src/test/java/org/apache/logging/log4j/conversant/test/DisruptorRecyclerFactoryProviderTest.java
new file mode 100644
index 0000000000..3d2f605347
--- /dev/null
+++ b/log4j-conversant/src/test/java/org/apache/logging/log4j/conversant/test/DisruptorRecyclerFactoryProviderTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.conversant.test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.ServiceLoader;
+import org.apache.logging.log4j.conversant.DisruptorRecyclerFactoryProvider;
+import org.apache.logging.log4j.kit.recycler.RecyclerFactoryProvider;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
+import org.junit.jupiter.api.Test;
+
+class DisruptorRecyclerFactoryProviderTest {
+
+    @Test
+    void verify_is_the_first() {
+        final List<Class<?>> providerClasses = ServiceLoaderUtil.safeStream(
+                        RecyclerFactoryProvider.class,
+                        ServiceLoader.load(
+                                RecyclerFactoryProvider.class, getClass().getClassLoader()),
+                        StatusLogger.getLogger())
+                .sorted(Comparator.comparing(RecyclerFactoryProvider::getOrder))
+                .<Class<?>>map(RecyclerFactoryProvider::getClass)
+                .toList();
+        assertThat(providerClasses).startsWith(DisruptorRecyclerFactoryProvider.class);
+    }
+}
diff --git a/log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml b/log4j-conversant/src/test/resources/DisruptorBlockingQueueFactoryTest.xml
similarity index 66%
copy from log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml
copy to log4j-conversant/src/test/resources/DisruptorBlockingQueueFactoryTest.xml
index 1b6ff95acb..b1f0ca990a 100644
--- a/log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml
+++ b/log4j-conversant/src/test/resources/DisruptorBlockingQueueFactoryTest.xml
@@ -15,25 +15,23 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<Configuration status="OFF" name="JCToolsBlockingQueueFactoryTest">
-
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd">
   <Appenders>
-    <Console name="STDOUT">
-      <PatternLayout pattern="%m%n"/>
-    </Console>
-    <List name="List">
-      <PatternLayout pattern="%C %M %m"/>
+    <List name="LIST">
+      <PatternLayout pattern="%m"/>
     </List>
-    <Async name="Async" includeLocation="true" error-ref="STDOUT">
-      <AppenderRef ref="List"/>
-      <JCToolsBlockingQueue/>
+    <Async name="ASYNC">
+      <AppenderRef ref="LIST"/>
+      <DisruptorBlockingQueue/>
     </Async>
   </Appenders>
-
   <Loggers>
-    <Root level="debug">
-      <AppenderRef ref="Async"/>
+    <Root level="DEBUG">
+      <AppenderRef ref="ASYNC"/>
     </Root>
   </Loggers>
-
 </Configuration>
diff --git a/log4j-core-test/pom.xml b/log4j-core-test/pom.xml
index ec83eae417..e492bff917 100644
--- a/log4j-core-test/pom.xml
+++ b/log4j-core-test/pom.xml
@@ -108,12 +108,7 @@
       <artifactId>commons-compress</artifactId>
       <optional>true</optional>
     </dependency>
-    <!-- Alternative implementation of BlockingQueue using Conversant Disruptor for AsyncAppender -->
-    <dependency>
-      <groupId>com.conversantmedia</groupId>
-      <artifactId>disruptor</artifactId>
-      <optional>true</optional>
-    </dependency>
+
     <!-- Required for AsyncLoggers -->
     <dependency>
       <groupId>com.lmax</groupId>
diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml
index c007ffc6c3..ecc230b326 100644
--- a/log4j-core/pom.xml
+++ b/log4j-core/pom.xml
@@ -44,11 +44,8 @@
       <!-- Annotations only -->
       org.jspecify.*;resolution:=optional,
       <!-- External optional dependencies -->
-      com.conversantmedia.util.concurrent;resolution:=optional;
-      com.lmax.disruptor.*;resolution:=optional,
       org.apache.commons.compress.*;resolution:=optional,
       org.fusesource.jansi;resolution:=optional,
-      org.jspecify.annotations.*;resolution:=optional,
       <!-- Optional Java modules -->
       <!-- java.management -->
       java.lang.management;resolution:=optional,
@@ -64,8 +61,6 @@
     </bnd-extra-package-options>
     <bnd-extra-module-options>
       <!-- Optional dependencies can not be transitive -->
-      com.conversantmedia.disruptor;transitive=false,
-      com.lmax.disruptor;transitive=false,
       java.management;transitive=false,
       java.sql;transitive=false,
       java.xml;transitive=false,
@@ -77,6 +72,7 @@
   </properties>
 
   <dependencies>
+
     <dependency>
       <groupId>org.jspecify</groupId>
       <artifactId>jspecify</artifactId>
@@ -87,44 +83,45 @@
       <artifactId>org.osgi.framework</artifactId>
       <scope>provided</scope>
     </dependency>
+
     <!-- Naturally, all implementations require the log4j-api JAR -->
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
     </dependency>
+
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-kit</artifactId>
     </dependency>
+
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-plugins</artifactId>
     </dependency>
-    <!-- The dependency on the plugin processor is only required to ensure the processor is built before core. We
-       don't want the dependency to be included by consumers -->
-    <dependency>
-      <groupId>org.apache.logging.log4j</groupId>
-      <artifactId>log4j-plugin-processor</artifactId>
-      <scope>test</scope>
-    </dependency>
+
     <!-- Used for compressing to formats other than zip and gz -->
     <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-compress</artifactId>
       <optional>true</optional>
     </dependency>
-    <!-- Alternative implementation of BlockingQueue using Conversant Disruptor for AsyncAppender -->
-    <dependency>
-      <groupId>com.conversantmedia</groupId>
-      <artifactId>disruptor</artifactId>
-      <optional>true</optional>
-    </dependency>
+
     <!-- Required for console color support in Windows -->
     <dependency>
       <groupId>org.fusesource.jansi</groupId>
       <artifactId>jansi</artifactId>
       <optional>true</optional>
     </dependency>
+
+    <!-- The dependency on the plugin processor is only required to ensure the processor is built before core. We
+   don't want the dependency to be included by consumers -->
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-plugin-processor</artifactId>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
 
 </project>
diff --git a/log4j-jctools/.log4j-plugin-processing-activator b/log4j-jctools/.log4j-plugin-processing-activator
new file mode 100644
index 0000000000..ba133f3696
--- /dev/null
+++ b/log4j-jctools/.log4j-plugin-processing-activator
@@ -0,0 +1 @@
+This file is here to activate the `plugin-processing` Maven profile.
diff --git a/log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java b/log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java
index 03e96f05ba..1fc5ecd15b 100644
--- a/log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java
+++ b/log4j-jctools/src/test/java/org/apache/logging/log4j/jctools/JCToolsBlockingQueueFactoryTest.java
@@ -37,7 +37,7 @@ class JCToolsBlockingQueueFactoryTest {
         final Exception parent = new IllegalStateException("Test");
         final Throwable child = new LoggingException("This is a test", parent);
         logger.error("This is a test", child);
-        final ListAppender appender = context.getConfiguration().getAppender("List");
+        final ListAppender appender = context.getConfiguration().getAppender("LIST");
         final List<String> messages;
         try {
             messages = appender.getMessages(1, 2, TimeUnit.SECONDS);
@@ -53,7 +53,7 @@ class JCToolsBlockingQueueFactoryTest {
         final ExtendedLogger logger = context.getLogger(AsyncAppender.class);
         logger.error("This is a test");
         logger.warn("Hello world!");
-        final ListAppender appender = context.getConfiguration().getAppender("List");
+        final ListAppender appender = context.getConfiguration().getAppender("LIST");
         final List<String> messages;
         try {
             messages = appender.getMessages(2, 2, TimeUnit.SECONDS);
@@ -62,9 +62,8 @@ class JCToolsBlockingQueueFactoryTest {
         }
         assertNotNull(messages);
         assertEquals(2, messages.size());
-        final String messagePrefix = JCToolsBlockingQueueFactoryTest.class.getName() + " rewriteTest ";
-        assertEquals(messagePrefix + "This is a test", messages.get(0));
-        assertEquals(messagePrefix + "Hello world!", messages.get(1));
+        assertEquals("This is a test", messages.get(0));
+        assertEquals("Hello world!", messages.get(1));
     }
 
     @Test
diff --git a/log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml b/log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml
index 1b6ff95acb..46ccb8e60f 100644
--- a/log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml
+++ b/log4j-jctools/src/test/resources/JCToolsBlockingQueueFactoryTest.xml
@@ -15,25 +15,23 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<Configuration status="OFF" name="JCToolsBlockingQueueFactoryTest">
-
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd">
   <Appenders>
-    <Console name="STDOUT">
-      <PatternLayout pattern="%m%n"/>
-    </Console>
-    <List name="List">
-      <PatternLayout pattern="%C %M %m"/>
+    <List name="LIST">
+      <PatternLayout pattern="%m"/>
     </List>
-    <Async name="Async" includeLocation="true" error-ref="STDOUT">
-      <AppenderRef ref="List"/>
+    <Async name="ASYNC">
+      <AppenderRef ref="LIST"/>
       <JCToolsBlockingQueue/>
     </Async>
   </Appenders>
-
   <Loggers>
-    <Root level="debug">
-      <AppenderRef ref="Async"/>
+    <Root level="DEBUG">
+      <AppenderRef ref="ASYNC"/>
     </Root>
   </Loggers>
-
 </Configuration>
diff --git a/log4j-jctools/src/test/resources/META-INF/services/org.apache.logging.log4j.kit.recycler.RecyclerFactoryProvider b/log4j-jctools/src/test/resources/META-INF/services/org.apache.logging.log4j.kit.recycler.RecyclerFactoryProvider
deleted file mode 100644
index 25c8b92149..0000000000
--- a/log4j-jctools/src/test/resources/META-INF/services/org.apache.logging.log4j.kit.recycler.RecyclerFactoryProvider
+++ /dev/null
@@ -1,6 +0,0 @@
-# `META-INF/services/*` files are automatically generated by `bnd-maven-plugin`.
-# We use `bnd:jar` goal, which only places them into the JAR.
-# As a result, tests of the same artifact (running against `target/` contents, not the JAR) don't have them.
-# To mitigate this, we manually create this file here only for tests.
-# `logging-parent` version `10.5.0` will switch from `bnd:jar` to `bnd:bnd-process`, then this hack won't be needed.
-org.apache.logging.log4j.jctools.JCToolsRecyclerFactoryProvider
diff --git a/log4j-kit/pom.xml b/log4j-kit/pom.xml
index c888f21c7a..7833f16922 100644
--- a/log4j-kit/pom.xml
+++ b/log4j-kit/pom.xml
@@ -35,6 +35,7 @@
       <!-- JSpecify is optional at runtime -->
       org.jspecify.annotations.*;resolution:=optional
     </bnd-extra-package-options>
+    <bnd-extra-module-options>org.jspecify;transitive:=false</bnd-extra-module-options>
   </properties>
 
   <dependencies>
diff --git a/log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java b/log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java
index 71dd1b2f19..897c310207 100644
--- a/log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java
+++ b/log4j-kit/src/main/java/org/apache/logging/log4j/kit/recycler/RecyclerProperties.java
@@ -50,4 +50,10 @@ public record RecyclerProperties(@Nullable String factory, @Nullable Integer cap
         }
         return DEFAULT_CAPACITY;
     }
+
+    @Override
+    public Integer capacity() {
+        assert capacity != null;
+        return capacity;
+    }
 }
diff --git a/log4j-parent/pom.xml b/log4j-parent/pom.xml
index 94b5feee54..a32c685846 100644
--- a/log4j-parent/pom.xml
+++ b/log4j-parent/pom.xml
@@ -103,7 +103,6 @@
     <commons-io.version>2.16.1</commons-io.version>
     <commons-lang3.version>3.17.0</commons-lang3.version>
     <commons-logging.version>1.3.4</commons-logging.version>
-    <conversant.disruptor.version>1.2.21</conversant.disruptor.version>
     <disruptor.version>4.0.0</disruptor.version>
     <elasticsearch.version>7.17.23</elasticsearch.version>
     <embedded-ldap.version>0.9.0</embedded-ldap.version>
@@ -342,12 +341,6 @@
         <version>${flapdoodle-reverse.version}</version>
       </dependency>
 
-      <dependency>
-        <groupId>com.conversantmedia</groupId>
-        <artifactId>disruptor</artifactId>
-        <version>${conversant.disruptor.version}</version>
-      </dependency>
-
       <dependency>
         <groupId>com.lmax</groupId>
         <artifactId>disruptor</artifactId>
diff --git a/log4j-perf-test/pom.xml b/log4j-perf-test/pom.xml
index 1be3e92ca3..fe3e6f8331 100644
--- a/log4j-perf-test/pom.xml
+++ b/log4j-perf-test/pom.xml
@@ -53,6 +53,10 @@
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-async-logger</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-conversant</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-core</artifactId>
@@ -77,14 +81,6 @@
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-plugins</artifactId>
     </dependency>
-    <dependency>
-      <groupId>com.conversantmedia</groupId>
-      <artifactId>disruptor</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.lmax</groupId>
-      <artifactId>disruptor</artifactId>
-    </dependency>
     <dependency>
       <groupId>com.h2database</groupId>
       <artifactId>h2</artifactId>
diff --git a/pom.xml b/pom.xml
index 1931478e9f..a2c2ffaf06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -236,6 +236,7 @@
     <module>log4j-config-jackson</module>
     <module>log4j-config-properties</module>
     <module>log4j-config-yaml</module>
+    <module>log4j-conversant</module>
     <module>log4j-core</module>
     <module>log4j-core-test</module>
     <module>log4j-csv</module>
@@ -406,6 +407,12 @@
         <version>${project.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-conversant</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
       <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-core</artifactId>


(logging-log4j2) 02/02: Document `DisruptorBlockingQueue` move

Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch feature/main/move-conversant
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 58bf2c842d38f3e9a9ea6ab10a2b263765fccb29
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Sun Sep 1 22:48:13 2024 +0200

    Document `DisruptorBlockingQueue` move
---
 src/site/antora/modules/ROOT/pages/components.adoc | 17 +++++++++
 .../ROOT/pages/manual/appenders/delegating.adoc    | 25 ++-----------
 .../modules/ROOT/pages/plugin-reference.adoc       |  2 +-
 .../ROOT/partials/components/log4j-conversant.adoc | 41 ++++++++++++++++++++++
 .../ROOT/partials/features/queue-conversant.adoc   | 21 +++++++++++
 5 files changed, 82 insertions(+), 24 deletions(-)

diff --git a/src/site/antora/modules/ROOT/pages/components.adoc b/src/site/antora/modules/ROOT/pages/components.adoc
index b354b6b91f..54bfcc0cda 100644
--- a/src/site/antora/modules/ROOT/pages/components.adoc
+++ b/src/site/antora/modules/ROOT/pages/components.adoc
@@ -103,6 +103,23 @@ See xref:manual/configuration.adoc#configuration-factories[predefined `Configura
 
 include::partial$components/log4j-config-yaml.adoc[]
 
+[#log4j-conversant]
+== `log4j-conversant`
+
+|===
+| JPMS module
+| `org.apache.logging.log4j.conversant`
+|===
+
+The `log4j-conversant` artifact contains a
+xref:manual/appenders/delegating.adoc#BlockingQueueFactory[blocking queue factory]
+that uses
+https://github.com/conversant/disruptor[Conversant Disruptor BlockingQueue].
+
+See xref:manual/appenders/delegating.adoc#DisruptorBlockingQueueFactory[Disruptor Blocking Queue] for more details.
+
+include::partial$components/log4j-conversant.adoc[]
+
 [#log4j-core]
 == `log4j-core`
 
diff --git a/src/site/antora/modules/ROOT/pages/manual/appenders/delegating.adoc b/src/site/antora/modules/ROOT/pages/manual/appenders/delegating.adoc
index a717e5c6ce..d2375bc628 100644
--- a/src/site/antora/modules/ROOT/pages/manual/appenders/delegating.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/appenders/delegating.adoc
@@ -265,31 +265,10 @@ The `SpinPolicy` to apply, when adding elements to the queue.
 .Additional dependencies are required to use `DisruptorBlockingQueue`
 [%collapsible]
 =====
-[tabs]
-====
-Maven::
-+
-[source,xml,subs="+attributes"]
-----
-<dependency>
-  <groupId>com.conversantmedia</groupId>
-  <artifactId>disruptor</artifactId>
-  <version>{conversant-version}</version>
-  <scope>runtime</scope>
-</dependency>
-----
-
-Gradle::
-+
-[source,groovy,subs="+attributes"]
-----
-runtimeOnly 'com.conversantmedia:disruptor:{conversant-version}'
-----
-
-====
+include::partial$features/queue-conversant.adoc[]
 =====
 +
-xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-async-DisruptorBlockingQueueFactory[{plugin-reference-marker} Plugin reference for `DisruptorBlockingQueue`]
+xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-conversant_org-apache-logging-log4j-conversant-DisruptorBlockingQueueFactory[{plugin-reference-marker} Plugin reference for `DisruptorBlockingQueue`]
 
 [#JCToolsBlockingQueueFactory]
 `JCToolsBlockingQueue`::
diff --git a/src/site/antora/modules/ROOT/pages/plugin-reference.adoc b/src/site/antora/modules/ROOT/pages/plugin-reference.adoc
index ebcc9b60ba..d049529bc3 100644
--- a/src/site/antora/modules/ROOT/pages/plugin-reference.adoc
+++ b/src/site/antora/modules/ROOT/pages/plugin-reference.adoc
@@ -269,7 +269,7 @@ The purpose of the sections below is to remove IDE errors while editing configur
 == AsyncWaitStrategyFactory
 [#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-async-BlockingQueueFactory]
 == `BlockingQueueFactory`
-[#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-async-DisruptorBlockingQueueFactory]
+[#org-apache-logging-log4j_log4j-conversant_org-apache-logging-log4j-conversant-DisruptorBlockingQueueFactory]
 == DisruptorBlockingQueue
 [#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-async-JCToolsBlockingQueueFactory]
 == JCToolsBlockingQueue
diff --git a/src/site/antora/modules/ROOT/partials/components/log4j-conversant.adoc b/src/site/antora/modules/ROOT/partials/components/log4j-conversant.adoc
new file mode 100644
index 0000000000..ba783ef06a
--- /dev/null
+++ b/src/site/antora/modules/ROOT/partials/components/log4j-conversant.adoc
@@ -0,0 +1,41 @@
+////
+    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.
+////
+
+[tabs]
+====
+Maven::
++
+We assume you use xref:components.adoc#log4j-bom[`log4j-bom`] for dependency management.
++
+[source,xml]
+----
+<dependency>
+  <groupId>org.apache.logging.log4j</groupId>
+  <artifactId>log4j-conversant</artifactId>
+  <scope>runtime</scope>
+</dependency>
+----
+
+Gradle::
++
+We assume you use xref:components.adoc#log4j-bom[`log4j-bom`] for dependency management.
++
+[source,groovy]
+----
+runtimeOnly 'org.apache.logging.log4j:log4j-conversant'
+----
+====
\ No newline at end of file
diff --git a/src/site/antora/modules/ROOT/partials/features/queue-conversant.adoc b/src/site/antora/modules/ROOT/partials/features/queue-conversant.adoc
new file mode 100644
index 0000000000..2d8b17c405
--- /dev/null
+++ b/src/site/antora/modules/ROOT/partials/features/queue-conversant.adoc
@@ -0,0 +1,21 @@
+////
+    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.
+////
+
+// This file exists in both the 2.x and 3.x branches.
+// It contains the dependencies required to enable the blocking queue based on JCTools.
+
+include::partial$components/log4j-conversant.adoc[]
\ No newline at end of file