Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions log4j-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<artifactId>org.osgi.resource</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jctools</groupId>
<artifactId>jctools-core</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
Expand All @@ -52,10 +57,6 @@
<configuration>
<instructions>
<Export-Package>org.apache.logging.log4j.*</Export-Package>
<Import-Package>
sun.reflect;resolution:=optional,
*
</Import-Package>
<Bundle-Activator>org.apache.logging.log4j.util.Activator</Bundle-Activator>
<_fixupmessages>"Classes found in the wrong directory";is:=warning</_fixupmessages>
</instructions>
Expand Down
4 changes: 4 additions & 0 deletions log4j-api/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@
exports org.apache.logging.log4j.status;
exports org.apache.logging.log4j.util;

// optional support for formatting SQL date/time classes in messages properly
requires static java.sql;
// optional support for running in an OSGi environment
requires static org.osgi.framework;
// optional support for using JCTools in a Recycler
requires static org.jctools.core;
uses org.apache.logging.log4j.spi.Provider;
uses PropertySource;
uses org.apache.logging.log4j.message.ThreadDumpMessage.ThreadInfoFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import java.util.function.Supplier;

/**
* Recycler strategy which doesn't recycle anything; all instances are freshly created.
*
* @param <V> the recyclable type
*/
public class DummyRecycler<V> implements Recycler<V> {

private final Supplier<V> supplier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import java.util.function.Consumer;
import java.util.function.Supplier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import java.util.Queue;
import java.util.function.Consumer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import java.util.Queue;
import java.util.function.Consumer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,30 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

/**
* Strategy for recycling objects. This is primarily useful for heavyweight objects and buffers.
*
* @param <V> the recyclable type
* @since 3.0.0
*/
public interface Recycler<V> {

/**
* Acquires an instance of V. This may either be a fresh instance of V or a recycled instance of V.
* Recycled instances will be modified by their cleanup function before being returned.
*
* @return an instance of V to be used
*/
V acquire();

/**
* Releases an instance of V. This allows the instance to be recycled and later reacquired for new
* purposes.
*
* @param value an instance of V no longer being used
*/
void release(V value);

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import org.jctools.queues.MpmcArrayQueue;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
Expand All @@ -25,30 +27,46 @@
import java.util.concurrent.ArrayBlockingQueue;
import java.util.function.Supplier;

import org.apache.logging.log4j.util.LoaderUtil;
import org.jctools.queues.MpmcArrayQueue;

import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled;

public final class RecyclerFactories {

private RecyclerFactories() {}

private static final String JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH =
"org.jctools.queues.MpmcArrayQueue.new";
private static final String JCTOOLS_FACTORY_CLASS_NAME =
RecyclerFactories.class.getName() + "$MpmcArrayQueueFactory";

private interface QueueFactory {
<V> Queue<V> create(final int capacity);
}

private static class ArrayBlockingQueueFactory implements QueueFactory {
@Override
public <V> Queue<V> create(final int capacity) {
return new ArrayBlockingQueue<>(capacity);
}
}

private static final boolean JCTOOLS_QUEUE_CLASS_AVAILABLE =
isJctoolsQueueClassAvailable();
@SuppressWarnings("unused") // loaded via reflection to check for presence of JCTools
private static class MpmcArrayQueueFactory implements QueueFactory {
@Override
public <V> Queue<V> create(final int capacity) {
return new MpmcArrayQueue<>(capacity);
}
}

private static boolean isJctoolsQueueClassAvailable() {
private static <V> Supplier<Queue<V>> getQueueSupplier(final int capacity) {
final ClassLoader classLoader = RecyclerFactories.class.getClassLoader();
Class<? extends QueueFactory> factoryClass;
try {
final String className = JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH
.replaceAll("\\.new$", "");
LoaderUtil.loadClass(className);
return true;
} catch (final ClassNotFoundException ignored) {
return false;
// try to load RecyclerFactories.MpmcArrayQueueFactory; a linkage error should occur if JCTools is unavailable
factoryClass = classLoader.loadClass(JCTOOLS_FACTORY_CLASS_NAME)
.asSubclass(QueueFactory.class);
} catch (final ClassNotFoundException | LinkageError ignored) {
factoryClass = ArrayBlockingQueueFactory.class;
}
final QueueFactory queueFactory = ReflectionUtil.instantiate(factoryClass);
return () -> queueFactory.create(capacity);
}

public static RecyclerFactory ofSpec(final String recyclerFactorySpec) {
Expand All @@ -63,11 +81,7 @@ public static RecyclerFactory ofSpec(final String recyclerFactorySpec) {
if (isThreadLocalsEnabled()) {
return ThreadLocalRecyclerFactory.getInstance();
} else {
final Supplier<Queue<Object>> queueSupplier =
JCTOOLS_QUEUE_CLASS_AVAILABLE
? () -> new MpmcArrayQueue<>(defaultCapacity)
: () -> new ArrayBlockingQueue<>(defaultCapacity);
return new QueueingRecyclerFactory(queueSupplier);
return new QueueingRecyclerFactory(getQueueSupplier(defaultCapacity));
}
}

Expand Down Expand Up @@ -113,9 +127,7 @@ private static RecyclerFactory readQueueingRecyclerFactory(
final StringParameterParser.Value supplierValue = parsedValues.get("supplier");
final String supplierPath;
if (supplierValue == null || supplierValue instanceof StringParameterParser.NullValue) {
supplierPath = JCTOOLS_QUEUE_CLASS_AVAILABLE
? JCTOOLS_QUEUE_CLASS_SUPPLIER_PATH
: "java.util.concurrent.ArrayBlockingQueue.new";
supplierPath = null;
} else {
supplierPath = supplierValue.toString();
}
Expand All @@ -136,6 +148,9 @@ private static RecyclerFactory readQueueingRecyclerFactory(
}

// Execute the read spec.
if (supplierPath == null) {
return new QueueingRecyclerFactory(getQueueSupplier(capacity));
}
return createRecyclerFactory(queueFactorySpec, supplierPath, capacity);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.util;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
* Factory for {@link Recycler} strategies. Depending on workloads, different instance recycling strategies may be
* most performant. For example, traditional multithreaded workloads may benefit from using thread-local instance
* recycling while different models of concurrency or versions of the JVM may benefit from using an object pooling
* strategy instead.
*
* @since 3.0.0
*/
@FunctionalInterface
public interface RecyclerFactory {

/**
* Creates a new recycler using the given supplier function for initial instances. These instances have
* no cleaner function and are assumed to always be reusable.
*
* @param supplier function to provide new instances of a recyclable object
* @param <V> the recyclable type
* @return a new recycler for V-type instances
*/
default <V> Recycler<V> create(final Supplier<V> supplier) {
return create(supplier, ignored -> {});
}

/**
* Creates a new recycler using the given functions for providing fresh instances and for cleaning up
* existing instances for reuse. For example, a StringBuilder recycler would provide two functions:
* a supplier function for constructing a new StringBuilder with a preselected initial capacity and
* another function for trimming the StringBuilder to some preselected maximum capacity and setting
* its length back to 0 as if it were a fresh StringBuilder.
*
* @param supplier function to provide new instances of a recyclable object
* @param cleaner function to reset a recyclable object to a fresh state
* @param <V> the recyclable type
* @return a new recycler for V-type instances
*/
<V> Recycler<V> create(Supplier<V> supplier, Consumer<V> cleaner);

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;

import org.apache.logging.log4j.util.Strings;
package org.apache.logging.log4j.util;

import java.util.Collections;
import java.util.LinkedHashMap;
Expand All @@ -25,6 +23,8 @@
import java.util.Set;
import java.util.concurrent.Callable;

import org.apache.logging.log4j.util.Strings;

public final class StringParameterParser {

private StringParameterParser() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
* Recycling strategy that caches instances in a ThreadLocal value to allow threads to reuse objects. This strategy
* may not be appropriate in workloads where units of work are independent of operating system threads such as
* reactive streams, coroutines, or virtual threads.
*
* @param <V> the recyclable type
*/
public class ThreadLocalRecycler<V> implements Recycler<V> {

private final Consumer<V> cleaner;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.layout.template.json.util;
package org.apache.logging.log4j.util;

import java.util.function.Consumer;
import java.util.function.Supplier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,23 @@
*/
package org.apache.logging.log4j.layout.template.json;

import co.elastic.logging.log4j2.EcsLayout;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.http.HttpHost;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
Expand All @@ -28,9 +44,9 @@
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.apache.logging.log4j.util.ThreadLocalRecyclerFactory;
import org.assertj.core.api.Assertions;
import org.awaitility.Awaitility;
import org.elasticsearch.ElasticsearchStatusException;
Expand All @@ -52,22 +68,7 @@
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import co.elastic.logging.log4j2.EcsLayout;

@Execution(ExecutionMode.SAME_THREAD)
class LogstashIT {
Expand Down
Loading