diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java
index b70a4c5e087..d1aaf8db0f7 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/SimpleLoggerContext.java
@@ -17,11 +17,10 @@
package org.apache.logging.log4j.simple;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.PrintStream;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.simple.internal.SimpleProvider;
import org.apache.logging.log4j.spi.AbstractLogger;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.LoggerContext;
@@ -36,10 +35,6 @@ public class SimpleLoggerContext implements LoggerContext {
/** Singleton instance. */
static final SimpleLoggerContext INSTANCE = new SimpleLoggerContext();
- private static final String SYSTEM_OUT = "system.out";
-
- private static final String SYSTEM_ERR = "system.err";
-
/** The default format to use when formatting dates */
protected static final String DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss:SSS zzz";
@@ -79,34 +74,15 @@ public class SimpleLoggerContext implements LoggerContext {
value = "PATH_TRAVERSAL_OUT",
justification = "Opens a file retrieved from configuration (Log4j properties)")
public SimpleLoggerContext() {
- props = new PropertiesUtil("log4j2.simplelog.properties");
-
- showContextMap = props.getBooleanProperty(SYSTEM_PREFIX + "showContextMap", false);
- showLogName = props.getBooleanProperty(SYSTEM_PREFIX + "showlogname", false);
- showShortName = props.getBooleanProperty(SYSTEM_PREFIX + "showShortLogname", true);
- showDateTime = props.getBooleanProperty(SYSTEM_PREFIX + "showdatetime", false);
- final String lvl = props.getStringProperty(SYSTEM_PREFIX + "level");
- defaultLevel = Level.toLevel(lvl, Level.ERROR);
-
- dateTimeFormat = showDateTime
- ? props.getStringProperty(
- SimpleLoggerContext.SYSTEM_PREFIX + "dateTimeFormat", DEFAULT_DATE_TIME_FORMAT)
- : null;
-
- final String fileName = props.getStringProperty(SYSTEM_PREFIX + "logFile", SYSTEM_ERR);
- PrintStream ps;
- if (SYSTEM_ERR.equalsIgnoreCase(fileName)) {
- ps = System.err;
- } else if (SYSTEM_OUT.equalsIgnoreCase(fileName)) {
- ps = System.out;
- } else {
- try {
- ps = new PrintStream(new FileOutputStream(fileName));
- } catch (final FileNotFoundException fnfe) {
- ps = System.err;
- }
- }
- this.stream = ps;
+ final SimpleProvider.Config config = SimpleProvider.Config.INSTANCE;
+ props = config.props;
+ showContextMap = config.showContextMap;
+ showLogName = config.showLogName;
+ showShortName = config.showShortName;
+ showDateTime = config.showDateTime;
+ defaultLevel = config.defaultLevel;
+ dateTimeFormat = config.dateTimeFormat;
+ stream = config.stream;
}
@Override
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/internal/SimpleProvider.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/internal/SimpleProvider.java
new file mode 100644
index 00000000000..e62e2a5c27f
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/internal/SimpleProvider.java
@@ -0,0 +1,119 @@
+/*
+ * 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.simple.internal;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.simple.SimpleLoggerContext;
+import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
+import org.apache.logging.log4j.spi.NoOpThreadContextMap;
+import org.apache.logging.log4j.spi.Provider;
+import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A {@link Provider} implementation to use {@link SimpleLoggerContext}.
+ *
+ * @since 2.24.0
+ */
+@NullMarked
+public final class SimpleProvider extends Provider {
+
+ private final ThreadContextMap threadContextMap;
+
+ public SimpleProvider() {
+ super(null, CURRENT_VERSION);
+ this.threadContextMap =
+ Config.INSTANCE.showContextMap ? super.getThreadContextMapInstance() : NoOpThreadContextMap.INSTANCE;
+ }
+
+ @Override
+ public LoggerContextFactory getLoggerContextFactory() {
+ return SimpleLoggerContextFactory.INSTANCE;
+ }
+
+ @Override
+ public ThreadContextMap getThreadContextMapInstance() {
+ return threadContextMap;
+ }
+
+ public static final class Config {
+
+ /** The default format to use when formatting dates */
+ private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy/MM/dd HH:mm:ss:SSS zzz";
+
+ /** All system properties used by SimpleLog
start with this */
+ private static final String SYSTEM_PREFIX = "org.apache.logging.log4j.simplelog.";
+
+ private static final String SYSTEM_OUT = "system.out";
+
+ private static final String SYSTEM_ERR = "system.err";
+
+ public static final Config INSTANCE = new Config();
+
+ public final PropertiesUtil props;
+
+ public final boolean showContextMap;
+
+ public final boolean showLogName;
+
+ public final boolean showShortName;
+
+ public final boolean showDateTime;
+
+ public final Level defaultLevel;
+
+ public final @Nullable String dateTimeFormat;
+
+ public final PrintStream stream;
+
+ private Config() {
+ props = new PropertiesUtil("log4j2.simplelog.properties");
+
+ showContextMap = props.getBooleanProperty(SYSTEM_PREFIX + "showContextMap", false);
+ showLogName = props.getBooleanProperty(SYSTEM_PREFIX + "showlogname", false);
+ showShortName = props.getBooleanProperty(SYSTEM_PREFIX + "showShortLogname", true);
+ showDateTime = props.getBooleanProperty(SYSTEM_PREFIX + "showdatetime", false);
+ final String lvl = props.getStringProperty(SYSTEM_PREFIX + "level");
+ defaultLevel = Level.toLevel(lvl, Level.ERROR);
+
+ dateTimeFormat = showDateTime
+ ? props.getStringProperty(SYSTEM_PREFIX + "dateTimeFormat", DEFAULT_DATE_TIME_FORMAT)
+ : null;
+
+ final String fileName = props.getStringProperty(SYSTEM_PREFIX + "logFile", SYSTEM_ERR);
+ PrintStream ps;
+ if (SYSTEM_ERR.equalsIgnoreCase(fileName)) {
+ ps = System.err;
+ } else if (SYSTEM_OUT.equalsIgnoreCase(fileName)) {
+ ps = System.out;
+ } else {
+ try {
+ ps = new PrintStream(new FileOutputStream(fileName));
+ } catch (final FileNotFoundException fnfe) {
+ ps = System.err;
+ }
+ }
+ this.stream = ps;
+ }
+ }
+}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/simple/package-info.java b/log4j-api/src/main/java/org/apache/logging/log4j/simple/package-info.java
index 15801ad9d7a..1481df9462e 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/simple/package-info.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/simple/package-info.java
@@ -20,7 +20,7 @@
* Providers are able to be loaded at runtime.
*/
@Export
-@Version("2.20.2")
+@Version("2.24.0")
package org.apache.logging.log4j.simple;
import org.osgi.annotation.bundle.Export;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
index c02526b4a0e..2b74606f081 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
@@ -16,7 +16,6 @@
*/
package org.apache.logging.log4j.util;
-import static org.apache.logging.log4j.LogManager.FACTORY_PROPERTY_NAME;
import static org.apache.logging.log4j.spi.Provider.PROVIDER_PROPERTY_NAME;
import aQute.bnd.annotation.Cardinality;
@@ -34,10 +33,10 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
+import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
+import org.apache.logging.log4j.simple.internal.SimpleProvider;
import org.apache.logging.log4j.spi.LoggerContextFactory;
-import org.apache.logging.log4j.spi.NoOpThreadContextMap;
import org.apache.logging.log4j.spi.Provider;
import org.apache.logging.log4j.status.StatusLogger;
@@ -72,19 +71,17 @@ public final class ProviderUtil {
*/
static final Lock STARTUP_LOCK = new ReentrantLock();
- private static final String API_VERSION = "Log4jAPIVersion";
private static final String[] COMPATIBLE_API_VERSIONS = {"2.6.0"};
private static final Logger LOGGER = StatusLogger.getLogger();
private static volatile Provider PROVIDER;
- private static final Provider FALLBACK_PROVIDER = new SimpleProvider();
private ProviderUtil() {}
static void addProvider(final Provider provider) {
if (validVersion(provider.getVersions())) {
PROVIDERS.add(provider);
- LOGGER.debug("Loaded Provider {}", provider);
+ LOGGER.debug("Loaded provider:\n{}", provider);
} else {
LOGGER.warn("Ignoring provider for incompatible version {}:\n{}", provider.getVersions(), provider);
}
@@ -100,6 +97,7 @@ static void addProvider(final Provider provider) {
@SuppressFBWarnings(
value = "URLCONNECTION_SSRF_FD",
justification = "Uses a fixed URL that ends in 'META-INF/log4j-provider.properties'.")
+ @SuppressWarnings("deprecation")
static void loadProvider(final URL url, final ClassLoader cl) {
try {
final Properties props = PropertiesUtil.loadClose(url.openStream(), url);
@@ -178,32 +176,37 @@ static void lazyInit() {
/**
* Used to test the public {@link #getProvider()} method.
*/
+ @SuppressWarnings("deprecation")
static Provider selectProvider(
final PropertiesUtil properties, final Collection providers, final Logger statusLogger) {
Provider selected = null;
// 1. Select provider using "log4j.provider" property
final String providerClass = properties.getStringProperty(PROVIDER_PROPERTY_NAME);
if (providerClass != null) {
- try {
- selected = LoaderUtil.newInstanceOf(providerClass);
- } catch (final Exception e) {
- statusLogger.error(
- "Unable to create provider {}.\nFalling back to default selection process.", PROVIDER, e);
+ if (SimpleProvider.class.getName().equals(providerClass)) {
+ selected = new SimpleProvider();
+ } else {
+ try {
+ selected = LoaderUtil.newInstanceOf(providerClass);
+ } catch (final Exception e) {
+ statusLogger.error(
+ "Unable to create provider {}.\nFalling back to default selection process.", PROVIDER, e);
+ }
}
}
// 2. Use deprecated "log4j2.loggerContextFactory" property to choose the provider
- final String factoryClassName = properties.getStringProperty(FACTORY_PROPERTY_NAME);
+ final String factoryClassName = properties.getStringProperty(LogManager.FACTORY_PROPERTY_NAME);
if (factoryClassName != null) {
if (selected != null) {
statusLogger.warn(
"Ignoring {} system property, since {} was set.",
- FACTORY_PROPERTY_NAME,
+ LogManager.FACTORY_PROPERTY_NAME,
PROVIDER_PROPERTY_NAME);
// 2a. Scan the known providers for one matching the logger context factory class name.
} else {
statusLogger.warn(
"Usage of the {} property is deprecated. Use the {} property instead.",
- FACTORY_PROPERTY_NAME,
+ LogManager.FACTORY_PROPERTY_NAME,
PROVIDER_PROPERTY_NAME);
for (final Provider provider : providers) {
if (factoryClassName.equals(provider.getClassName())) {
@@ -225,14 +228,14 @@ static Provider selectProvider(
statusLogger.error(
"Class {} specified in the {} system property does not extend {}",
factoryClassName,
- FACTORY_PROPERTY_NAME,
+ LogManager.FACTORY_PROPERTY_NAME,
LoggerContextFactory.class.getName());
}
} catch (final Exception e) {
statusLogger.error(
"Unable to create class {} specified in the {} system property",
factoryClassName,
- FACTORY_PROPERTY_NAME,
+ LogManager.FACTORY_PROPERTY_NAME,
e);
}
}
@@ -253,7 +256,7 @@ static Provider selectProvider(
.collect(Collectors.joining("\n", "Log4j API found multiple logging providers:\n", "")));
break;
}
- selected = providers.stream().max(comparator).orElse(FALLBACK_PROVIDER);
+ selected = providers.stream().max(comparator).orElseGet(SimpleProvider::new);
}
statusLogger.info("Using provider:\n{}", selected);
return selected;
@@ -271,10 +274,4 @@ private static boolean validVersion(final String version) {
}
return false;
}
-
- private static final class SimpleProvider extends Provider {
- private SimpleProvider() {
- super(null, CURRENT_VERSION, SimpleLoggerContextFactory.class, NoOpThreadContextMap.class);
- }
- }
}