findUrlResources(final String resource, boolean useTccl) {
// @formatter:off
final ClassLoader[] candidates = {
- getThreadContextClassLoader(),
+ useTccl ? getThreadContextClassLoader() : null,
isForceTccl() ? null : LoaderUtil.class.getClassLoader(),
isForceTccl() || GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()};
// @formatter:on
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index 643e52b7348..9aaedf41007 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -29,6 +29,8 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
+import org.apache.logging.log4j.spi.LoggingSystem;
+
/**
* Consider this class private.
*
@@ -87,15 +89,13 @@ private PropertiesUtil(final String propertiesFileName, final boolean useTccl) {
* Returns the PropertiesUtil used by Log4j.
*
* @return the main Log4j PropertiesUtil instance.
+ * @deprecated use {@link LoggingSystem#getPropertyResolver()}
*/
+ @Deprecated
public static PropertiesUtil getProperties() {
return COMPONENT_PROPERTIES.value();
}
- public static PropertyEnvironment getProperties(final String namespace) {
- return new Environment(new PropertyFilePropertySource(String.format("log4j2.%s.properties", namespace)));
- }
-
public static ResourceBundle getCharsetsResourceBundle() {
return ResourceBundle.getBundle("Log4j-charsets");
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyResolver.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyResolver.java
new file mode 100644
index 00000000000..8a0226d9f02
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyResolver.java
@@ -0,0 +1,81 @@
+/*
+ * 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.List;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+
+public interface PropertyResolver {
+
+ String DEFAULT_CONTEXT = PropertySource.DEFAULT_CONTEXT;
+
+ void addSource(final PropertySource source);
+
+ default boolean hasProperty(final String key) {
+ return hasProperty(DEFAULT_CONTEXT, key);
+ }
+
+ boolean hasProperty(final String context, final String key);
+
+ default Optional getString(final String key) {
+ return getString(DEFAULT_CONTEXT, key);
+ }
+
+ Optional getString(final String context, final String key);
+
+ default List getList(final String key) {
+ return getList(DEFAULT_CONTEXT, key);
+ }
+
+ List getList(final String context, final String key);
+
+ default boolean getBoolean(final String key) {
+ return getBoolean(DEFAULT_CONTEXT, key);
+ }
+
+ default boolean getBoolean(final String context, final String key) {
+ return getBoolean(context, key, false);
+ }
+
+ default boolean getBoolean(final String key, final boolean defaultValue) {
+ return getBoolean(DEFAULT_CONTEXT, key, defaultValue);
+ }
+
+ boolean getBoolean(final String context, final String key, final boolean defaultValue);
+
+ default boolean getBoolean(final String key,
+ final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent) {
+ return getBoolean(DEFAULT_CONTEXT, key, defaultValueIfAbsent, defaultValueIfPresent);
+ }
+
+ boolean getBoolean(final String context, final String key,
+ final boolean defaultValueIfAbsent, final boolean defaultValueIfPresent);
+
+ default OptionalInt getInt(final String key) {
+ return getInt(DEFAULT_CONTEXT, key);
+ }
+
+ OptionalInt getInt(final String context, final String key);
+
+ default OptionalLong getLong(final String key) {
+ return getLong(DEFAULT_CONTEXT, key);
+ }
+
+ OptionalLong getLong(final String context, final String key);
+}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
index 4a3e29f0741..f3de116641f 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertySource.java
@@ -24,16 +24,25 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
- * A source for global configuration properties.
+ * A source for global and LoggerContext configuration properties.
*
* @since 2.10.0
*/
public interface PropertySource {
+ /**
+ * Constant value for the name used to represent the default context for providing default settings for
+ * LoggerContext properties along with default values for global properties.
+ *
+ * @since 3.0.0
+ */
+ String DEFAULT_CONTEXT = "*";
/**
* Returns the order in which this PropertySource has priority. A higher value means that the source will be
@@ -48,14 +57,16 @@ public interface PropertySource {
*
* @param action action to perform on each key/value pair
*/
+ @Deprecated(since = "3.0.0")
default void forEach(final BiConsumer action) {
}
/**
* Returns the list of all property names.
- *
+ *
* @return list of property names
*/
+ @Deprecated(since = "3.0.0")
default Collection getPropertyNames() {
return Collections.emptySet();
}
@@ -67,6 +78,7 @@ default Collection getPropertyNames() {
* @param tokens list of property name tokens
* @return a normalized property name using the given tokens
*/
+ @Deprecated(since = "3.0.0")
default CharSequence getNormalForm(final Iterable extends CharSequence> tokens) {
return null;
}
@@ -81,6 +93,43 @@ default String getProperty(final String key) {
return null;
}
+ default String getProperty(final String context, final String key) {
+ final String compositeKey = isDefaultContext(context) ? key : compositeKey(context, key);
+ return getProperty(compositeKey);
+ }
+
+ default List getList(final String context, final String key) {
+ final String value = getProperty(context, key);
+ return List.of(Strings.splitList(value));
+ }
+
+ default BooleanProperty getBoolean(final String context, final String key) {
+ return BooleanProperty.parse(getProperty(context, key));
+ }
+
+ default OptionalInt getInt(final String context, final String key) {
+ final String value = getProperty(context, key);
+ if (value != null) {
+ try {
+ final int i = Integer.parseInt(value);
+ return OptionalInt.of(i);
+ } catch (final NumberFormatException ignored) {
+ }
+ }
+ return OptionalInt.empty();
+ }
+
+ default OptionalLong getLong(final String context, final String key) {
+ final String value = getProperty(context, key);
+ if (value != null) {
+ try {
+ final long i = Long.parseLong(value);
+ return OptionalLong.of(i);
+ } catch (final NumberFormatException ignored) {
+ }
+ }
+ return OptionalLong.empty();
+ }
/**
* For PropertySources that cannot iterate over all the potential properties this provides a direct lookup.
@@ -92,6 +141,24 @@ default boolean containsProperty(final String key) {
return false;
}
+ default boolean containsProperty(final String context, final String key) {
+ return isDefaultContext(context) ?
+ containsProperty(key) :
+ containsProperty(compositeKey(context, key));
+ }
+
+ private static boolean isDefaultContext(final String context) {
+ return context == null || context.equals(DEFAULT_CONTEXT);
+ }
+
+ private static String compositeKey(final String context, final String key) {
+ final int i = key.indexOf('*');
+ if (i == -1 || i + 1 == key.length()) {
+ return "log4j2." + context + '.' + key;
+ }
+ return key.substring(0, i) + context + key.substring(i + 1);
+ }
+
/**
* Comparator for ordering PropertySource instances by priority.
*
@@ -107,10 +174,9 @@ public int compare(final PropertySource o1, final PropertySource o2) {
}
/**
- * Utility methods useful for PropertySource implementations.
- *
- * @since 2.10.0
+ * @deprecated no longer needed by PropertySource
*/
+ @Deprecated(since = "3.0.0")
final class Util {
private static final Pattern PREFIX_PATTERN = Pattern.compile(
// just lookahead for AsyncLogger
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecycler.java
similarity index 89%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecycler.java
index b83ae2f3033..5f1bbc6b44f 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecycler.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecycler.java
@@ -14,12 +14,17 @@
* 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;
import java.util.function.Supplier;
+/**
+ * Recycling strategy that uses an internal queue to maintain a maximum number of unused recyclable instances.
+ *
+ * @param the recycling type
+ */
public class QueueingRecycler implements Recycler {
private final Supplier supplier;
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecyclerFactory.java
similarity index 89%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecyclerFactory.java
index 85b04ab7e3c..3967cad179b 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/QueueingRecyclerFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/QueueingRecyclerFactory.java
@@ -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;
@@ -32,8 +32,7 @@ public QueueingRecyclerFactory(final Supplier> queueSupplier) {
public Recycler create(
final Supplier supplier,
final Consumer cleaner) {
- @SuppressWarnings("unchecked")
- final Queue queue = (Queue) queueSupplier.get();
+ final Queue queue = Cast.cast(queueSupplier.get());
return new QueueingRecycler<>(supplier, cleaner, queue);
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Recycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Recycler.java
new file mode 100644
index 00000000000..1a41b03827d
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Recycler.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * Strategy for recycling objects. This is primarily useful for heavyweight objects and buffers.
+ *
+ * @param the recyclable type
+ * @since 3.0.0
+ */
+public interface Recycler {
+
+ /**
+ * 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);
+
+}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactories.java
similarity index 77%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactories.java
index 2b4d236758f..65a5ed403a0 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/RecyclerFactories.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactories.java
@@ -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.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -25,7 +25,8 @@
import java.util.concurrent.ArrayBlockingQueue;
import java.util.function.Supplier;
-import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.spi.InstanceFactory;
+import org.apache.logging.log4j.spi.LoggingSystem;
import org.jctools.queues.MpmcArrayQueue;
import static org.apache.logging.log4j.util.Constants.isThreadLocalsEnabled;
@@ -34,21 +35,46 @@ 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 static final boolean JCTOOLS_QUEUE_CLASS_AVAILABLE =
- isJctoolsQueueClassAvailable();
+ private interface QueueFactory {
+ Queue create(final int capacity);
+ }
+
+ private static class ArrayBlockingQueueFactory implements QueueFactory {
+ @Override
+ public Queue create(final int capacity) {
+ return new ArrayBlockingQueue<>(capacity);
+ }
+ }
+
+ @SuppressWarnings("unused") // loaded via reflection to check for presence of JCTools
+ private static class MpmcArrayQueueFactory implements QueueFactory {
+ @Override
+ public Queue create(final int capacity) {
+ return new MpmcArrayQueue<>(capacity);
+ }
+ }
+
+ private static Supplier> getQueueSupplier(final int capacity) {
- private static boolean isJctoolsQueueClassAvailable() {
+ 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 LoggingSystem system = LoggingSystem.getInstance();
+ final InstanceFactory instanceFactory = system.getInstanceFactory();
+ final QueueFactory queueFactory = instanceFactory.getInstance(factoryClass);
+
+ return () -> queueFactory.create(capacity);
+
}
public static RecyclerFactory ofSpec(final String recyclerFactorySpec) {
@@ -63,11 +89,7 @@ public static RecyclerFactory ofSpec(final String recyclerFactorySpec) {
if (isThreadLocalsEnabled()) {
return ThreadLocalRecyclerFactory.getInstance();
} else {
- final Supplier> queueSupplier =
- JCTOOLS_QUEUE_CLASS_AVAILABLE
- ? () -> new MpmcArrayQueue<>(defaultCapacity)
- : () -> new ArrayBlockingQueue<>(defaultCapacity);
- return new QueueingRecyclerFactory(queueSupplier);
+ return new QueueingRecyclerFactory(getQueueSupplier(defaultCapacity));
}
}
@@ -113,9 +135,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();
}
@@ -136,6 +156,9 @@ private static RecyclerFactory readQueueingRecyclerFactory(
}
// Execute the read spec.
+ if (supplierPath == null) {
+ return new QueueingRecyclerFactory(getQueueSupplier(capacity));
+ }
return createRecyclerFactory(queueFactorySpec, supplierPath, capacity);
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactory.java
new file mode 100644
index 00000000000..eab78a702d3
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/RecyclerFactory.java
@@ -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 the recyclable type
+ * @return a new recycler for V-type instances
+ */
+ default Recycler create(final Supplier 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 the recyclable type
+ * @return a new recycler for V-type instances
+ */
+ Recycler create(Supplier supplier, Consumer cleaner);
+
+}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java
index fe549822c95..5f092e3d6c6 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java
@@ -27,13 +27,9 @@
*/
@InternalApi
public final class StackLocatorUtil {
- private static StackLocator stackLocator = null;
+ private static final StackLocator stackLocator = StackLocator.getInstance();
private static volatile boolean errorLogged;
- static {
- stackLocator = StackLocator.getInstance();
- }
-
private StackLocatorUtil() {
}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
similarity index 99%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
index c2333a588eb..653877c1f49 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/StringParameterParser.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringParameterParser.java
@@ -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;
@@ -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() {}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
index b3d1c3ccdfd..6f0e5a31b0c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
@@ -16,6 +16,8 @@
*/
package org.apache.logging.log4j.util;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.Objects;
import java.util.Properties;
@@ -32,18 +34,33 @@ public class SystemPropertiesPropertySource implements PropertySource {
private static final int DEFAULT_PRIORITY = 0;
private static final String PREFIX = "log4j2.";
+ private static final PrivilegedAction GET_SYSTEM_PROPERTIES = System::getProperties;
+
+ private static PrivilegedAction getSystemPropertyAction(final String key) {
+ return () -> System.getProperty(key);
+ }
+
+ private static PrivilegedAction getSystemPropertyAction(final String key, final String defaultKey) {
+ return () -> System.getProperty(key, defaultKey);
+ }
+
/**
* Used by bootstrap code to get system properties without loading PropertiesUtil.
*/
public static String getSystemProperty(final String key, final String defaultValue) {
try {
- return System.getProperty(key, defaultValue);
- } catch (SecurityException e) {
+ return System.getSecurityManager() == null ?
+ System.getProperty(key, defaultValue) :
+ AccessController.doPrivileged(getSystemPropertyAction(key, defaultValue));
+ } catch (SecurityException ignored) {
// Silently ignore the exception
return defaultValue;
}
}
+ private final SystemProperties systemProperties = new DefaultSystemProperties();
+ private final SystemProperties securedProperties = new AccessControlledSystemProperties();
+
@Override
public int getPriority() {
return DEFAULT_PRIORITY;
@@ -51,17 +68,7 @@ public int getPriority() {
@Override
public void forEach(final BiConsumer action) {
- final Properties properties;
- try {
- properties = System.getProperties();
- } catch (final SecurityException e) {
- // (1) There is no status logger.
- // (2) LowLevelLogUtil also consults system properties ("line.separator") to
- // open a BufferedWriter, so this may fail as well. Just having a hard reference
- // in this code to LowLevelLogUtil would cause a problem.
- // (3) We could log to System.err (nah) or just be quiet as we do now.
- return;
- }
+ final Properties properties = getSystemProperties().getProperties();
// Lock properties only long enough to get a thread-safe SAFE snapshot of its
// current keys, an array.
final Object[] keySet;
@@ -83,20 +90,12 @@ public CharSequence getNormalForm(final Iterable extends CharSequence> tokens)
@Override
public Collection getPropertyNames() {
- try {
- return System.getProperties().stringPropertyNames();
- } catch (final SecurityException e) {
- return PropertySource.super.getPropertyNames();
- }
+ return getSystemProperties().getProperties().stringPropertyNames();
}
@Override
public String getProperty(String key) {
- try {
- return System.getProperty(key);
- } catch (final SecurityException e) {
- return PropertySource.super.getProperty(key);
- }
+ return getSystemProperties().getProperty(key);
}
@Override
@@ -104,4 +103,79 @@ public boolean containsProperty(String key) {
return getProperty(key) != null;
}
+ private SystemProperties getSystemProperties() {
+ return System.getSecurityManager() == null ? systemProperties : securedProperties;
+ }
+
+ private interface SystemProperties {
+ Properties getProperties();
+
+ String getProperty(String key);
+
+ String getProperty(String key, String defaultValue);
+ }
+
+ private static class DefaultSystemProperties implements SystemProperties {
+ @Override
+ public Properties getProperties() {
+ try {
+ return System.getProperties();
+ } catch (final SecurityException ignored) {
+ return new Properties();
+ }
+ }
+
+ @Override
+ public String getProperty(final String key) {
+ try {
+ return System.getProperty(key);
+ } catch (final SecurityException ignored) {
+ return null;
+ }
+ }
+
+ @Override
+ public String getProperty(final String key, final String defaultValue) {
+ try {
+ return System.getProperty(key, defaultValue);
+ } catch (final SecurityException ignored) {
+ return defaultValue;
+ }
+ }
+ }
+
+ private static class AccessControlledSystemProperties implements SystemProperties {
+ @Override
+ public Properties getProperties() {
+ try {
+ return AccessController.doPrivileged(GET_SYSTEM_PROPERTIES);
+ } catch (final SecurityException ignored) {
+ // (1) There is no status logger.
+ // (2) LowLevelLogUtil also consults system properties ("line.separator") to
+ // open a BufferedWriter, so this may fail as well. Just having a hard reference
+ // in this code to LowLevelLogUtil would cause a problem.
+ // (3) We could log to System.err (nah) or just be quiet as we do now.
+ return new Properties();
+ }
+ }
+
+ @Override
+ public String getProperty(final String key) {
+ try {
+ return AccessController.doPrivileged(getSystemPropertyAction(key));
+ } catch (final SecurityException ignored) {
+ return null;
+ }
+ }
+
+ @Override
+ public String getProperty(final String key, final String defaultValue) {
+ try {
+ return AccessController.doPrivileged(getSystemPropertyAction(key, defaultValue));
+ } catch (final SecurityException ignored) {
+ return defaultValue;
+ }
+ }
+ }
+
}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecycler.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecycler.java
new file mode 100644
index 00000000000..5401891b56a
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecycler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.concurrent.atomic.AtomicInteger;
+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 the recyclable type
+ */
+public class ThreadLocalRecycler implements Recycler {
+
+ private final Supplier supplier;
+ private final Consumer cleaner;
+
+ private final ThreadLocal holder;
+ private final boolean referenceCountingEnabled;
+ private final ThreadLocal activeReferenceCount = ThreadLocal.withInitial(AtomicInteger::new);
+
+ public ThreadLocalRecycler(
+ final Supplier supplier,
+ final Consumer cleaner) {
+ this(supplier, cleaner, false);
+ }
+
+ public ThreadLocalRecycler(
+ final Supplier supplier,
+ final Consumer cleaner,
+ final boolean referenceCountingEnabled) {
+ this.supplier = supplier;
+ this.cleaner = cleaner;
+ this.holder = ThreadLocal.withInitial(supplier);
+ this.referenceCountingEnabled = referenceCountingEnabled;
+ }
+
+ @Override
+ public V acquire() {
+ final V value;
+ if (referenceCountingEnabled) {
+ final AtomicInteger count = activeReferenceCount.get();
+ if (count.compareAndSet(0, 1)) {
+ value = holder.get();
+ } else {
+ count.incrementAndGet();
+ value = supplier.get();
+ }
+ } else {
+ value = holder.get();
+ }
+ cleaner.accept(value);
+ return value;
+ }
+
+ @Override
+ public void release(final V value) {
+ if (referenceCountingEnabled) {
+ activeReferenceCount.get().decrementAndGet();
+ }
+ }
+
+ // Visible for testing
+ int getActiveReferenceCount() {
+ return activeReferenceCount.get().get();
+ }
+
+}
diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecyclerFactory.java
similarity index 95%
rename from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java
rename to log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecyclerFactory.java
index 048262cf4e0..c877b4d24b7 100644
--- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/util/ThreadLocalRecyclerFactory.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ThreadLocalRecyclerFactory.java
@@ -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;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java
index 3c5907bb9ff..9774da48989 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java
@@ -17,6 +17,7 @@
package org.apache.logging.log4j.util;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.spi.LoggingSystem;
import org.apache.logging.log4j.spi.LoggingSystemProperties;
import org.apache.logging.log4j.status.StatusLogger;
@@ -51,7 +52,7 @@ public class Unbox {
private static final Logger LOGGER = StatusLogger.getLogger();
private static final int BITS_PER_INT = 32;
private static final int RINGBUFFER_MIN_SIZE = 32;
- private static final int RINGBUFFER_SIZE = calculateRingBufferSize(LoggingSystemProperties.UNBOX_RING_BUFFER_SIZE);
+ private static final int RINGBUFFER_SIZE = calculateRingBufferSize();
private static final int MASK = RINGBUFFER_SIZE - 1;
/**
@@ -128,22 +129,16 @@ private Unbox() {
// this is a utility
}
- private static int calculateRingBufferSize(final String propertyName) {
- final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName,
- String.valueOf(RINGBUFFER_MIN_SIZE));
- try {
- int size = Integer.parseInt(userPreferredRBSize);
- if (size < RINGBUFFER_MIN_SIZE) {
- size = RINGBUFFER_MIN_SIZE;
- LOGGER.warn("Invalid {} {}, using minimum size {}.", propertyName, userPreferredRBSize,
- RINGBUFFER_MIN_SIZE);
- }
- return ceilingNextPowerOfTwo(size);
- } catch (final Exception ex) {
- LOGGER.warn("Invalid {} {}, using default size {}.", propertyName, userPreferredRBSize,
- RINGBUFFER_MIN_SIZE);
- return RINGBUFFER_MIN_SIZE;
+ private static int calculateRingBufferSize() {
+ int size = LoggingSystem.getPropertyResolver()
+ .getInt(LoggingSystemProperties.UNBOX_RING_BUFFER_SIZE)
+ .orElse(RINGBUFFER_MIN_SIZE);
+ if (size < RINGBUFFER_MIN_SIZE) {
+ LOGGER.warn("Invalid {} {}, using minimum size {}.",
+ LoggingSystemProperties.UNBOX_RING_BUFFER_SIZE, size, RINGBUFFER_MIN_SIZE);
+ size = RINGBUFFER_MIN_SIZE;
}
+ return ceilingNextPowerOfTwo(size);
}
/**
diff --git a/log4j-api/src/main/resources/META-INF/log4j2.default.component.json b/log4j-api/src/main/resources/META-INF/log4j2.default.component.json
new file mode 100644
index 00000000000..832a29161bb
--- /dev/null
+++ b/log4j-api/src/main/resources/META-INF/log4j2.default.component.json
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+{
+ "log4j2": {
+ "*": {
+ "GC": {
+ "enableThreadLocals": "calculate",
+ "unboxRingBufferSize": 32
+ },
+ "Message": {
+ "jsonFormatterMaxDepth": 8
+ },
+ "SimpleLogger": {
+ "showContextMap": false,
+ "showLogName": false,
+ "showShortLogName": true,
+ "showDateTime": false,
+ "dateTimeFormat": "yyyy/MM/dd HH:mm:ss:SSS zzz",
+ "logFile": "system.err",
+ "logLevel": "ERROR"
+ },
+ "StatusLogger": {
+ "dateFormat": null,
+ "entries": 200,
+ "statusLoggerLevel": "WARN"
+ },
+ "ThreadContext": {
+ "enabled": true,
+ "enableMap": true,
+ "enableStack": true,
+ "garbageFree": false,
+ "inheritable": false,
+ "initialCapacity": 16
+ },
+ "Web": {
+ "enableWebApp": "calculate"
+ }
+ }
+ }
+}
diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java
index 8b316839ac9..b2b560993af 100644
--- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java
+++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraAppender.java
@@ -25,6 +25,7 @@
import org.apache.logging.log4j.core.net.SocketAddress;
import org.apache.logging.log4j.core.time.Clock;
import org.apache.logging.log4j.plugins.Configurable;
+import org.apache.logging.log4j.plugins.Inject;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
import org.apache.logging.log4j.plugins.PluginElement;
@@ -96,6 +97,8 @@ public static class Builder> extends AbstractAppender.Build
@PluginBuilderAttribute
private boolean useClockForTimestampGenerator;
+ private Clock clock;
+
/**
* Number of LogEvents to buffer before writing. Can be used with or without batch statements.
*/
@@ -103,7 +106,7 @@ public static class Builder> extends AbstractAppender.Build
private int bufferSize;
/**
- * Whether or not to use batch statements when inserting records.
+ * Whether to use batch statements when inserting records.
*/
@PluginBuilderAttribute
private boolean batched;
@@ -159,6 +162,12 @@ public B setUseClockForTimestampGenerator(final boolean useClockForTimestampGene
return asBuilder();
}
+ @Inject
+ public B setClock(final Clock clock) {
+ this.clock = clock;
+ return asBuilder();
+ }
+
public B setBufferSize(final int bufferSize) {
this.bufferSize = bufferSize;
return asBuilder();
@@ -177,8 +186,8 @@ public B setBatchType(final BatchStatement.Type batchType) {
@Override
public CassandraAppender build() {
final CassandraManager manager = CassandraManager.getManager(getName(), contactPoints, columns, useTls,
- clusterName, keyspace, table, username, password, useClockForTimestampGenerator, bufferSize, batched,
- batchType);
+ clusterName, keyspace, table, username, password, useClockForTimestampGenerator, clock, bufferSize,
+ batched, batchType);
return new CassandraAppender(getName(), getFilter(), isIgnoreExceptions(), getPropertyArray(), manager);
}
diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java
index 88f87d71693..9965536de65 100644
--- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java
+++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/CassandraManager.java
@@ -16,6 +16,11 @@
*/
package org.apache.logging.log4j.cassandra;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
import com.datastax.driver.core.BatchStatement;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.Cluster;
@@ -26,18 +31,13 @@
import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
import org.apache.logging.log4j.core.appender.db.ColumnMapping;
import org.apache.logging.log4j.core.net.SocketAddress;
+import org.apache.logging.log4j.core.time.Clock;
import org.apache.logging.log4j.jdbc.convert.DateTypeConverter;
import org.apache.logging.log4j.spi.ThreadContextMap;
import org.apache.logging.log4j.spi.ThreadContextStack;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.Strings;
-import java.io.Serializable;
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
/**
* Manager for a Cassandra appender instance.
*/
@@ -87,7 +87,7 @@ protected void connectAndStart() {
}
@Override
- protected void writeInternal(final LogEvent event, final Serializable serializable) {
+ protected void writeInternal(final LogEvent event, final Object serializable) {
for (int i = 0; i < columnMappings.size(); i++) {
final ColumnMapping columnMapping = columnMappings.get(i);
if (ThreadContextMap.class.isAssignableFrom(columnMapping.getType())
@@ -121,11 +121,12 @@ public static CassandraManager getManager(final String name, final SocketAddress
final ColumnMapping[] columns, final boolean useTls,
final String clusterName, final String keyspace, final String table,
final String username, final String password,
- final boolean useClockForTimestampGenerator, final int bufferSize,
+ final boolean useClockForTimestampGenerator, final Clock clock,
+ final int bufferSize,
final boolean batched, final BatchStatement.Type batchType) {
return getManager(name,
new FactoryData(contactPoints, columns, useTls, clusterName, keyspace, table, username, password,
- useClockForTimestampGenerator, bufferSize, batched, batchType), CassandraManagerFactory.INSTANCE);
+ useClockForTimestampGenerator, bufferSize, clock, batched, batchType), CassandraManagerFactory.INSTANCE);
}
private static class CassandraManagerFactory implements ManagerFactory {
@@ -144,7 +145,7 @@ public CassandraManager createManager(final String name, final FactoryData data)
builder.withCredentials(data.username, data.password);
}
if (data.useClockForTimestampGenerator) {
- builder.withTimestampGenerator(new ClockTimestampGenerator());
+ builder.withTimestampGenerator(new ClockTimestampGenerator(data.clock));
}
final Cluster cluster = builder.build();
@@ -182,13 +183,14 @@ private static class FactoryData extends AbstractFactoryData {
private final String username;
private final String password;
private final boolean useClockForTimestampGenerator;
+ private final Clock clock;
private final boolean batched;
private final BatchStatement.Type batchType;
private FactoryData(final SocketAddress[] contactPoints, final ColumnMapping[] columns, final boolean useTls,
final String clusterName, final String keyspace, final String table, final String username,
final String password, final boolean useClockForTimestampGenerator, final int bufferSize,
- final boolean batched, final BatchStatement.Type batchType) {
+ final Clock clock, final boolean batched, final BatchStatement.Type batchType) {
super(bufferSize, null);
this.contactPoints = convertAndAddDefaultPorts(contactPoints);
this.columns = columns;
@@ -199,6 +201,7 @@ private FactoryData(final SocketAddress[] contactPoints, final ColumnMapping[] c
this.username = username;
this.password = password;
this.useClockForTimestampGenerator = useClockForTimestampGenerator;
+ this.clock = clock;
this.batched = batched;
this.batchType = batchType;
}
diff --git a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java
index cbc5c1fe888..88408360b0f 100644
--- a/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java
+++ b/log4j-cassandra/src/main/java/org/apache/logging/log4j/cassandra/ClockTimestampGenerator.java
@@ -18,14 +18,17 @@
import com.datastax.driver.core.TimestampGenerator;
import org.apache.logging.log4j.core.time.Clock;
-import org.apache.logging.log4j.core.time.ClockFactory;
/**
* A {@link TimestampGenerator} implementation using the configured {@link Clock}.
*/
public class ClockTimestampGenerator implements TimestampGenerator {
- private final Clock clock = ClockFactory.getClock();
+ private final Clock clock;
+
+ public ClockTimestampGenerator(final Clock clock) {
+ this.clock = clock;
+ }
@Override
public long next() {
diff --git a/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java b/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java
index 4f17e12e950..4cb42a92434 100644
--- a/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java
+++ b/log4j-cassandra/src/test/java/org/apache/logging/log4j/cassandra/CassandraExtension.java
@@ -24,12 +24,14 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicReference;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.Session;
import org.apache.cassandra.service.CassandraDaemon;
import org.apache.logging.log4j.core.util.Cancellable;
import org.apache.logging.log4j.core.util.Closer;
import org.apache.logging.log4j.core.util.Log4jThreadFactory;
import org.apache.logging.log4j.core.util.Throwables;
-import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.Constants;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
@@ -38,9 +40,6 @@
import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver;
import org.opentest4j.TestAbortedException;
-import com.datastax.driver.core.Cluster;
-import com.datastax.driver.core.Session;
-
import static org.junit.jupiter.api.Assertions.fail;
public class CassandraExtension extends TypeBasedParameterResolver implements BeforeEachCallback, AfterEachCallback {
@@ -122,7 +121,7 @@ private EmbeddedCassandra(
@Override
public void cancel() {
// LOG4J2-1850 Cassandra on Windows calls System.exit in the daemon stop method
- if (PropertiesUtil.getProperties().isOsWindows()) {
+ if (Constants.isWindows()) {
cancelOnWindows();
} else {
daemon.stop();
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
index 1cd9f78d7b1..382e810741b 100644
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/HttpAppenderTest.java
@@ -16,32 +16,22 @@
*/
package org.apache.logging.log4j.core.appender;
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.containing;
-import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.post;
-import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.put;
-import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
import java.io.IOException;
import java.net.URL;
+import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.lookup.JavaLookup;
import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration;
import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
-import org.apache.logging.log4j.core.test.net.ssl.TestConstants;
import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration;
-import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.net.ssl.TestConstants;
+import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.status.StatusData;
import org.apache.logging.log4j.status.StatusListener;
@@ -50,8 +40,10 @@
import org.junit.Rule;
import org.junit.Test;
-import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import static com.github.tomakehurst.wiremock.client.WireMock.*;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
@Ignore("Fails often on Windows")
@@ -129,13 +121,13 @@ public class HttpAppenderTest {
private static final String LOG_MESSAGE = "Hello, world!";
- private static Log4jLogEvent createLogEvent() {
- return Log4jLogEvent.newBuilder()
+ private static LogEvent createLogEvent() {
+ return LogEvent.builder()
.setLoggerName(HttpAppenderTest.class.getName())
.setLoggerFqcn(HttpAppenderTest.class.getName())
.setLevel(Level.INFO)
.setMessage(new SimpleMessage(LOG_MESSAGE))
- .build();
+ .get();
}
private final ResponseDefinitionBuilder SUCCESS_RESPONSE = aResponse().withStatus(201)
@@ -183,14 +175,22 @@ public void testAppendHttps() throws Exception {
wireMockRule.stubFor(post(urlEqualTo("/test/log4j/"))
.willReturn(SUCCESS_RESPONSE));
+ final TrustStoreConfiguration trustStoreConfiguration = TrustStoreConfiguration.builder()
+ .setLocation(TestConstants.TRUSTSTORE_FILE)
+ .setPassword(TestConstants.TRUSTSTORE_PWD())
+ .setKeyStoreType(TestConstants.TRUSTSTORE_TYPE)
+ .build();
+ final KeyStoreConfiguration keyStoreConfiguration = KeyStoreConfiguration.builder()
+ .setLocation(TestConstants.KEYSTORE_FILE)
+ .setPassword(TestConstants.KEYSTORE_PWD())
+ .setKeyStoreType(TestConstants.KEYSTORE_TYPE)
+ .build();
final Appender appender = HttpAppender.newBuilder()
.setName("Http")
.setLayout(JsonLayout.createDefaultLayout())
.setConfiguration(ctx.getConfiguration())
.setUrl(new URL("https://localhost:" + wireMockRule.httpsPort() + "/test/log4j/"))
- .setSslConfiguration(SslConfiguration.createSSLConfiguration(null,
- KeyStoreConfiguration.createKeyStoreConfiguration(TestConstants.KEYSTORE_FILE, TestConstants.KEYSTORE_PWD(), null, null, TestConstants.KEYSTORE_TYPE, null),
- TrustStoreConfiguration.createKeyStoreConfiguration(TestConstants.TRUSTSTORE_FILE, TestConstants.TRUSTSTORE_PWD(), null ,null, TestConstants.TRUSTSTORE_TYPE, null)))
+ .setSslConfiguration(SslConfiguration.createSSLConfiguration(null, keyStoreConfiguration, trustStoreConfiguration))
.setVerifyHostname(false)
.build();
appender.append(createLogEvent());
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
index 1a24bcbe7cf..9773ef3c79d 100644
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SecureSocketAppenderSocketOptionsTest.java
@@ -17,9 +17,7 @@
package org.apache.logging.log4j.core.appender;
import java.io.IOException;
-import java.io.OutputStream;
import java.net.Socket;
-
import javax.net.ssl.SSLServerSocketFactory;
import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
@@ -29,24 +27,21 @@
import org.apache.logging.log4j.core.net.ssl.KeyStoreConfiguration;
import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.net.ssl.StoreConfigurationException;
-import org.apache.logging.log4j.core.test.net.ssl.TestConstants;
import org.apache.logging.log4j.core.net.ssl.TrustStoreConfiguration;
-import org.apache.logging.log4j.core.util.NullOutputStream;
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
import org.apache.logging.log4j.core.test.AvailablePortFinder;
+import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.apache.logging.log4j.core.test.net.ssl.TestConstants;
import org.junit.AfterClass;
import org.junit.Assert;
-import org.junit.Assume;
import org.junit.ClassRule;
import org.junit.Test;
public class SecureSocketAppenderSocketOptionsTest {
private static final int PORT;
- private static TcpSocketTestServer tcpSocketTestServer;
+ private static final TcpSocketTestServer tcpSocketTestServer;
private static SSLServerSocketFactory serverSocketFactory;
- private static SslConfiguration sslConfiguration;
static {
PORT = AvailablePortFinder.getNextAvailable();
@@ -73,22 +68,15 @@ public static void afterClass() {
}
public static void initServerSocketFactory() throws StoreConfigurationException {
- final KeyStoreConfiguration ksc = KeyStoreConfiguration.createKeyStoreConfiguration(
- TestConstants.KEYSTORE_FILE, // file
- TestConstants.KEYSTORE_PWD(), // password
- null, // passwordEnvironmentVariable
- null, // passwordFile
- null, // key store type
- null); // algorithm
-
- final TrustStoreConfiguration tsc = TrustStoreConfiguration.createKeyStoreConfiguration(
- TestConstants.TRUSTSTORE_FILE, // file
- TestConstants.TRUSTSTORE_PWD(), // password
- null, // passwordEnvironmentVariable
- null, // passwordFile
- null, // key store type
- null); // algorithm
- sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc);
+ final KeyStoreConfiguration ksc = KeyStoreConfiguration.builder()
+ .setLocation(TestConstants.KEYSTORE_FILE)
+ .setPassword(TestConstants.KEYSTORE_PWD())
+ .build();
+ final TrustStoreConfiguration tsc = TrustStoreConfiguration.builder()
+ .setLocation(TestConstants.TRUSTSTORE_FILE)
+ .setPassword(TestConstants.TRUSTSTORE_PWD())
+ .build();
+ SslConfiguration sslConfiguration = SslConfiguration.createSSLConfiguration(null, ksc, tsc);
serverSocketFactory = sslConfiguration.getSslServerSocketFactory();
}
@@ -100,8 +88,6 @@ public void testSocketOptions() throws IOException {
Assert.assertNotNull(appender);
final TcpSocketManager manager = (TcpSocketManager) appender.getManager();
Assert.assertNotNull(manager);
- final OutputStream outputStream = manager.getOutputStream();
- Assert.assertFalse(outputStream instanceof NullOutputStream);
final SocketOptions socketOptions = manager.getSocketOptions();
Assert.assertNotNull(socketOptions);
final Socket socket = manager.getSocket();
@@ -127,14 +113,4 @@ public void testSocketOptions() throws IOException {
Assert.assertEquals(12345, socket.getSoLinger());
Assert.assertEquals(54321, socket.getSoTimeout());
}
-
- @Test
- public void testSocketTrafficClass() throws IOException {
- Assume.assumeTrue("Run only on Java 7", System.getProperty("java.specification.version").equals("1.7"));
- Assume.assumeFalse("Do not run on Travis CI", "true".equals(System.getenv("TRAVIS")));
- final SocketAppender appender = loggerContextRule.getAppender("socket", SocketAppender.class);
- final TcpSocketManager manager = (TcpSocketManager) appender.getManager();
- final Socket socket = manager.getSocket();
- Assert.assertEquals(Rfc1349TrafficClass.IPTOS_LOWCOST.value(), socket.getTrafficClass());
- }
}
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
index 0d1b9914367..36b04cf1534 100644
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderBufferSizeTest.java
@@ -20,9 +20,9 @@
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.SocketAppenderTest.TcpSocketTestServer;
-import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
import org.apache.logging.log4j.core.test.AvailablePortFinder;
+import org.apache.logging.log4j.core.util.GarbageFreeConfiguration;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -61,12 +61,12 @@ public void teardown() {
@Test
public void testTcpAppenderDefaultEncoderBufferSize() throws Exception {
- SocketAppenderTest.testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE);
+ SocketAppenderTest.testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize());
}
@Test
public void testTcpAppenderLargeEncoderBufferSize() throws Exception {
- SocketAppenderTest.testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE * 100);
+ SocketAppenderTest.testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize() * 100);
}
@Test
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
index bad65d4eeea..012007fe205 100644
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderSocketOptionsTest.java
@@ -26,7 +26,6 @@
import org.apache.logging.log4j.core.net.TcpSocketManager;
import org.apache.logging.log4j.core.test.junit.AllocatePorts;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
-import org.apache.logging.log4j.core.util.NullOutputStream;
import org.apache.logging.log4j.plugins.Named;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -64,8 +63,7 @@ public void testSocketOptions(@Named("socket") final SocketAppender appender) th
.isInstanceOf(TcpSocketManager.class);
final TcpSocketManager manager = (TcpSocketManager) abstractSocketManager;
assertThat(manager.getOutputStream())
- .isNotNull()
- .isInstanceOf(NullOutputStream.class);
+ .isNotNull();
final SocketOptions socketOptions = manager.getSocketOptions();
assertNotNull(socketOptions);
final Socket socket = manager.getSocket();
diff --git a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
index 99fd2d08d76..f23cf35e349 100644
--- a/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
+++ b/log4j-core-its/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java
@@ -16,6 +16,21 @@
*/
package org.apache.logging.log4j.core.appender;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.Level;
@@ -25,10 +40,10 @@
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
+import org.apache.logging.log4j.core.impl.ImmutableLogEvent;
import org.apache.logging.log4j.core.net.Protocol;
import org.apache.logging.log4j.core.test.AvailablePortFinder;
-import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.GarbageFreeConfiguration;
import org.apache.logging.log4j.core.util.Throwables;
import org.apache.logging.log4j.jackson.json.Log4jJsonObjectMapper;
import org.apache.logging.log4j.jackson.json.layout.JsonLayout;
@@ -39,21 +54,6 @@
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
import static org.junit.jupiter.api.Assertions.*;
/**
@@ -112,13 +112,13 @@ static void reset() {
@Test
public void testTcpAppender1() throws Exception {
- testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE);
+ testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize());
}
@Test
@Disabled("WIP Bug when this method runs after testTcpAppender1()")
public void testTcpAppender2() throws Exception {
- testTcpAppender(tcpServer, logger, Constants.ENCODER_BYTE_BUFFER_SIZE);
+ testTcpAppender(tcpServer, logger, GarbageFreeConfiguration.getDefaultConfiguration().getEncoderByteBufferSize());
}
static void testTcpAppender(final TcpSocketTestServer tcpTestServer, final Logger logger, final int bufferSize)
@@ -310,7 +310,7 @@ public void run() {
latch.countDown();
sock.receive(packet);
count.incrementAndGet();
- final LogEvent event = objectMapper.readValue(packet.getData(), Log4jLogEvent.class);
+ final LogEvent event = objectMapper.readValue(packet.getData(), ImmutableLogEvent.class);
queue.add(event);
}
} catch (final Throwable e) {
@@ -374,7 +374,7 @@ public void run() {
if (socket != null) {
final InputStream is = socket.getInputStream();
while (!shutdown) {
- final MappingIterator mappingIterator = objectMapper.readerFor(Log4jLogEvent.class).readValues(is);
+ final MappingIterator mappingIterator = objectMapper.readerFor(ImmutableLogEvent.class).readValues(is);
while (mappingIterator.hasNextValue()) {
queue.add(mappingIterator.nextValue());
count.incrementAndGet();
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
index 4297dca4932..a08cdd72eff 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
@@ -33,7 +33,7 @@ public class BasicConfigurationFactory extends ConfigurationFactory {
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
- return new BasicConfiguration();
+ return new BasicConfiguration(loggerContext);
}
@Override
@@ -50,8 +50,8 @@ public static class BasicConfiguration extends AbstractConfiguration {
private static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
- public BasicConfiguration() {
- super(null, ConfigurationSource.NULL_SOURCE);
+ public BasicConfiguration(final LoggerContext loggerContext) {
+ super(loggerContext, ConfigurationSource.NULL_SOURCE);
final LoggerConfig root = getRootLogger();
final String name = System.getProperty(DEFAULT_LEVEL);
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java
index 4910494856d..092fb459889 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/EncodingListAppender.java
@@ -16,7 +16,6 @@
*/
package org.apache.logging.log4j.core.test.appender;
-import java.io.Serializable;
import java.nio.ByteBuffer;
import org.apache.logging.log4j.core.Filter;
@@ -37,7 +36,7 @@ public EncodingListAppender(final String name) {
super(name);
}
- public EncodingListAppender(final String name, final Filter filter, final Layout extends Serializable> layout,
+ public EncodingListAppender(final String name, final Filter filter, final Layout> layout,
final boolean newline, final boolean raw) {
super(name, filter, layout, newline, raw);
}
@@ -69,7 +68,7 @@ public void writeBytes(final byte[] data, final int offset, final int length) {
@Override
public synchronized void append(final LogEvent event) {
- final Layout extends Serializable> layout = getLayout();
+ final Layout> layout = getLayout();
if (layout == null) {
events.add(event);
} else {
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java
index 206afbc122a..3987a6d9dca 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/FailOnceAppender.java
@@ -16,21 +16,20 @@
*/
package org.apache.logging.log4j.core.test.appender;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
import org.apache.logging.log4j.LoggingException;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
-import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
-import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.util.Throwables;
import org.apache.logging.log4j.plugins.Configurable;
import org.apache.logging.log4j.plugins.Plugin;
-import org.apache.logging.log4j.plugins.validation.constraints.Required;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Supplier;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.PluginFactory;
/**
* An {@link Appender} that fails on the first use and works for the rest.
@@ -74,11 +73,8 @@ public synchronized List drainEvents() {
}
@PluginFactory
- public static FailOnceAppender createAppender(
- @PluginAttribute("name") @Required(message = "A name for the Appender must be specified") final String name,
- @PluginAttribute("throwableClassName") final String throwableClassName) {
- final Supplier throwableSupplier = createThrowableSupplier(name, throwableClassName);
- return new FailOnceAppender(name, throwableSupplier);
+ public static Builder newBuilder() {
+ return new Builder();
}
private static Supplier createThrowableSupplier(
@@ -111,6 +107,24 @@ private static void stopCurrentThread() {
Thread.currentThread().stop();
}
+ public static class Builder extends AbstractAppender.Builder implements Supplier {
+ private String throwableClassName;
+
+ public String getThrowableClassName() {
+ return throwableClassName;
+ }
+
+ public Builder setThrowableClassName(@PluginAttribute final String throwableClassName) {
+ this.throwableClassName = throwableClassName;
+ return this;
+ }
+
+ @Override
+ public FailOnceAppender get() {
+ return new FailOnceAppender(getName(), createThrowableSupplier(getName(), getThrowableClassName()));
+ }
+ }
+
public enum ThrowableClassName {;
public static final String RUNTIME_EXCEPTION = "RuntimeException";
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java
index 532a6b3d464..fe1d572986e 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/InMemoryAppender.java
@@ -18,7 +18,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.Serializable;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
@@ -31,7 +30,7 @@
*/
public class InMemoryAppender extends AbstractOutputStreamAppender {
- public InMemoryAppender(final String name, final Layout extends Serializable> layout, final CompositeFilter filters,
+ public InMemoryAppender(final String name, final Layout> layout, final CompositeFilter filters,
final boolean ignoreExceptions, final boolean writeHeader, Property[] properties) {
super(name, layout, filters, ignoreExceptions, true, properties, new InMemoryManager(name, layout, writeHeader));
}
@@ -43,7 +42,7 @@ public String toString() {
static class InMemoryManager extends OutputStreamManager {
- public InMemoryManager(final String name, final Layout extends Serializable> layout,
+ public InMemoryManager(final String name, final Layout> layout,
final boolean writeHeader) {
super(new ByteArrayOutputStream(), name, layout, writeHeader);
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java
index aac8bbc912d..75621f435c6 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/appender/ListAppender.java
@@ -16,6 +16,12 @@
*/
package org.apache.logging.log4j.core.test.appender;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
@@ -32,13 +38,6 @@
import org.apache.logging.log4j.plugins.PluginFactory;
import org.apache.logging.log4j.plugins.validation.constraints.Required;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
/**
* This appender is primarily used for testing. Use in a real environment is discouraged as the List could eventually
* grow to cause an OutOfMemoryError.
@@ -69,7 +68,7 @@ public class ListAppender extends AbstractAppender {
/**
* CountDownLatch for asynchronous logging tests. Example usage:
- *
+ *
*
* @Rule
* public LoggerContextRule context = new LoggerContextRule("log4j-list.xml");
@@ -102,7 +101,7 @@ public ListAppender(final String name) {
raw = false;
}
- public ListAppender(final String name, final Filter filter, final Layout extends Serializable> layout,
+ public ListAppender(final String name, final Filter filter, final Layout> layout,
final boolean newline, final boolean raw) {
super(name, filter, layout, true, Property.EMPTY_ARRAY);
this.newLine = newline;
@@ -117,11 +116,11 @@ public ListAppender(final String name, final Filter filter, final Layout exten
@Override
public void append(final LogEvent event) {
- final Layout extends Serializable> layout = getLayout();
+ final Layout> layout = getLayout();
if (layout == null) {
if (event instanceof MutableLogEvent) {
// must take snapshot or subsequent calls to logger.log() will modify this event
- events.add(((MutableLogEvent) event).createMemento());
+ events.add(event.copy());
} else {
events.add(event);
}
@@ -174,7 +173,7 @@ void write(final byte[] bytes) {
public boolean stop(final long timeout, final TimeUnit timeUnit) {
setStopping();
super.stop(timeout, timeUnit, false);
- final Layout extends Serializable> layout = getLayout();
+ final Layout> layout = getLayout();
if (layout != null) {
final byte[] bytes = layout.getFooter();
if (bytes != null) {
@@ -221,7 +220,7 @@ public List getData() {
}
public static ListAppender createAppender(final String name, final boolean newLine, final boolean raw,
- final Layout extends Serializable> layout, final Filter filter) {
+ final Layout> layout, final Filter filter) {
return new ListAppender(name, filter, layout, newLine, raw);
}
@@ -235,7 +234,7 @@ public static class Builder implements org.apache.logging.log4j.plugins.util.Bui
private String name;
private boolean entryPerNewLine;
private boolean raw;
- private Layout extends Serializable> layout;
+ private Layout> layout;
private Filter filter;
public Builder setName(@Required @PluginAttribute final String name) {
@@ -253,7 +252,7 @@ public Builder setRaw(@PluginAttribute final boolean raw) {
return this;
}
- public Builder setLayout(@PluginElement final Layout extends Serializable> layout) {
+ public Builder setLayout(@PluginElement final Layout> layout) {
this.layout = layout;
return this;
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java
index ea5f36e4007..3d7f2bd4620 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderManagerResolver.java
@@ -14,9 +14,10 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-
package org.apache.logging.log4j.core.test.junit;
+import java.lang.reflect.Parameter;
+
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.AbstractManager;
@@ -28,8 +29,6 @@
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.platform.commons.support.ReflectionSupport;
-import java.lang.reflect.Parameter;
-
import static org.apache.logging.log4j.core.test.junit.LoggerContextResolver.getLoggerContext;
/**
@@ -46,9 +45,6 @@ public boolean supportsParameter(final ParameterContext parameterContext, final
@Override
public Object resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext) throws ParameterResolutionException {
final LoggerContext loggerContext = getLoggerContext(extensionContext);
- if (loggerContext == null) {
- throw new ParameterResolutionException("No LoggerContext defined");
- }
final Configuration configuration = loggerContext.getConfiguration();
final Parameter parameter = parameterContext.getParameter();
final String name = Keys.getName(parameter);
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java
index 6e206591a38..c858490e9a3 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/AppenderResolver.java
@@ -14,19 +14,19 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-
package org.apache.logging.log4j.core.test.junit;
+import java.lang.reflect.Parameter;
+
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.plugins.di.Keys;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
-import java.lang.reflect.Parameter;
-
import static org.apache.logging.log4j.core.test.junit.LoggerContextResolver.getLoggerContext;
/**
@@ -45,16 +45,18 @@ public boolean supportsParameter(
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
final LoggerContext loggerContext = getLoggerContext(extensionContext);
- if (loggerContext == null) {
- throw new ParameterResolutionException("No LoggerContext defined");
- }
final String name = Keys.getName(parameterContext.getParameter());
if (name.isEmpty()) {
throw new ParameterResolutionException("No named annotation present after checking earlier");
}
- final Appender appender = loggerContext.getConfiguration().getAppender(name);
+ final String contextName = loggerContext.getName();
+ final Configuration configuration = loggerContext.getConfiguration();
+ final String configName = configuration.getName();
+ final Appender appender = configuration.getAppender(name);
if (appender == null) {
- throw new ParameterResolutionException("No appender named " + name);
+ final String error = String.format("No appender found for name '%s' in config='%s' and context='%s'",
+ name, configName, contextName);
+ throw new ParameterResolutionException(error);
}
return appender;
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java
index 9b809fc4a61..7b4ffbe5301 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationResolver.java
@@ -35,9 +35,10 @@ public ConfigurationResolver() {
public Configuration resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
final LoggerContext loggerContext = getLoggerContext(extensionContext);
- if (loggerContext == null) {
- throw new ParameterResolutionException("No LoggerContext defined");
+ final Configuration configuration = loggerContext.getConfiguration();
+ if (configuration == null) {
+ throw new ParameterResolutionException("No Configuration defined");
}
- return loggerContext.getConfiguration();
+ return configuration;
}
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java
index 7848c778958..bdf0515c85a 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ContextSelectorCallback.java
@@ -16,33 +16,28 @@
*/
package org.apache.logging.log4j.core.test.junit;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import java.util.function.Consumer;
+
import org.apache.logging.log4j.core.selector.ContextSelector;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.Injector;
-import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.platform.commons.support.AnnotationSupport;
-public class ContextSelectorCallback implements BeforeAllCallback, AfterAllCallback {
+class ContextSelectorCallback implements BeforeAllCallback {
@Override
public void beforeAll(final ExtensionContext context) throws Exception {
AnnotationSupport.findAnnotation(context.getTestClass(), ContextSelectorType.class)
.map(ContextSelectorType::value)
.ifPresent(contextSelectorClass -> {
- final Injector injector = DI.createInjector();
- injector.registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
- injector.init();
- final Log4jContextFactory factory = injector.getInstance(Log4jContextFactory.class);
- LogManager.setFactory(factory);
+ final LoggingTestContext testContext = LoggingTestContext.configurer()
+ .setBootstrap(true)
+ .setContextName(context.getRequiredTestClass().getSimpleName())
+ .build();
+ final Consumer configurer = injector ->
+ injector.registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
+ testContext.init(configurer);
+ LoggerContextResolver.setTestContext(context, testContext);
});
}
-
- @Override
- public void afterAll(final ExtensionContext context) throws Exception {
- AnnotationSupport.findAnnotation(context.getTestClass(), ContextSelectorType.class)
- .ifPresent(ignored -> LogManager.setFactory(null));
- }
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java
index 53bd60172b7..81343578172 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextResolver.java
@@ -16,17 +16,9 @@
*/
package org.apache.logging.log4j.core.test.junit;
-import java.net.URI;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
-import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.LoggerContextAccessor;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.Injector;
import org.apache.logging.log4j.test.junit.TypeBasedParameterResolver;
import org.junit.jupiter.api.extension.AfterEachCallback;
@@ -34,17 +26,13 @@
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
-import org.junit.jupiter.api.extension.ExtensionContext.Store;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.platform.commons.support.AnnotationSupport;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
class LoggerContextResolver extends TypeBasedParameterResolver implements BeforeAllCallback,
BeforeEachCallback, AfterEachCallback {
- private static final String FQCN = LoggerContextResolver.class.getName();
- private static final Namespace BASE_NAMESPACE = Namespace.create(LoggerContext.class);
+ private static final Namespace NAMESPACE = Namespace.create(LoggingTestContext.class);
public LoggerContextResolver() {
super(LoggerContext.class);
@@ -54,30 +42,20 @@ public LoggerContextResolver() {
public void beforeAll(ExtensionContext context) throws Exception {
final Class> testClass = context.getRequiredTestClass();
AnnotationSupport.findAnnotation(testClass, LoggerContextSource.class)
- .ifPresent(testSource -> setUpLoggerContext(testSource, context));
+ .ifPresent(testSource -> initializeTestContext(testSource, context));
}
@Override
public void beforeEach(ExtensionContext context) throws Exception {
- final Class> testClass = context.getRequiredTestClass();
- if (AnnotationSupport.isAnnotated(testClass, LoggerContextSource.class)) {
- final Store testClassStore = context.getStore(BASE_NAMESPACE.append(testClass));
- final LoggerContextAccessor accessor = testClassStore.get(LoggerContextAccessor.class, LoggerContextAccessor.class);
- if (accessor == null) {
- throw new IllegalStateException(
- "Specified @LoggerContextSource but no LoggerContext found for test class " +
- testClass.getCanonicalName());
- }
- if (testClassStore.get(ReconfigurationPolicy.class, ReconfigurationPolicy.class) == ReconfigurationPolicy.BEFORE_EACH) {
- accessor.getLoggerContext().reconfigure();
- }
+ if (AnnotationSupport.isAnnotated(context.getRequiredTestClass(), LoggerContextSource.class)) {
+ final LoggingTestContext testContext = getTestContext(context);
+ testContext.beforeEachTest();
}
AnnotationSupport.findAnnotation(context.getRequiredTestMethod(), LoggerContextSource.class)
.ifPresent(source -> {
- final LoggerContext loggerContext = setUpLoggerContext(source, context);
- if (source.reconfigure() == ReconfigurationPolicy.BEFORE_EACH) {
- loggerContext.reconfigure();
- }
+ initializeTestContext(source, context);
+ final LoggingTestContext testContext = getTestContext(context);
+ testContext.beforeEachTest();
});
}
@@ -85,10 +63,8 @@ public void beforeEach(ExtensionContext context) throws Exception {
public void afterEach(ExtensionContext context) throws Exception {
final Class> testClass = context.getRequiredTestClass();
if (AnnotationSupport.isAnnotated(testClass, LoggerContextSource.class)) {
- final Store testClassStore = getTestStore(context);
- if (testClassStore.get(ReconfigurationPolicy.class, ReconfigurationPolicy.class) == ReconfigurationPolicy.AFTER_EACH) {
- testClassStore.get(LoggerContextAccessor.class, LoggerContextAccessor.class).getLoggerContext().reconfigure();
- }
+ final LoggingTestContext testContext = getTestContext(context);
+ testContext.afterEachTest();
}
}
@@ -98,72 +74,42 @@ public LoggerContext resolveParameter(
return getLoggerContext(extensionContext);
}
- static LoggerContext getLoggerContext(ExtensionContext context) {
- final Store store = getTestStore(context);
- final LoggerContextAccessor accessor = store.get(LoggerContextAccessor.class, LoggerContextAccessor.class);
- assertNotNull(accessor);
- return accessor.getLoggerContext();
+ private static void initializeTestContext(final LoggerContextSource source, final ExtensionContext extensionContext) {
+ final LoggingTestContext context = LoggingTestContext.configurer()
+ .setBootstrap(source.bootstrap())
+ .setConfigurationLocation(source.value())
+ .setContextName(source.name())
+ .setReconfigurationPolicy(source.reconfigure())
+ .setTimeout(source.timeout(), source.unit())
+ .setV1Config(source.v1config())
+ .setClassLoader(extensionContext.getRequiredTestClass().getClassLoader())
+ .build();
+ final Consumer configurer = extensionContext.getTestInstance()
+ .map(instance -> (Consumer) injector -> injector.registerBundle(instance))
+ .orElse(null);
+ context.init(configurer);
+ setTestContext(extensionContext, context);
}
- private static Store getTestStore(final ExtensionContext context) {
- return context.getStore(BASE_NAMESPACE.append(context.getRequiredTestClass()));
+ static void setTestContext(final ExtensionContext context, final LoggingTestContext testContext) {
+ context.getStore(NAMESPACE).put(LoggingTestContext.class, testContext);
}
- private static LoggerContext setUpLoggerContext(final LoggerContextSource source, final ExtensionContext extensionContext) {
- final String displayName = extensionContext.getDisplayName();
- final Injector injector = extensionContext.getTestInstance().map(DI::createInjector).orElseGet(DI::createInjector);
- injector.init();
- final Log4jContextFactory loggerContextFactory;
- if (source.bootstrap()) {
- loggerContextFactory = new Log4jContextFactory(injector);
- LogManager.setFactory(loggerContextFactory);
- } else {
- loggerContextFactory = (Log4jContextFactory) LogManager.getFactory();
- }
- final Class> testClass = extensionContext.getRequiredTestClass();
- final ClassLoader classLoader = testClass.getClassLoader();
- final Map.Entry injectorContext = Map.entry(Injector.class.getName(), injector);
- final String configLocation = source.value();
- final URI configUri;
- if (source.v1config()) {
- System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, configLocation);
- configUri = null; // handled by system property
- } else {
- configUri = configLocation.isEmpty() ? null : NetUtils.toURI(configLocation);
+ static LoggingTestContext getTestContext(final ExtensionContext context) {
+ final LoggingTestContext testContext = context.getStore(NAMESPACE).get(LoggingTestContext.class, LoggingTestContext.class);
+ if (testContext == null) {
+ throw new ParameterResolutionException("No LoggingTestContext defined");
}
- final LoggerContext context = loggerContextFactory.getContext(FQCN, classLoader, injectorContext, false, configUri, displayName);
- assertNotNull(context, () -> "No LoggerContext created for " + testClass + " and config file " + configLocation);
- final Store store = getTestStore(extensionContext);
- store.put(ReconfigurationPolicy.class, source.reconfigure());
- store.put(LoggerContextAccessor.class, new ContextHolder(context, source.timeout(), source.unit()));
- return context;
+ return testContext;
}
- private static class ContextHolder implements Store.CloseableResource, LoggerContextAccessor {
- private final LoggerContext context;
- private final long shutdownTimeout;
- private final TimeUnit unit;
-
- private ContextHolder(final LoggerContext context, final long shutdownTimeout, final TimeUnit unit) {
- this.context = context;
- this.shutdownTimeout = shutdownTimeout;
- this.unit = unit;
- }
-
- @Override
- public LoggerContext getLoggerContext() {
- return context;
- }
-
- @Override
- public void close() throws Throwable {
- try {
- context.stop(shutdownTimeout, unit);
- } finally {
- System.clearProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL);
- System.clearProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY);
- }
+ static LoggerContext getLoggerContext(ExtensionContext context) {
+ final LoggingTestContext testContext = getTestContext(context);
+ final LoggerContext loggerContext = testContext.getLoggerContext();
+ if (loggerContext == null) {
+ throw new ParameterResolutionException("No LoggerContext defined");
}
+ return loggerContext;
}
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java
index 118f71b2450..616a5d839f2 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextRule.java
@@ -17,30 +17,28 @@
package org.apache.logging.log4j.core.test.junit;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.AbstractLifeCycle;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.LoggerContextAccessor;
import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.Configurator;
-import org.apache.logging.log4j.core.impl.Log4jContextFactory;
import org.apache.logging.log4j.core.selector.ContextSelector;
import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.plugins.di.DI;
import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.di.Keys;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.test.junit.CleanFiles;
import org.apache.logging.log4j.test.junit.CleanFolders;
-import org.apache.logging.log4j.util.Strings;
+import org.apache.logging.log4j.util.Cast;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import org.opentest4j.AssertionFailedError;
import static org.junit.Assert.assertNotNull;
@@ -59,14 +57,11 @@ public static LoggerContextRule createShutdownTimeoutLoggerContextRule(final Str
return new LoggerContextRule(config, 10, TimeUnit.SECONDS);
}
- private static final String SYS_PROP_KEY_CLASS_NAME = "org.apache.logging.log4j.junit.LoggerContextRule#ClassName";
- private static final String SYS_PROP_KEY_DISPLAY_NAME = "org.apache.logging.log4j.junit.LoggerContextRule#DisplayName";
+ private final LoggingTestContext.Configurer configurer;
private final String configurationLocation;
private LoggerContext loggerContext;
private Class extends ContextSelector> contextSelectorClass;
private String testClassName;
- private final long shutdownTimeout;
- private final TimeUnit shutdownTimeUnit;
/**
* Constructs a new LoggerContextRule without a configuration file.
@@ -100,10 +95,13 @@ public LoggerContextRule(final String configurationLocation, final Class exten
public LoggerContextRule(final String configurationLocation, final Class extends ContextSelector> contextSelectorClass,
final long shutdownTimeout, final TimeUnit shutdownTimeUnit) {
+ configurer = LoggingTestContext.configurer()
+ .setConfigurationLocation(configurationLocation)
+ .setTimeout(shutdownTimeout, shutdownTimeUnit)
+ // TODO(ms): can support ReconfigurationPolicy if we allow reuse of the context like in LoggerContextResolver
+ .setBootstrap(true);
this.configurationLocation = configurationLocation;
this.contextSelectorClass = contextSelectorClass;
- this.shutdownTimeout = shutdownTimeout;
- this.shutdownTimeUnit = shutdownTimeUnit;
}
public LoggerContextRule(final String configurationLocation, final int shutdownTimeout, final TimeUnit shutdownTimeUnit) {
@@ -116,45 +114,29 @@ public Statement apply(final Statement base, final Description description) {
if (System.getProperties().containsKey("EBUG")) {
StatusLogger.getLogger().setLevel(Level.DEBUG);
}
+ final LoggingTestContext testContext = configurer.setClassLoader(description.getTestClass().getClassLoader())
+ .setContextName(Keys.getSpecifiedName(description.getAnnotations()).orElse(description.getMethodName()))
+ .build();
testClassName = description.getClassName();
return new Statement() {
@Override
public void evaluate() throws Throwable {
- System.setProperty(SYS_PROP_KEY_CLASS_NAME, description.getClassName());
- final String displayName = description.getDisplayName();
- System.setProperty(SYS_PROP_KEY_DISPLAY_NAME, displayName);
- final Injector injector = DI.createInjector();
+ final Consumer injectorConsumer;
if (contextSelectorClass != null) {
- injector.registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
- }
- injector.init();
- final Log4jContextFactory factory = new Log4jContextFactory(injector);
- LogManager.setFactory(factory);
- final String fqcn = getClass().getName();
- final ClassLoader classLoader = description.getTestClass().getClassLoader();
-
- if (Strings.isBlank(configurationLocation)) {
- loggerContext = factory.getContext(fqcn, classLoader, null, false);
- } else if (configurationLocation.contains(",")) {
- loggerContext = factory.getContext(fqcn, classLoader, null, false, NetUtils.toURIs(configurationLocation),
- displayName);
+ injectorConsumer = injector -> injector
+ .registerBinding(ContextSelector.KEY, injector.getFactory(contextSelectorClass));
} else {
- loggerContext = factory.getContext(fqcn, classLoader, null, false, NetUtils.toURI(configurationLocation),
- displayName);
+ injectorConsumer = null;
}
- assertNotNull("Error initializing LoggerContext", loggerContext);
+ testContext.init(injectorConsumer);
+ loggerContext = testContext.getLoggerContext();
try {
base.evaluate();
} finally {
- if (!Configurator.shutdown(loggerContext, shutdownTimeout, shutdownTimeUnit)) {
- StatusLogger.getLogger().error("Logger context {} did not shutdown completely after {} {}.",
- loggerContext.getName(), shutdownTimeout, shutdownTimeUnit);
- }
+ testContext.close();
loggerContext = null;
contextSelectorClass = null;
StatusLogger.getLogger().reset();
- System.clearProperty(SYS_PROP_KEY_CLASS_NAME);
- System.clearProperty(SYS_PROP_KEY_DISPLAY_NAME);
}
}
};
@@ -168,9 +150,8 @@ public void evaluate() throws Throwable {
* the name of the Appender to look up.
* @return the named Appender or {@code null} if it wasn't defined in the configuration.
*/
- @SuppressWarnings("unchecked") // Assume the call site knows what it is doing.
public T getAppender(final String name) {
- return (T) getConfiguration().getAppenders().get(name);
+ return Cast.cast(getConfiguration().getAppenders().get(name));
}
/**
@@ -230,7 +211,7 @@ public ListAppender getListAppender(final String name) {
if (appender instanceof ListAppender) {
return (ListAppender) appender;
}
- throw new AssertionError("No ListAppender named " + name + " found.");
+ throw new AssertionFailedError("No ListAppender named " + name + " found.");
}
/**
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java
index ccdc5027642..0747560d3ea 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerContextSource.java
@@ -14,17 +14,8 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-
package org.apache.logging.log4j.core.test.junit;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.extension.ExtendWith;
-
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
@@ -33,6 +24,15 @@
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractManager;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.extension.ExtendWith;
+
/**
* Specifies a configuration file to use for unit tests. This configuration file will be loaded once and used for all tests
* executed in the annotated test class unless otherwise specified by {@link #reconfigure()}. When annotated on a test method,
@@ -63,6 +63,14 @@
@ExtendWith(AppenderManagerResolver.class)
@ExtendWith(LoggerResolver.class)
public @interface LoggerContextSource {
+
+ /**
+ * Specifies the LoggerContext name to run under. If no name is given or is an empty string, then
+ * the simple test class name or test method name will be used depending on whether this annotation is applied
+ * to a test class or test method respectively.
+ */
+ String name() default "";
+
/**
* Specifies the name of the configuration file to use for the annotated test.
*/
@@ -89,7 +97,8 @@
boolean v1config() default false;
/**
- * Determines whether to bootstrap a fresh LoggerContextFactory.
+ * Determines whether to bootstrap a fresh LoggerContextFactory. This may be useful when configuring
+ * classes used by {@link org.apache.logging.log4j.core.impl.Log4jContextFactory}.
*/
boolean bootstrap() default false;
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java
index 80f72a8b144..bc0b166af45 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggerResolver.java
@@ -14,9 +14,10 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-
package org.apache.logging.log4j.core.test.junit;
+import java.lang.reflect.Parameter;
+
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.plugins.di.Keys;
@@ -25,8 +26,6 @@
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
-import java.lang.reflect.Parameter;
-
import static org.apache.logging.log4j.core.test.junit.LoggerContextResolver.getLoggerContext;
class LoggerResolver implements ParameterResolver {
@@ -40,9 +39,6 @@ public boolean supportsParameter(final ParameterContext parameterContext, final
public Logger resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
throws ParameterResolutionException {
final LoggerContext loggerContext = getLoggerContext(extensionContext);
- if (loggerContext == null) {
- throw new ParameterResolutionException("No LoggerContext defined");
- }
final String loggerName;
final Parameter parameter = parameterContext.getParameter();
if (Keys.hasName(parameter)) {
@@ -50,6 +46,10 @@ public Logger resolveParameter(final ParameterContext parameterContext, final Ex
} else {
loggerName = extensionContext.getRequiredTestClass().getCanonicalName();
}
- return loggerContext.getLogger(loggerName);
+ final Logger logger = loggerContext.getLogger(loggerName);
+ if (logger == null) {
+ throw new ParameterResolutionException("No Logger defined; name=" + loggerName);
+ }
+ return logger;
}
}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggingTestContext.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggingTestContext.java
new file mode 100644
index 00000000000..b93297fce81
--- /dev/null
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/LoggingTestContext.java
@@ -0,0 +1,258 @@
+/*
+ * 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.test.junit;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.LoggerContextAccessor;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import org.apache.logging.log4j.core.util.NetUtils;
+import org.apache.logging.log4j.plugins.di.DI;
+import org.apache.logging.log4j.plugins.di.Injector;
+import org.apache.logging.log4j.plugins.util.Builder;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Strings;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.opentest4j.AssertionFailedError;
+
+public class LoggingTestContext implements ExtensionContext.Store.CloseableResource, LoggerContextAccessor {
+ public static Configurer configurer() {
+ return new Configurer();
+ }
+
+ private static final String FQCN = LoggingTestContext.class.getName();
+ private final long timeout;
+ private final TimeUnit unit;
+ private final String configurationLocation;
+ private final URI configUri;
+ private final String contextName;
+ private final ReconfigurationPolicy reconfigurationPolicy;
+ private final boolean v1Config;
+ private final boolean bootstrap;
+ private final ClassLoader classLoader;
+ private LoggerContext loggerContext;
+
+ LoggingTestContext(final Configurer configuration) {
+ timeout = configuration.getTimeout();
+ unit = configuration.getUnit();
+ configurationLocation = configuration.getConfigurationLocation();
+ configUri = configuration.getConfigUri();
+ contextName = configuration.getContextName();
+ reconfigurationPolicy = configuration.getReconfigurationPolicy();
+ v1Config = configuration.isV1Config();
+ bootstrap = configuration.isBootstrap();
+ classLoader = configuration.getClassLoader();
+ }
+
+ public void init(final Consumer configurer) {
+ final Log4jContextFactory factory;
+ if (bootstrap) {
+ final Injector injector = DI.createInjector();
+ injector.init();
+ if (configurer != null) {
+ configurer.accept(injector);
+ }
+ factory = injector.getInstance(Log4jContextFactory.class);
+ LogManager.setFactory(factory);
+ } else {
+ factory = (Log4jContextFactory) LogManager.getFactory();
+ }
+ if (v1Config) {
+ System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, configurationLocation);
+ loggerContext = factory.getContext(FQCN, classLoader, null, false);
+ } else if (configUri != null) {
+ loggerContext = factory.getContext(FQCN, classLoader, false, configUri, contextName, configurer);
+ } else if (Strings.isBlank(configurationLocation)) {
+ loggerContext = factory.getContext(FQCN, classLoader, false, null, contextName, configurer);
+ } else if (configurationLocation.contains(",")) {
+ loggerContext = factory.getContext(FQCN, classLoader, null, false, NetUtils.toURIs(configurationLocation), contextName);
+ } else {
+ loggerContext = factory.getContext(FQCN, classLoader, false, NetUtils.toURI(configurationLocation), contextName, configurer);
+ }
+ if (loggerContext == null) {
+ throw new AssertionFailedError("Error creating LoggerContext");
+ }
+ }
+
+ public void beforeEachTest() {
+ if (reconfigurationPolicy == ReconfigurationPolicy.BEFORE_EACH) {
+ loggerContext.reconfigure();
+ }
+ }
+
+ public void afterEachTest() {
+ if (reconfigurationPolicy == ReconfigurationPolicy.AFTER_EACH) {
+ loggerContext.reconfigure();
+ }
+ }
+
+ @Override
+ public LoggerContext getLoggerContext() {
+ return loggerContext;
+ }
+
+ @Override
+ public void close() {
+ if (loggerContext != null) {
+ if (!loggerContext.stop(timeout, unit)) {
+ StatusLogger.getLogger().error("Logger context {} did not shutdown completely after {} {}.",
+ contextName, timeout, unit);
+ }
+ }
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ public TimeUnit getUnit() {
+ return unit;
+ }
+
+ public String getConfigurationLocation() {
+ return configurationLocation;
+ }
+
+ public URI getConfigUri() {
+ return configUri;
+ }
+
+ public String getContextName() {
+ return contextName;
+ }
+
+ public ReconfigurationPolicy getReconfigurationPolicy() {
+ return reconfigurationPolicy;
+ }
+
+ public boolean isV1Config() {
+ return v1Config;
+ }
+
+ public boolean isBootstrap() {
+ return bootstrap;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public static class Configurer implements Builder {
+ private long timeout;
+ private TimeUnit unit = TimeUnit.SECONDS;
+ private String configurationLocation;
+ private URI configUri;
+ private String contextName;
+ private ReconfigurationPolicy reconfigurationPolicy = ReconfigurationPolicy.NEVER;
+ private boolean v1Config;
+ private boolean bootstrap;
+ private ClassLoader classLoader;
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ public Configurer setTimeout(final long timeout, final TimeUnit unit) {
+ this.timeout = timeout;
+ this.unit = unit;
+ return this;
+ }
+
+ public TimeUnit getUnit() {
+ return unit;
+ }
+
+ public String getConfigurationLocation() {
+ return configurationLocation;
+ }
+
+ public Configurer setConfigurationLocation(final String configurationLocation) {
+ this.configurationLocation = configurationLocation;
+ return this;
+ }
+
+ public URI getConfigUri() {
+ return configUri;
+ }
+
+ public Configurer setConfigUri(final URI configUri) {
+ this.configUri = configUri;
+ return this;
+ }
+
+ public String getContextName() {
+ return contextName;
+ }
+
+ public Configurer setContextName(final String contextName) {
+ this.contextName = contextName;
+ return this;
+ }
+
+ public ReconfigurationPolicy getReconfigurationPolicy() {
+ return reconfigurationPolicy;
+ }
+
+ public Configurer setReconfigurationPolicy(final ReconfigurationPolicy reconfigurationPolicy) {
+ this.reconfigurationPolicy = reconfigurationPolicy;
+ return this;
+ }
+
+ public boolean isV1Config() {
+ return v1Config;
+ }
+
+ public Configurer setV1Config(final boolean v1Config) {
+ this.v1Config = v1Config;
+ return this;
+ }
+
+ public boolean isBootstrap() {
+ return bootstrap;
+ }
+
+ public Configurer setBootstrap(final boolean bootstrap) {
+ this.bootstrap = bootstrap;
+ return this;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public Configurer setClassLoader(final ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ return this;
+ }
+
+ @Override
+ public LoggingTestContext build() {
+ if (timeout != 0 && unit == null) {
+ throw new IllegalStateException("No unit specified for timeout value: " + timeout);
+ }
+ if (reconfigurationPolicy == null) {
+ reconfigurationPolicy = ReconfigurationPolicy.NEVER;
+ }
+ return new LoggingTestContext(this);
+ }
+ }
+}
diff --git a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java
index f738e4c3568..e1623a3536b 100644
--- a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java
+++ b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/layout/LogEventFixtures.java
@@ -16,27 +16,26 @@
*/
package org.apache.logging.log4j.core.test.layout;
-import static org.junit.Assert.*;
-
import java.io.IOException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.impl.ContextDataFactory;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.impl.ThrowableProxy;
+import org.apache.logging.log4j.core.ThrowableProxy;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.spi.DefaultThreadContextStack;
+import org.apache.logging.log4j.util.SortedArrayStringMap;
import org.apache.logging.log4j.util.StringMap;
+import static org.junit.Assert.*;
+
public class LogEventFixtures {
/**
* @return a log event that uses all the bells and whistles, features, nooks and crannies
*/
- public static Log4jLogEvent createLogEvent() {
+ public static LogEvent createLogEvent() {
final Marker cMarker = MarkerManager.getMarker("Marker1");
final Marker pMarker1 = MarkerManager.getMarker("ParentMarker1");
final Marker pMarker2 = MarkerManager.getMarker("ParentMarker2");
@@ -55,14 +54,15 @@ public static Log4jLogEvent createLogEvent() {
ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 1"));
ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 2"));
final ThrowableProxy throwableProxy = new ThrowableProxy(ioException);
- final StringMap contextData = ContextDataFactory.createContextData();
+ final StringMap contextData = new SortedArrayStringMap();
contextData.putValue("MDC.A", "A_Value");
contextData.putValue("MDC.B", "B_Value");
final DefaultThreadContextStack contextStack = new DefaultThreadContextStack(true);
contextStack.clear();
contextStack.push("stack_msg1");
contextStack.add("stack_msg2");
- final Log4jLogEvent expected = Log4jLogEvent.newBuilder() //
+ // validate event?
+ return LogEvent.builder() //
.setLoggerName("a.B") //
.setMarker(cMarker) //
.setLoggerFqcn("f.q.c.n") //
@@ -74,15 +74,14 @@ public static Log4jLogEvent createLogEvent() {
.setContextStack(contextStack) //
.setThreadName("MyThreadName") //
.setSource(source) //
- .setTimeMillis(1).build();
- // validate event?
- return expected;
+ .setTimeMillis(1)
+ .get();
}
public static void assertEqualLogEvents(final LogEvent expected, final LogEvent actual, final boolean includeSource,
final boolean includeContext, final boolean includeStacktrace) {
assertEquals(expected.getClass(), actual.getClass());
- assertEquals(includeContext ? expected.getContextData() : ContextDataFactory.createContextData(), actual.getContextData());
+ assertEquals(includeContext ? expected.getContextData() : new SortedArrayStringMap(), actual.getContextData());
assertEquals(expected.getContextStack(), actual.getContextStack());
assertEquals(expected.getLevel(), actual.getLevel());
assertEquals(expected.getLoggerName(), actual.getLoggerName());
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java
index 76c1b64e12b..6742042c6be 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/EventParameterMemoryLeakTest.java
@@ -16,13 +16,6 @@
*/
package org.apache.logging.log4j.core;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.test.CoreLoggerContexts;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junitpioneer.jupiter.SetSystemProperty;
-
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@@ -30,14 +23,22 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.impl.Log4jProperties;
+import org.apache.logging.log4j.core.test.CoreLoggerContexts;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetSystemProperty;
+
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Tag("functional")
-@SetSystemProperty(key = "log4j2.enable.direct.encoders", value = "true")
-@SetSystemProperty(key = "log4j2.configurationFile", value = "EventParameterMemoryLeakTest.xml")
+@SetSystemProperty(key = Log4jProperties.GC_ENABLE_DIRECT_ENCODERS, value = "true")
+@SetSystemProperty(key = Log4jProperties.CONFIG_LOCATION, value = "EventParameterMemoryLeakTest.xml")
public class EventParameterMemoryLeakTest {
@Test
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java
index f51f411bd56..a4b2fcb4452 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LateConfigTest.java
@@ -16,11 +16,6 @@
*/
package org.apache.logging.log4j.core;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNotSame;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
import java.io.File;
import java.util.stream.Stream;
@@ -39,6 +34,8 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
+import static org.junit.jupiter.api.Assertions.*;
+
@Tag("functional")
public class LateConfigTest {
@@ -47,12 +44,13 @@ public class LateConfigTest {
private static final String FQCN = Log4jContextFactory.class.getName();
static Stream selectors() {
- Injector injector = DI.createInjector();
- injector.init();
- return Stream
- .of(new ClassLoaderContextSelector(injector.copy()), new BasicContextSelector(injector.copy()),
- new AsyncLoggerContextSelector(injector.copy()), new BasicAsyncLoggerContextSelector(injector.copy()))
- .map(Log4jContextFactory::new);
+ return Stream.of(ClassLoaderContextSelector.class, BasicContextSelector.class, AsyncLoggerContextSelector.class, BasicAsyncLoggerContextSelector.class)
+ .map(contextSelectorClass -> {
+ Injector inj = DI.createInjector();
+ inj.registerBinding(ContextSelector.KEY, inj.getFactory(contextSelectorClass));
+ inj.init();
+ return inj.getInstance(Log4jContextFactory.class);
+ });
}
@ParameterizedTest
@@ -73,4 +71,3 @@ public void testReconfiguration(final Log4jContextFactory factory) throws Except
assertSame(newConfig, sameConfig, "Configuration should not have been reset");
}
}
-
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
index bec9ab97437..8b2262ff3a0 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventFactoryTest.java
@@ -16,21 +16,21 @@
*/
package org.apache.logging.log4j.core;
+import java.util.List;
+
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.LogEventFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.core.test.junit.Named;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.plugins.Factory;
+import org.apache.logging.log4j.plugins.Inject;
import org.junit.jupiter.api.Test;
-import java.util.List;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -40,7 +40,7 @@
public class LogEventFactoryTest {
@Test
- @LoggerContextSource(value = "log4j2-config.xml")
+ @LoggerContextSource(value = "log4j2-config.xml", bootstrap = true)
public void testEvent(@Named("List") final ListAppender app, final LoggerContext context) {
final org.apache.logging.log4j.Logger logger = context.getLogger("org.apache.test.LogEventFactory");
logger.error("error message");
@@ -52,32 +52,36 @@ public void testEvent(@Named("List") final ListAppender app, final LoggerContext
}
public static class TestLogEventFactory implements LogEventFactory {
- private final ContextDataInjector injector;
+ private final ContextDataInjector contextDataInjector;
+ private final ContextDataFactory contextDataFactory;
- public TestLogEventFactory(final ContextDataInjector injector) {
- this.injector = injector;
+ @Inject
+ public TestLogEventFactory(final ContextDataInjector contextDataInjector,
+ final ContextDataFactory contextDataFactory) {
+ this.contextDataInjector = contextDataInjector;
+ this.contextDataFactory = contextDataFactory;
}
@Override
public LogEvent createEvent(final String loggerName, final Marker marker,
final String fqcn, final Level level, final Message data,
final List properties, final Throwable t) {
- return Log4jLogEvent.newBuilder()
+ return LogEvent.builder()
.setLoggerName("Test")
.setMarker(marker)
.setLoggerFqcn(fqcn)
.setLevel(level)
.setMessage(data)
- .setContextDataInjector(injector)
- .setContextData(injector.injectContextData(properties, ContextDataFactory.createContextData()))
+ .setContextDataInjector(contextDataInjector)
+ .setContextDataFactory(contextDataFactory)
+ .setContextData(properties)
.setThrown(t)
.build();
}
}
@Factory
- public LogEventFactory logEventFactory(final ContextDataInjector injector) {
- return new TestLogEventFactory(injector);
+ public LogEventFactory logEventFactory(final TestLogEventFactory factory) {
+ return factory;
}
}
-
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
index 9561f37b584..2b8768bc772 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LogEventTest.java
@@ -16,18 +16,9 @@
*/
package org.apache.logging.log4j.core;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LoggingException;
-import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.util.FilteredObjectInputStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -41,112 +32,22 @@ public class LogEventTest {
private static Message MESSAGE = new SimpleMessage("This is a test");
private static TestClass TESTER = new TestClass();
- @SuppressWarnings("BanSerializableRead")
- @Test
- public void testSerialization() throws Exception {
- final LogEvent event1 = Log4jLogEvent.newBuilder() //
- .setLoggerName(this.getClass().getName()) //
- .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
- .setLevel(Level.INFO) //
- .setMessage(new SimpleMessage("Hello, world!")) //
- .build();
- final Exception parent = new IllegalStateException("Test");
- final Throwable child = new LoggingException("This is a test", parent);
- final LogEvent event2 = Log4jLogEvent.newBuilder() //
- .setLoggerName(this.getClass().getName()) //
- .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
- .setLevel(Level.INFO) //
- .setMessage(new SimpleMessage("Hello, world!")) //
- .setThrown(child) //
- .build();
-
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(event1);
- oos.writeObject(event2);
-
- final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- final ObjectInputStream ois = new FilteredObjectInputStream(bais);
- try {
- ois.readObject();
- } catch (final IOException ioe) {
- fail("Exception processing event1");
- }
- try {
- ois.readObject();
- } catch (final IOException ioe) {
- fail("Exception processing event2");
- }
- }
-
- @SuppressWarnings("BanSerializableRead")
- @Test
- public void testNanoTimeIsNotSerialized1() throws Exception {
- final LogEvent event1 = Log4jLogEvent.newBuilder() //
- .setLoggerName(this.getClass().getName()) //
- .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
- .setLevel(Level.INFO) //
- .setMessage(new SimpleMessage("Hello, world!")) //
- .setThreadName("this must be initialized or the test fails") //
- .setNanoTime(12345678L) //
- .build();
- final LogEvent copy = new Log4jLogEvent.Builder(event1).build();
-
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(event1);
-
- final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- final ObjectInputStream ois = new FilteredObjectInputStream(bais);
-
- final LogEvent actual = (LogEvent) ois.readObject();
- assertNotEquals(copy, actual, "Different event: nanoTime");
- assertNotEquals(copy.getNanoTime(), actual.getNanoTime(), "Different nanoTime");
- assertEquals(0, actual.getNanoTime(), "deserialized nanoTime is zero");
- }
-
- @SuppressWarnings("BanSerializableRead")
- @Test
- public void testNanoTimeIsNotSerialized2() throws Exception {
- final LogEvent event1 = Log4jLogEvent.newBuilder() //
- .setLoggerName(this.getClass().getName()) //
- .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
- .setLevel(Level.INFO) //
- .setMessage(new SimpleMessage("Hello, world!")) //
- .setThreadId(1) // this must be initialized or the test fails
- .setThreadName("this must be initialized or the test fails") //
- .setThreadPriority(2) // this must be initialized or the test fails
- .setNanoTime(0) //
- .build();
- final LogEvent event2 = new Log4jLogEvent.Builder(event1).build();
-
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- final ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(event1);
-
- final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- final ObjectInputStream ois = new FilteredObjectInputStream(bais);
-
- final LogEvent actual = (LogEvent) ois.readObject();
- assertEquals(event2, actual, "both zero nanoTime");
- }
-
@Test
@Disabled
public void testEquals() {
- final LogEvent event1 = Log4jLogEvent.newBuilder() //
+ final LogEvent event1 = LogEvent.builder() //
.setLoggerName(this.getClass().getName()) //
.setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
.setLevel(Level.INFO) //
.setMessage(new SimpleMessage("Hello, world!")) //
.build();
- final LogEvent event2 = Log4jLogEvent.newBuilder() //
+ final LogEvent event2 = LogEvent.builder() //
.setLoggerName(this.getClass().getName()) //
.setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
.setLevel(Level.INFO) //
.setMessage(new SimpleMessage("Hello, world!")) //
.build();
- final LogEvent event3 = Log4jLogEvent.newBuilder() //
+ final LogEvent event3 = LogEvent.builder() //
.setLoggerName(this.getClass().getName()) //
.setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
.setLevel(Level.INFO) //
@@ -167,9 +68,13 @@ private static class TestClass {
private static final String FQCN = TestClass.class.getName();
public StackTraceElement getEventSource(final String loggerName) {
- final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName)
- .setLoggerFqcn(FQCN).setLevel(Level.INFO).setMessage(MESSAGE).build();
- event.setIncludeLocation(true);
+ final LogEvent event = LogEvent.builder()
+ .setLoggerName(loggerName)
+ .setLoggerFqcn(FQCN)
+ .setLevel(Level.INFO)
+ .setMessage(MESSAGE)
+ .includeLocation(true)
+ .get();
return event.getSource();
}
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
index b1944ed9c92..82bdd2a8c23 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/LoggerSerializationTest.java
@@ -26,7 +26,7 @@ public class LoggerSerializationTest extends AbstractSerializationTest {
@Parameters
protected Stream