From ed4c72e679951fe78fe4121436085444bc87b388 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Tue, 19 Mar 2024 13:25:16 +0100 Subject: [PATCH] Apply suggestions from review of #2374 --- .../apache/logging/log4j/test/TestLogger.java | 10 +- .../apache/logging/log4j/TestProvider.java | 2 +- .../log4j/spi/ThreadContextMapTest.java | 24 ++-- .../logging/log4j/util/ProviderUtilTest.java | 120 ++++++++++++++++-- .../log4j/spi/DefaultThreadContextMap.java | 2 +- .../log4j/spi/NoOpThreadContextMap.java | 3 + .../apache/logging/log4j/spi/Provider.java | 65 ++++------ .../logging/log4j/util/ProviderUtil.java | 46 +++---- 8 files changed, 183 insertions(+), 89 deletions(-) diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java index fc8de75793c..e95f1e9bb67 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestLogger.java @@ -75,18 +75,18 @@ protected void log( sb.append(level.toString()); sb.append(' '); if (location != null) { - sb.append(location.toString()); + sb.append(location); sb.append(' '); } sb.append(message.getFormattedMessage()); final Map mdc = ThreadContext.getImmutableContext(); - if (mdc.size() > 0) { + if (!mdc.isEmpty()) { sb.append(' '); - sb.append(mdc.toString()); + sb.append(mdc); sb.append(' '); } final Object[] params = message.getParameters(); - Throwable t; + final Throwable t; if (throwable == null && params != null && params.length > 0 @@ -99,7 +99,7 @@ protected void log( sb.append(' '); final ByteArrayOutputStream baos = new ByteArrayOutputStream(); t.printStackTrace(new PrintStream(baos)); - sb.append(baos.toString()); + sb.append(baos); } list.add(sb.toString()); // System.out.println(sb.toString()); diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/TestProvider.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/TestProvider.java index 5feb4a1f25e..1aa91ae529d 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/TestProvider.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/TestProvider.java @@ -24,6 +24,6 @@ */ public class TestProvider extends Provider { public TestProvider() { - super(10, "2.6.0", TestLoggerContextFactory.class); + super(5, CURRENT_VERSION, TestLoggerContextFactory.class); } } diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadContextMapTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadContextMapTest.java index 42df896f9ef..f394e71bea0 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadContextMapTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/spi/ThreadContextMapTest.java @@ -29,6 +29,8 @@ class ThreadContextMapTest { + private static final String KEY = "key"; + static Stream defaultMaps() { return Stream.of( new DefaultThreadContextMap(), @@ -49,26 +51,24 @@ static Stream inheritableMaps() { @ParameterizedTest @MethodSource("defaultMaps") void threadLocalNotInheritableByDefault(final ThreadContextMap contextMap) { - contextMap.put("key", "threadLocalNotInheritableByDefault"); - final ExecutorService executorService = Executors.newSingleThreadExecutor(); - try { - assertThat(executorService.submit(() -> contextMap.get("key"))) - .succeedsWithin(Duration.ofSeconds(1)) - .isEqualTo(null); - } finally { - executorService.shutdown(); - } + contextMap.put(KEY, "threadLocalNotInheritableByDefault"); + verifyThreadContextValueFromANewThread(contextMap, null); } @ParameterizedTest @MethodSource("inheritableMaps") void threadLocalInheritableIfConfigured(final ThreadContextMap contextMap) { - contextMap.put("key", "threadLocalInheritableIfConfigured"); + contextMap.put(KEY, "threadLocalInheritableIfConfigured"); + verifyThreadContextValueFromANewThread(contextMap, "threadLocalInheritableIfConfigured"); + } + + private static void verifyThreadContextValueFromANewThread( + final ThreadContextMap contextMap, final String expected) { final ExecutorService executorService = Executors.newSingleThreadExecutor(); try { - assertThat(executorService.submit(() -> contextMap.get("key"))) + assertThat(executorService.submit(() -> contextMap.get(KEY))) .succeedsWithin(Duration.ofSeconds(1)) - .isEqualTo("threadLocalInheritableIfConfigured"); + .isEqualTo(expected); } finally { executorService.shutdown(); } diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ProviderUtilTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ProviderUtilTest.java index c9b59eb8131..8d67050cc2b 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ProviderUtilTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ProviderUtilTest.java @@ -18,29 +18,70 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Properties; +import java.util.regex.Pattern; +import java.util.stream.Stream; import org.apache.logging.log4j.TestProvider; +import org.apache.logging.log4j.spi.Provider; +import org.apache.logging.log4j.test.TestLogger; import org.apache.logging.log4j.test.TestLoggerContextFactory; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; @Execution(ExecutionMode.CONCURRENT) class ProviderUtilTest { - /* - * Force initialization of ProviderUtil#PROVIDERS - */ - static { - ProviderUtil.lazyInit(); + private static final Pattern ERROR_OR_WARNING = Pattern.compile(" (ERROR|WARN) .*", Pattern.DOTALL); + + private static final Provider LOCAL_PROVIDER = new LocalProvider(); + private static final Provider TEST_PROVIDER = new TestProvider(); + + private static final Collection NO_PROVIDERS = Collections.emptyList(); + private static final Collection ONE_PROVIDER = Collections.singleton(TEST_PROVIDER); + private static final Collection TWO_PROVIDERS = Arrays.asList(LOCAL_PROVIDER, TEST_PROVIDER); + + private TestLogger statusLogger; + + @BeforeEach + void setup() { + statusLogger = new TestLogger(); + } + + @Test + void should_have_a_fallback_provider() { + final PropertiesUtil properties = new PropertiesUtil(new Properties()); + assertThat(ProviderUtil.selectProvider(properties, NO_PROVIDERS, statusLogger)) + .as("check selected provider") + .isNotNull(); + // An error for the absence of providers + assertHasErrorOrWarning(statusLogger); + } + + @Test + void should_be_silent_with_a_single_provider() { + final PropertiesUtil properties = new PropertiesUtil(new Properties()); + assertThat(ProviderUtil.selectProvider(properties, ONE_PROVIDER, statusLogger)) + .as("check selected provider") + .isSameAs(TEST_PROVIDER); + assertNoErrorsOrWarnings(statusLogger); } @Test void should_select_provider_with_highest_priority() { final PropertiesUtil properties = new PropertiesUtil(new Properties()); - assertThat(ProviderUtil.selectProvider(properties)) + assertThat(ProviderUtil.selectProvider(properties, TWO_PROVIDERS, statusLogger)) .as("check selected provider") - .isInstanceOf(TestProvider.class); + .isSameAs(TEST_PROVIDER); + // A warning for the presence of multiple providers + assertHasErrorOrWarning(statusLogger); } @Test @@ -48,19 +89,70 @@ void should_recognize_log4j_provider_property() { final Properties map = new Properties(); map.setProperty("log4j.provider", LocalProvider.class.getName()); final PropertiesUtil properties = new PropertiesUtil(map); - assertThat(ProviderUtil.selectProvider(properties)) + assertThat(ProviderUtil.selectProvider(properties, TWO_PROVIDERS, statusLogger)) .as("check selected provider") .isInstanceOf(LocalProvider.class); + assertNoErrorsOrWarnings(statusLogger); } + /** + * Can be removed in the future. + */ @Test void should_recognize_log4j_factory_property() { final Properties map = new Properties(); map.setProperty("log4j2.loggerContextFactory", LocalLoggerContextFactory.class.getName()); final PropertiesUtil properties = new PropertiesUtil(map); - assertThat(ProviderUtil.selectProvider(properties).getLoggerContextFactory()) + assertThat(ProviderUtil.selectProvider(properties, TWO_PROVIDERS, statusLogger) + .getLoggerContextFactory()) .as("check selected logger context factory") .isInstanceOf(LocalLoggerContextFactory.class); + // Deprecation warning + assertHasErrorOrWarning(statusLogger); + } + + /** + * Can be removed in the future. + */ + @Test + void log4j_provider_property_has_priority() { + final Properties map = new Properties(); + map.setProperty("log4j.provider", LocalProvider.class.getName()); + map.setProperty("log4j2.loggerContextFactory", TestLoggerContextFactory.class.getName()); + final PropertiesUtil properties = new PropertiesUtil(map); + assertThat(ProviderUtil.selectProvider(properties, TWO_PROVIDERS, statusLogger)) + .as("check selected provider") + .isInstanceOf(LocalProvider.class); + // Warning + assertHasErrorOrWarning(statusLogger); + } + + static Stream incorrect_configuration_do_not_throw() { + return Stream.of( + Arguments.of("java.lang.String", null), + Arguments.of("non.existent.Provider", null), + // logger context factory without a matching provider + Arguments.of(null, "org.apache.logging.log4j.util.ProviderUtilTest$LocalLoggerContextFactory"), + Arguments.of(null, "java.lang.String"), + Arguments.of(null, "non.existent.LoggerContextFactory")); + } + + @ParameterizedTest + @MethodSource + void incorrect_configuration_do_not_throw(final String provider, final String contextFactory) { + final Properties map = new Properties(); + if (provider != null) { + map.setProperty("log4j.provider", provider); + } + if (contextFactory != null) { + map.setProperty("log4j2.loggerContextFactory", contextFactory); + } + final PropertiesUtil properties = new PropertiesUtil(map); + assertThat(ProviderUtil.selectProvider(properties, ONE_PROVIDER, statusLogger)) + .as("check selected provider") + .isNotNull(); + // Warnings will be present + assertHasErrorOrWarning(statusLogger); } public static class LocalLoggerContextFactory extends TestLoggerContextFactory {} @@ -73,4 +165,14 @@ public LocalProvider() { super(0, CURRENT_VERSION, LocalLoggerContextFactory.class); } } + + private void assertHasErrorOrWarning(final TestLogger statusLogger) { + assertThat(statusLogger.getEntries()).as("check StatusLogger entries").anySatisfy(entry -> assertThat(entry) + .matches(ERROR_OR_WARNING)); + } + + private void assertNoErrorsOrWarnings(final TestLogger statusLogger) { + assertThat(statusLogger.getEntries()).as("check StatusLogger entries").allSatisfy(entry -> assertThat(entry) + .doesNotMatch(ERROR_OR_WARNING)); + } } diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java index b4e0a48bef6..a07992d371f 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java @@ -48,7 +48,7 @@ public DefaultThreadContextMap() { } /** - * @deprecated Since 2.24.0 use the default constructor or {@link NoOpThreadContextMap} instead. + * @deprecated Since 2.24.0. See {@link Provider#getThreadContextMap()} on how to obtain a no-op map. */ @Deprecated public DefaultThreadContextMap(final boolean useMap) { diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java index 155baad10a5..e79626f25a9 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java @@ -24,7 +24,10 @@ * {@code disableThreadContext} is {@code true}. This implementation does nothing. * * @since 2.7 + * @deprecated since 2.24.0. Return the {@value Provider#NO_OP_CONTEXT_MAP} constant in + * {@link Provider#getThreadContextMap()} instead. */ +@Deprecated public class NoOpThreadContextMap implements ThreadContextMap { @Override public void clear() {} diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java index 83dbd76606b..bca1a9ecae3 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/Provider.java @@ -18,6 +18,7 @@ import java.lang.ref.WeakReference; import java.net.URL; +import java.util.Objects; import java.util.Properties; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.simple.SimpleLoggerContextFactory; @@ -39,6 +40,9 @@ *

*/ public class Provider { + /** + * Constant inlined by the compiler + */ protected static final String CURRENT_VERSION = "2.6.0"; /** @@ -68,9 +72,6 @@ public class Provider { */ public static final String PROVIDER_PROPERTY_NAME = "log4j.provider"; - // Bundled context map implementations - private static final String BASE = "org.apache.logging.log4j.internal.map."; - /** * Constant used to disable the {@link ThreadContextMap}. *

@@ -78,7 +79,7 @@ public class Provider { *

* @see #getThreadContextMap */ - public static final String NO_OP_CONTEXT_MAP = BASE + "NoOp"; + protected static final String NO_OP_CONTEXT_MAP = "NoOp"; /** * Constant used to select a web application-safe implementation of {@link ThreadContextMap}. @@ -90,7 +91,7 @@ public class Provider { *

* @see #getThreadContextMap */ - public static final String WEB_APP_CONTEXT_MAP = BASE + "WebApp"; + protected static final String WEB_APP_CONTEXT_MAP = "WebApp"; /** * Constant used to select a copy-on-write implementation of {@link ThreadContextMap}. @@ -99,7 +100,7 @@ public class Provider { *

* @see #getThreadContextMap */ - public static final String COPY_ON_WRITE_CONTEXT_MAP = BASE + "CopyOnWrite"; + protected static final String COPY_ON_WRITE_CONTEXT_MAP = "CopyOnWrite"; /** * Constant used to select a garbage-free implementation of {@link ThreadContextMap}. @@ -112,7 +113,7 @@ public class Provider { *

* @see #getThreadContextMap */ - public static final String GARBAGE_FREE_CONTEXT_MAP = BASE + "GarbageFree"; + protected static final String GARBAGE_FREE_CONTEXT_MAP = "GarbageFree"; // Property keys relevant for context map selection private static final String DISABLE_CONTEXT_MAP = "log4j2.disableThreadContextMap"; @@ -270,11 +271,7 @@ public Class loadLoggerContextFactory() { return null; } - /** - * Extension point for providers to create a {@link LoggerContextFactory}. - * @since 2.24.0 - */ - protected LoggerContextFactory createLoggerContextFactory() { + private LoggerContextFactory createLoggerContextFactory() { final Class factoryClass = loadLoggerContextFactory(); if (factoryClass != null) { try { @@ -289,10 +286,10 @@ protected LoggerContextFactory createLoggerContextFactory() { } /** - * @return A lazily initialized logger context factory + * @return The logger context factory to be used by {@link org.apache.logging.log4j.LogManager}. * @since 2.24.0 */ - public final LoggerContextFactory getLoggerContextFactory() { + public LoggerContextFactory getLoggerContextFactory() { return loggerContextFactoryLazy.get(); } @@ -373,19 +370,17 @@ public Class loadThreadContextMap() { } /** - * Extension point for providers to create a {@link ThreadContextMap} - *

- * The default implementation: - *

+ * Creates a {@link ThreadContextMap} using the legacy {@link #loadThreadContextMap()} and + * {@link #getThreadContextMap()} methods: *
    *
  1. calls {@link #loadThreadContextMap},
  2. *
  3. if the previous call returns {@code null}, it calls {@link #getThreadContextMap} to instantiate one of * the internal implementations,
  4. *
  5. it returns a no-op map otherwise.
  6. *
- * @since 2.24.0 */ - protected ThreadContextMap createThreadContextMap() { + @SuppressWarnings("deprecation") + ThreadContextMap createThreadContextMap() { final Class threadContextMapClass = loadThreadContextMap(); if (threadContextMapClass != null) { try { @@ -432,10 +427,10 @@ void resetThreadContextMap() { } /** - * @return A lazily initialized thread context map. + * @return The thread context map to be used by {@link org.apache.logging.log4j.ThreadContext}. * @since 2.24.0 */ - public final ThreadContextMap getThreadContextMapInstance() { + public ThreadContextMap getThreadContextMapInstance() { return threadContextMapLazy.get(); } @@ -456,25 +451,25 @@ public String toString() { final StringBuilder result = new StringBuilder("Provider '").append(getClass().getName()).append("'"); if (!DEFAULT_PRIORITY.equals(priority)) { - result.append("\n\tpriority = ").append(priority); + result.append("\n\tpriority = ").append(priority); } final String threadContextMap = getThreadContextMap(); if (threadContextMap != null) { - result.append("\n\tthreadContextMap = ").append(threadContextMap); + result.append("\n\tthreadContextMap = ").append(threadContextMap); } final String loggerContextFactory = getClassName(); if (loggerContextFactory != null) { result.append("\n\tloggerContextFactory = ").append(loggerContextFactory); } if (url != null) { - result.append("\n\turl = ").append(url); + result.append("\n\turl = ").append(url); } if (Provider.class.equals(getClass())) { final ClassLoader loader = classLoader.get(); if (loader == null) { - result.append("\n\tclassLoader = null or not reachable"); + result.append("\n\tclassLoader = null or not reachable"); } else { - result.append("\n\tclassLoader = ").append(loader); + result.append("\n\tclassLoader = ").append(loader); } } return result.toString(); @@ -491,18 +486,10 @@ public boolean equals(final Object o) { final Provider provider = (Provider) o; - if (priority != null ? !priority.equals(provider.priority) : provider.priority != null) { - return false; - } - if (className != null ? !className.equals(provider.className) : provider.className != null) { - return false; - } - if (loggerContextFactoryClass != null - ? !loggerContextFactoryClass.equals(provider.loggerContextFactoryClass) - : provider.loggerContextFactoryClass != null) { - return false; - } - return versions != null ? versions.equals(provider.versions) : provider.versions == null; + return Objects.equals(priority, provider.priority) + && Objects.equals(className, provider.className) + && Objects.equals(loggerContextFactoryClass, provider.loggerContextFactoryClass) + && Objects.equals(versions, provider.versions); } @Override 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 ca7c4c71784..a669bf71433 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 @@ -82,8 +82,12 @@ public final class ProviderUtil { private ProviderUtil() {} static void addProvider(final Provider provider) { - PROVIDERS.add(provider); - LOGGER.debug("Loaded Provider {}", provider); + if (validVersion(provider.getVersions())) { + PROVIDERS.add(provider); + LOGGER.debug("Loaded Provider {}", provider); + } else { + LOGGER.warn("Ignoring provider for incompatible version {}:\n{}", provider.getVersions(), provider); + } } /** @@ -99,11 +103,7 @@ static void addProvider(final Provider provider) { static void loadProvider(final URL url, final ClassLoader cl) { try { final Properties props = PropertiesUtil.loadClose(url.openStream(), url); - if (validVersion(props.getProperty(API_VERSION))) { - final Provider provider = new Provider(props, url, cl); - PROVIDERS.add(provider); - LOGGER.debug("Loaded Provider {}", provider); - } + addProvider(new Provider(props, url, cl)); } catch (final IOException e) { LOGGER.error("Unable to open {}", url, e); } @@ -154,13 +154,13 @@ static void lazyInit() { if (PROVIDER == null) { ServiceLoaderUtil.loadServices(Provider.class, MethodHandles.lookup(), false) .filter(provider -> validVersion(provider.getVersions())) - .forEach(PROVIDERS::add); + .forEach(ProviderUtil::addProvider); for (final LoaderUtil.UrlResource resource : LoaderUtil.findUrlResources(PROVIDER_RESOURCE, false)) { loadProvider(resource.getUrl(), resource.getClassLoader()); } - PROVIDER = selectProvider(PropertiesUtil.getProperties()); + PROVIDER = selectProvider(PropertiesUtil.getProperties(), PROVIDERS, LOGGER); } } finally { STARTUP_LOCK.unlock(); @@ -175,7 +175,8 @@ static void lazyInit() { /** * Used to test the public {@link #getProvider()} method. */ - static Provider selectProvider(final PropertiesUtil properties) { + 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); @@ -183,24 +184,25 @@ static Provider selectProvider(final PropertiesUtil properties) { try { selected = LoaderUtil.newInstanceOf(providerClass); } catch (final Exception e) { - LOGGER.error("Unable to create provider {}.\nFalling back to default selection process.", PROVIDER, 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); if (factoryClassName != null) { if (selected != null) { - LOGGER.warn( + statusLogger.warn( "Ignoring {} system property, since {} was set.", FACTORY_PROPERTY_NAME, PROVIDER_PROPERTY_NAME); // 2a. Scan the known providers for one matching the logger context factory class name. } else { - LOGGER.warn( + statusLogger.warn( "Usage of the {} property is deprecated. Use the {} property instead.", FACTORY_PROPERTY_NAME, PROVIDER_PROPERTY_NAME); - for (final Provider provider : PROVIDERS) { + for (final Provider provider : providers) { if (factoryClassName.equals(provider.getClassName())) { selected = provider; break; @@ -209,7 +211,7 @@ static Provider selectProvider(final PropertiesUtil properties) { } // 2b. Instantiate if (selected == null) { - LOGGER.warn( + statusLogger.warn( "No provider found using {} as logger context factory. The factory will be instantiated directly.", factoryClassName); try { @@ -217,14 +219,14 @@ static Provider selectProvider(final PropertiesUtil properties) { if (LoggerContextFactory.class.isAssignableFrom(clazz)) { selected = new Provider(null, Strings.EMPTY, clazz.asSubclass(LoggerContextFactory.class)); } else { - LOGGER.error( + statusLogger.error( "Class {} specified in the {} system property does not extend {}", factoryClassName, FACTORY_PROPERTY_NAME, LoggerContextFactory.class.getName()); } } catch (final Exception e) { - LOGGER.error( + statusLogger.error( "Unable to create class {} specified in the {} system property", factoryClassName, FACTORY_PROPERTY_NAME, @@ -235,22 +237,22 @@ static Provider selectProvider(final PropertiesUtil properties) { // 3. Select a provider automatically. if (selected == null) { final Comparator comparator = Comparator.comparing(Provider::getPriority); - switch (PROVIDERS.size()) { + switch (providers.size()) { case 0: - LOGGER.error("Log4j API could not find a logging provider."); + statusLogger.error("Log4j API could not find a logging provider."); break; case 1: break; default: - LOGGER.warn(PROVIDERS.stream() + statusLogger.warn(providers.stream() .sorted(comparator) .map(Provider::toString) .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).orElse(FALLBACK_PROVIDER); } - LOGGER.info("Using provider:\n{}", selected); + statusLogger.info("Using provider:\n{}", selected); return selected; }