From 423876f9715ffe70a25a20b161a2a97b3158e58b Mon Sep 17 00:00:00 2001
From: "Piotr P. Karwasz"
Date: Mon, 9 Sep 2024 11:22:05 +0200
Subject: [PATCH] Split new `jul-to-log4j` artifact from `log4j-jul`
This splits `log4j-jul` into two artifacts:
- `jul-to-log4j` that contains a `j.u.l.LogManager` implementation, but
does not depend on Log4j Core.
- `log4j-jul` that contains a `j.u.l.Handler` implementation and depends
on Log4j Core.
We also update the `j.u.l.LogManager` implementation to:
- implement methods introduced in Java 9,
- remove methods deprecated in Java 9,
- remove the support for `j.u.l.Filter`.
---
jul-to-log4j/pom.xml | 133 +++++
.../logging/jul/tolog4j}/LevelTranslator.java | 5 +-
.../logging/jul/tolog4j}/LogManager.java | 48 +-
.../jul/tolog4j/internal/ApiLogger.java | 74 +++
.../tolog4j/internal}/ApiLoggerAdapter.java | 5 +-
.../internal}/DefaultLevelConverter.java | 4 +-
.../jul/tolog4j/internal}/JulProperties.java | 4 +-
.../jul/tolog4j/internal}/NoOpLogger.java | 4 +-
.../logging/jul/tolog4j/package-info.java | 22 +
.../tolog4j/spi/AbstractLoggerAdapter.java | 67 +++
.../jul/tolog4j/spi}/LevelConverter.java | 6 +-
.../logging/jul/tolog4j/spi/package-info.java | 25 +
.../jul/tolog4j/support/AbstractLogger.java | 441 +++++++++++++++++
.../jul/tolog4j/support/package-info.java | 26 +
.../META-INF/log4j/propertyMapping.json | 0
.../tolog4j}/test/AsyncLoggerThreadsTest.java | 2 +-
.../BracketInNotInterpolatedMessageTest.java | 4 +-
.../tolog4j/test/CallerInformationTest.java | 162 +++++++
.../test/JavaLevelTranslatorTest.java | 4 +-
.../jul/tolog4j}/test/JulTestProperties.java | 2 +-
.../test/Log4jLevelTranslatorTest.java | 4 +-
.../jul/tolog4j/test/ResourceBundleTest.java | 91 ++++
.../tolog4j/test/internal}/ApiLoggerTest.java | 32 +-
...aultLevelConverterCustomJulLevelsTest.java | 8 +-
.../internal}/DefaultLevelConverterTest.java | 9 +-
.../test/support}/AbstractLoggerTest.java | 53 +-
.../test/support/CustomLoggerAdapterTest.java | 95 ++++
.../test/resources/CallerInformationTest.xml | 42 ++
.../resources/ResourceBundleTest.properties | 21 +
.../src/test/resources/ResourceBundleTest.xml | 23 +-
.../src/test/resources/log4j2-test.xml | 46 ++
log4j-jul/pom.xml | 92 +---
.../log4j/jul/AbstractLoggerAdapter.java | 39 --
.../apache/logging/log4j/jul/ApiLogger.java | 325 -------------
.../apache/logging/log4j/jul/CoreLogger.java | 78 ---
.../logging/log4j/jul/CoreLoggerAdapter.java | 41 --
.../logging/log4j/jul/Log4jBridgeHandler.java | 257 +++-------
.../logging/log4j/jul/WrappedLogger.java | 67 ---
.../jul/internal/JulLevelPropagator.java | 100 ++++
.../logging/log4j/jul/package-info.java | 2 +-
.../log4j/jul/spi/LevelChangePropagator.java | 45 ++
.../logging/log4j/jul/spi/package-info.java | 25 +
.../log4j/jul/Log4jBridgeHandlerTest.java | 269 ++++++++++
.../jul/internal/JulLevelPropagatorTest.java | 67 +++
.../log4j/jul/test/CallerInformationTest.java | 78 ---
.../log4j/jul/test/CoreLoggerTest.java | 120 -----
.../jul/test/Log4jBridgeHandlerTest.java | 459 ------------------
.../test/resources/log4j2-julBridge-test.xml | 39 --
log4j-jul/src/test/resources/log4j2-test.xml | 40 +-
.../test/resources/logging-test.properties | 22 +-
pom.xml | 13 +-
.../antora/modules/ROOT/pages/components.adoc | 29 +-
.../antora/modules/ROOT/pages/log4j-jul.adoc | 251 ++++++----
.../ROOT/pages/manual/installation.adoc | 4 +-
.../partials/components/jul-to-log4j.adoc | 41 ++
.../properties-log4j-jul.adoc | 54 ++-
56 files changed, 2224 insertions(+), 1795 deletions(-)
create mode 100644 jul-to-log4j/pom.xml
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j}/LevelTranslator.java (93%)
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j}/LogManager.java (66%)
create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal}/ApiLoggerAdapter.java (88%)
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal}/DefaultLevelConverter.java (97%)
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal}/JulProperties.java (86%)
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal}/NoOpLogger.java (98%)
create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/package-info.java
create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java
rename {log4j-jul/src/main/java/org/apache/logging/log4j/jul => jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi}/LevelConverter.java (87%)
create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java
create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java
create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java
rename {log4j-jul => jul-to-log4j}/src/main/resources/META-INF/log4j/propertyMapping.json (100%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j}/test/AsyncLoggerThreadsTest.java (98%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j}/test/BracketInNotInterpolatedMessageTest.java (95%)
create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j}/test/JavaLevelTranslatorTest.java (96%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j}/test/JulTestProperties.java (95%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j}/test/Log4jLevelTranslatorTest.java (95%)
create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul/test => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal}/ApiLoggerTest.java (72%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul/test => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal}/DefaultLevelConverterCustomJulLevelsTest.java (96%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul/test => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal}/DefaultLevelConverterTest.java (81%)
rename {log4j-jul/src/test/java/org/apache/logging/log4j/jul/test => jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support}/AbstractLoggerTest.java (76%)
create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java
create mode 100644 jul-to-log4j/src/test/resources/CallerInformationTest.xml
create mode 100644 jul-to-log4j/src/test/resources/ResourceBundleTest.properties
rename log4j-jul/src/test/resources/log4j2-calling-class.xml => jul-to-log4j/src/test/resources/ResourceBundleTest.xml (68%)
create mode 100644 jul-to-log4j/src/test/resources/log4j2-test.xml
delete mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/AbstractLoggerAdapter.java
delete mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLogger.java
delete mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/CoreLogger.java
delete mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/CoreLoggerAdapter.java
delete mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/WrappedLogger.java
create mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/internal/JulLevelPropagator.java
create mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/spi/LevelChangePropagator.java
create mode 100644 log4j-jul/src/main/java/org/apache/logging/log4j/jul/spi/package-info.java
create mode 100644 log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jBridgeHandlerTest.java
create mode 100644 log4j-jul/src/test/java/org/apache/logging/log4j/jul/internal/JulLevelPropagatorTest.java
delete mode 100644 log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CallerInformationTest.java
delete mode 100644 log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CoreLoggerTest.java
delete mode 100644 log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jBridgeHandlerTest.java
delete mode 100644 log4j-jul/src/test/resources/log4j2-julBridge-test.xml
create mode 100644 src/site/antora/modules/ROOT/partials/components/jul-to-log4j.adoc
diff --git a/jul-to-log4j/pom.xml b/jul-to-log4j/pom.xml
new file mode 100644
index 00000000000..9e1842005f7
--- /dev/null
+++ b/jul-to-log4j/pom.xml
@@ -0,0 +1,133 @@
+
+
+
+ 4.0.0
+
+ org.apache.logging.log4j
+ log4j
+ ${revision}
+ ../log4j-parent
+
+
+ jul-to-log4j
+ Apache Log4j JUL LogManager
+ A `java.util.logging` LogManager that forwards events to the Log4j API.
+
+
+
+
+
+ org.jspecify.*;resolution:=optional
+
+
+
+ org.jspecify;transitive=false
+
+
+
+
+
+
+ org.apache.logging.log4j
+ log4j-api
+
+
+
+ org.apache.logging.log4j
+ log4j-kit
+
+
+
+ org.assertj
+ assertj-core
+ test
+
+
+
+ org.hamcrest
+ hamcrest
+ test
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.apache.logging.log4j
+ log4j-async-logger
+ test
+
+
+
+ org.apache.logging.log4j
+ log4j-core
+ test
+
+
+
+ org.apache.logging.log4j
+ log4j-core-test
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ true
+
+ -Xms256m -Xmx1024m
+ 1
+ false
+
+
+
+
+ org.apache.maven.surefire
+ surefire-junit47
+ ${surefire.version}
+
+
+
+
+ default-test
+
+ test
+
+ test
+
+
+
+ org.apache.logging.jul.tolog4j.LogManager
+
+
+
+
+
+
+
+
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LevelTranslator.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java
similarity index 93%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/LevelTranslator.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java
index cc6ea5168bf..142b19fe759 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LevelTranslator.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java
@@ -14,8 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j;
+import org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter;
+import org.apache.logging.jul.tolog4j.internal.JulProperties;
+import org.apache.logging.jul.tolog4j.spi.LevelConverter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.kit.env.PropertyEnvironment;
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java
similarity index 66%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java
index b92d87bdf8c..6e105aa679f 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LogManager.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java
@@ -14,36 +14,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
-import org.apache.logging.log4j.LoggingException;
+import org.apache.logging.jul.tolog4j.internal.ApiLoggerAdapter;
+import org.apache.logging.jul.tolog4j.internal.JulProperties;
+import org.apache.logging.jul.tolog4j.internal.NoOpLogger;
+import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
import org.apache.logging.log4j.kit.env.PropertyEnvironment;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;
/**
- * Log4j implementation of {@link java.util.logging.LogManager}. Note that the system property
- * {@code java.util.logging.manager} must be set to {@code org.apache.logging.log4j.jul.LogManager} in order to use
- * this adaptor. This LogManager requires the {@code log4j-api} library to be available. If {@code log4j-core} is
- * also available, then more features of {@link java.util.logging.Logger} are supported.
- *
- *
To override the default {@link AbstractLoggerAdapter} that is used, specify the Log4j property
- * {@code log4j.jul.LoggerAdapter} and set it to the fully qualified class name of a custom
- * implementation. All implementations must have a default constructor.
+ * Log4j implementation of {@link java.util.logging.LogManager}.
+ *
+ * Note that the system property {@code java.util.logging.manager} must be set to
+ * {@code org.apache.logging.jul.tolog4j.LogManager} in order to use this adaptor.
+ * This LogManager requires the {@code log4j-api} library to be available.
+ *
+ *
+ * To override the default {@link AbstractLoggerAdapter} that is used, specify the Log4j property
+ * {@code log4j.jul.LoggerAdapter} and set it to the fully qualified class name of a custom
+ * implementation.
+ * All implementations must have a default constructor.
+ *
*
* @since 2.1
*/
public class LogManager extends java.util.logging.LogManager {
private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
- private static final String CORE_LOGGER_CLASS_NAME = "org.apache.logging.log4j.core.Logger";
- private static final String CORE_LOGGER_ADAPTER_CLASS_NAME = "org.apache.logging.log4j.jul.CoreLoggerAdapter";
- private static final String API_LOGGER_ADAPTER_CLASS_NAME = "org.apache.logging.log4j.jul.ApiLoggerAdapter";
private final AbstractLoggerAdapter loggerAdapter;
// Contains the set of logger names that are actively being requested using getLogger.
private final ThreadLocal> recursive = ThreadLocal.withInitial(HashSet::new);
@@ -62,21 +66,9 @@ public LogManager() {
}
}
if (adapter == null) {
- // default adapter
- String adapterClassName;
- try {
- // find out if log4j-core is available
- LoaderUtil.loadClass(CORE_LOGGER_CLASS_NAME);
- adapterClassName = CORE_LOGGER_ADAPTER_CLASS_NAME;
- } catch (final ClassNotFoundException ignored) {
- adapterClassName = API_LOGGER_ADAPTER_CLASS_NAME;
- }
- LOGGER.debug("Attempting to use {}", adapterClassName);
- try {
- adapter = LoaderUtil.newCheckedInstanceOf(adapterClassName, AbstractLoggerAdapter.class);
- } catch (final Exception e) {
- throw LOGGER.throwing(new LoggingException(e));
- }
+ // Use API by default
+ // See https://github.com/apache/logging-log4j2/issues/2353
+ adapter = new ApiLoggerAdapter();
}
loggerAdapter = adapter;
LOGGER.info("Registered Log4j as the java.util.logging.LogManager.");
diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java
new file mode 100644
index 00000000000..bde8a191009
--- /dev/null
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jul.tolog4j.internal;
+
+import java.util.logging.Filter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.support.AbstractLogger;
+import org.apache.logging.log4j.spi.ExtendedLogger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Implementation of {@link java.util.logging.Logger} that ignores all method calls that do not have an equivalent in
+ * the Log4j API.
+ */
+public class ApiLogger extends AbstractLogger {
+
+ private static final String MUTATOR_DISABLED =
+ """
+ Ignoring call to `j.ul.Logger.{}()`, since the Log4j API does not provide methods to modify the underlying implementation.
+ To modify the configuration using JUL, use an `AbstractLoggerAdapter` appropriate for your logging implementation.
+ See https://logging.apache.org/log4j/3.x/log4j-jul.html#log4j.jul.loggerAdapter for more information.""";
+ private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+ public ApiLogger(ExtendedLogger logger) {
+ super(logger);
+ }
+
+ @Override
+ public void setFilter(Filter newFilter) throws SecurityException {
+ LOGGER.warn(MUTATOR_DISABLED, "setFilter");
+ }
+
+ @Override
+ public void setLevel(Level newLevel) throws SecurityException {
+ LOGGER.warn(MUTATOR_DISABLED, "setLevel");
+ }
+
+ @Override
+ public void addHandler(Handler handler) throws SecurityException {
+ LOGGER.warn(MUTATOR_DISABLED, "addHandler");
+ }
+
+ @Override
+ public void removeHandler(Handler handler) throws SecurityException {
+ LOGGER.warn(MUTATOR_DISABLED, "removeHandler");
+ }
+
+ @Override
+ public void setUseParentHandlers(boolean useParentHandlers) {
+ LOGGER.warn(MUTATOR_DISABLED, "setUseParentHandlers");
+ }
+
+ @Override
+ public void setParent(Logger parent) {
+ throw new UnsupportedOperationException(
+ ApiLogger.class.getSimpleName() + " does not support `j.u.l.Logger#setParent()`.");
+ }
+}
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLoggerAdapter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java
similarity index 88%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLoggerAdapter.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java
index 03f994c68b8..6e6778f9e2d 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLoggerAdapter.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java
@@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j.internal;
import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.message.MessageFormatMessageFactory;
import org.apache.logging.log4j.spi.LoggerContext;
@@ -32,7 +33,7 @@ public class ApiLoggerAdapter extends AbstractLoggerAdapter {
private static final MessageFactory MESSAGE_FACTORY = new MessageFormatMessageFactory();
@Override
- protected Logger newLogger(final String name, final LoggerContext context) {
+ public Logger newLogger(final String name, final LoggerContext context) {
return new ApiLogger(context.getLogger(name, MESSAGE_FACTORY));
}
}
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/DefaultLevelConverter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java
similarity index 97%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/DefaultLevelConverter.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java
index 0a6bdbf6aba..9a8ed846b55 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/DefaultLevelConverter.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j.internal;
import java.util.ArrayList;
import java.util.Collections;
@@ -24,6 +24,8 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.apache.logging.jul.tolog4j.LevelTranslator;
+import org.apache.logging.jul.tolog4j.spi.LevelConverter;
import org.apache.logging.log4j.Level;
/**
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/JulProperties.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java
similarity index 86%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/JulProperties.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java
index ec5a4af0790..1b500b678bc 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/JulProperties.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java
@@ -14,8 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j.internal;
+import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
+import org.apache.logging.jul.tolog4j.spi.LevelConverter;
import org.apache.logging.log4j.kit.env.Log4jProperty;
import org.jspecify.annotations.Nullable;
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/NoOpLogger.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java
similarity index 98%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/NoOpLogger.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java
index 2ed1c4f0289..879d19abb43 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/NoOpLogger.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j.internal;
import java.util.ResourceBundle;
import java.util.function.Supplier;
@@ -27,7 +27,7 @@
*/
public class NoOpLogger extends Logger {
- protected NoOpLogger(final String name) {
+ public NoOpLogger(final String name) {
super(name, null);
}
diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/package-info.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/package-info.java
new file mode 100644
index 00000000000..d0fc9b2d63e
--- /dev/null
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+@Export
+@Version("3.0.0")
+package org.apache.logging.jul.tolog4j;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java
new file mode 100644
index 00000000000..8c43dc8a1a2
--- /dev/null
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java
@@ -0,0 +1,67 @@
+/*
+ * 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.jul.tolog4j.spi;
+
+import java.util.logging.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.StackLocatorUtil;
+
+/**
+ * Abstract Logger registry.
+ *
+ * JUL contains methods, such as {@link Logger#setLevel}, which modify the configuration of the logging backend.
+ * To fully implement all {@code Logger} methods, we need to provide a different {@code Logger} implementation
+ * for each Log4j API implementation.
+ *
+ *
+ * Older Log4j versions provided an alternative {@code CoreLoggerAdapter} implementation that supported
+ * the modification of Log4j Core configuration using JUL.
+ *
+ * Since version 2.24.0, however, this implementation was deprecated for removal.
+ * If you wish to enable this feature again, you need to implement this class and provide its FQCN
+ * as {@code log4j.jul.loggerAdapter} configuration property.
+ *
+ *
+ * Implementation note: since version 3.0.0, this interface was moved to a new package.
+ *
+ * Each implementation should provide this method.
+ *
+ */
+ @Override
+ public abstract Logger newLogger(String name, LoggerContext context);
+
+ /**
+ * Provides the most appropriate {@link LoggerContext} for the caller.
+ */
+ @Override
+ public LoggerContext getContext() {
+ return getContext(
+ LogManager.getFactory().isClassLoaderDependent()
+ ? StackLocatorUtil.getCallerClass(java.util.logging.LogManager.class)
+ : null);
+ }
+}
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LevelConverter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java
similarity index 87%
rename from log4j-jul/src/main/java/org/apache/logging/log4j/jul/LevelConverter.java
rename to jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java
index d9d26116329..489477ebaa9 100644
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/LevelConverter.java
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java
@@ -14,13 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul;
+package org.apache.logging.jul.tolog4j.spi;
+import org.apache.logging.jul.tolog4j.internal.JulProperties;
import org.apache.logging.log4j.Level;
/**
* Strategy interface to convert between custom Log4j {@link Level Levels} and JUL
* {@link java.util.logging.Level Levels}.
+ *
+ * Implementation note: since version 3.0.0, this interface was moved to a new package.
+ *
*
* @see JulProperties#levelConverter()
* @since 2.1
diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java
new file mode 100644
index 00000000000..b7eb30cbacc
--- /dev/null
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/**
+ * Contains interfaces an abstract classes to extend the functionality of Log4j JUL Adapter.
+ */
+@Export
+@Version("3.0.0")
+package org.apache.logging.jul.tolog4j.spi;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java
new file mode 100644
index 00000000000..f91812b45b6
--- /dev/null
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java
@@ -0,0 +1,441 @@
+/*
+ * 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.jul.tolog4j.support;
+
+import static org.apache.logging.log4j.spi.AbstractLogger.ENTRY_MARKER;
+import static org.apache.logging.log4j.spi.AbstractLogger.EXIT_MARKER;
+import static org.apache.logging.log4j.spi.AbstractLogger.THROWING_MARKER;
+
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.util.logging.Filter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.LevelTranslator;
+import org.apache.logging.log4j.BridgeAware;
+import org.apache.logging.log4j.LogBuilder;
+import org.apache.logging.log4j.message.DefaultFlowMessageFactory;
+import org.apache.logging.log4j.message.LocalizedMessage;
+import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.message.MessageFactory;
+import org.apache.logging.log4j.spi.ExtendedLogger;
+
+/**
+ * Log4j API implementation of the JUL {@link Logger} class.
+ *
+ * Note that this implementation does not use the {@link java.util.logging.Handler} class.
+ * Instead,
+ * logging is delegated to the underlying Log4j {@link org.apache.logging.log4j.Logger}
+ * which may be implemented in one of many different ways.
+ * Consult the documentation for your Log4j API Provider for more details.
+ *
+ *
+ * Note that the methods {@link #getParent()} and mutator methods such as {@link #setLevel(java.util.logging.Level)}
+ * must be provided by implementations of this class.
+ * The default {@link org.apache.logging.jul.tolog4j.internal.ApiLogger} implementations just ignores them.
+ * If you need support for these methods, then you'll need to provide your own
+ * {@link org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter}.
+ *
+ *
+ * @since 3.0.0
+ */
+public abstract class AbstractLogger extends Logger {
+
+ private final ExtendedLogger logger;
+ private static final String FQCN = AbstractLogger.class.getName();
+
+ protected AbstractLogger(final ExtendedLogger logger) {
+ super(logger.getName(), null);
+ final Level javaLevel = LevelTranslator.toJavaLevel(logger.getLevel());
+ super.setLevel(javaLevel);
+ this.logger = logger;
+ }
+
+ @Override
+ public void log(final LogRecord record) {
+ final org.apache.logging.log4j.Level level = LevelTranslator.toLevel(record.getLevel());
+ final Object[] parameters = record.getParameters();
+ final MessageFactory messageFactory = logger.getMessageFactory();
+ final Message message = parameters == null
+ ? messageFactory.newMessage(record.getMessage()) /* LOG4J2-1251: not formatted case */
+ : messageFactory.newMessage(record.getMessage(), parameters);
+ final Throwable thrown = record.getThrown();
+ logger.logIfEnabled(FQCN, level, null, message, thrown);
+ }
+
+ //
+ // Methods
+
+ @Override
+ public abstract void setFilter(Filter newFilter) throws SecurityException;
+
+ @Override
+ public abstract void setLevel(Level newLevel) throws SecurityException;
+
+ @Override
+ public abstract void addHandler(Handler handler) throws SecurityException;
+
+ @Override
+ public abstract void removeHandler(Handler handler) throws SecurityException;
+
+ @Override
+ public abstract void setUseParentHandlers(boolean useParentHandlers);
+
+ @Override
+ public abstract void setParent(Logger parent);
+
+ @Override
+ public Filter getFilter() {
+ return null;
+ }
+
+ /**
+ * Returns the configured level of a logger.
+ *
+ * Implementation note: this method returns the level explicitly configured
+ * in the Log4j API logging implementation and is implementation specific.
+ * The default implementation always returns {@code null}.
+ *
+ *
+ * To test if a logger is enabled for a specific logging level, i.e. to test its effective
+ * level, use {@link Logger#isLoggable(Level)}.
+ *
+ * @see #isLoggable(Level)
+ */
+ @Override
+ public Level getLevel() {
+ return null;
+ }
+
+ @Override
+ public Handler[] getHandlers() {
+ return new Handler[0];
+ }
+
+ @Override
+ public boolean getUseParentHandlers() {
+ return false;
+ }
+
+ @Override
+ public Logger getParent() {
+ return null;
+ }
+
+ //
+
+ //
+ // Implementation of methods used for logging
+
+ @Override
+ public boolean isLoggable(final Level level) {
+ return logger.isEnabled(LevelTranslator.toLevel(level));
+ }
+
+ @Override
+ public String getName() {
+ return logger.getName();
+ }
+
+ private org.apache.logging.log4j.util.Supplier toLog4jSupplier(Supplier msgSupplier) {
+ return msgSupplier::get;
+ }
+
+ private org.apache.logging.log4j.util.Supplier toMessageSupplier(Supplier msgSupplier) {
+ return () -> logger.getMessageFactory().newMessage(msgSupplier.get());
+ }
+
+ private org.apache.logging.log4j.util.Supplier toMessageSupplier(ResourceBundle bundle, String msg) {
+ return () -> new LocalizedMessage(bundle, msg);
+ }
+
+ private org.apache.logging.log4j.util.Supplier toMessageSupplier(
+ ResourceBundle bundle, String msg, Object[] params) {
+ return () -> new LocalizedMessage(bundle, msg, params);
+ }
+
+ private StackTraceElement toLocation(String sourceClass, String sourceMethod) {
+ return new StackTraceElement(sourceClass, sourceMethod, null, 0);
+ }
+
+ @Override
+ public void log(final Level level, final String msg) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, msg);
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void log(Level level, Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void log(final Level level, final String msg, final Object param1) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, msg, param1);
+ }
+
+ @Override
+ public void log(final Level level, final String msg, final Object[] params) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, msg, params);
+ }
+
+ @Override
+ public void log(final Level level, final String msg, final Throwable thrown) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, msg, thrown);
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void log(Level level, Throwable thrown, Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, toLog4jSupplier(msgSupplier), thrown);
+ }
+
+ @Override
+ public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .log(msg);
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void logp(Level level, String sourceClass, String sourceMethod, Supplier msgSupplier) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .log(toMessageSupplier(msgSupplier));
+ }
+
+ @Override
+ public void logp(
+ final Level level,
+ final String sourceClass,
+ final String sourceMethod,
+ final String msg,
+ final Object param1) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .log(msg, param1);
+ }
+
+ @Override
+ public void logp(
+ final Level level,
+ final String sourceClass,
+ final String sourceMethod,
+ final String msg,
+ final Object[] params) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .log(msg, params);
+ }
+
+ @Override
+ public void logp(
+ final Level level,
+ final String sourceClass,
+ final String sourceMethod,
+ final String msg,
+ final Throwable thrown) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withThrowable(thrown)
+ .log(msg);
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void logp(
+ Level level, String sourceClass, String sourceMethod, Throwable thrown, Supplier msgSupplier) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withThrowable(thrown)
+ .log(toMessageSupplier(msgSupplier));
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void logrb(
+ Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String msg, Object... params) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .log(toMessageSupplier(bundle, msg, params));
+ }
+
+ @Override
+ public void logrb(
+ Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String msg, Throwable thrown) {
+ logger.atLevel(LevelTranslator.toLevel(level))
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withThrowable(thrown)
+ .log(toMessageSupplier(bundle, msg));
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void logrb(Level level, ResourceBundle bundle, String msg, Object... params) {
+ logger.logIfEnabled(FQCN, LevelTranslator.toLevel(level), null, toMessageSupplier(bundle, msg, params), null);
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void logrb(Level level, ResourceBundle bundle, String msg, Throwable thrown) {
+ LogBuilder builder = logger.atLevel(LevelTranslator.toLevel(level)).withThrowable(thrown);
+ if (builder instanceof BridgeAware bridgeAware) {
+ bridgeAware.setEntryPoint(FQCN);
+ }
+ builder.log(toMessageSupplier(bundle, msg));
+ }
+
+ @Override
+ public void entering(final String sourceClass, final String sourceMethod) {
+ logger.atTrace()
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withMarker(ENTRY_MARKER)
+ .log(DefaultFlowMessageFactory.INSTANCE.newEntryMessage(null, (Object[]) null));
+ }
+
+ @Override
+ public void entering(final String sourceClass, final String sourceMethod, final Object param1) {
+ logger.atTrace()
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withMarker(ENTRY_MARKER)
+ .log(DefaultFlowMessageFactory.INSTANCE.newEntryMessage(null, param1));
+ }
+
+ @Override
+ public void entering(final String sourceClass, final String sourceMethod, final Object[] params) {
+ logger.atTrace()
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withMarker(ENTRY_MARKER)
+ .log(DefaultFlowMessageFactory.INSTANCE.newEntryMessage(null, params));
+ }
+
+ @Override
+ public void exiting(final String sourceClass, final String sourceMethod) {
+ logger.atTrace()
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withMarker(EXIT_MARKER)
+ .log(DefaultFlowMessageFactory.INSTANCE.newExitMessage(null, (Object) null));
+ }
+
+ @Override
+ public void exiting(final String sourceClass, final String sourceMethod, final Object result) {
+ logger.atTrace()
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withMarker(EXIT_MARKER)
+ .log(DefaultFlowMessageFactory.INSTANCE.newExitMessage(null, result));
+ }
+
+ @Override
+ public void throwing(final String sourceClass, final String sourceMethod, final Throwable thrown) {
+ logger.atTrace()
+ .withLocation(toLocation(sourceClass, sourceMethod))
+ .withMarker(THROWING_MARKER)
+ .withThrowable(thrown)
+ .log("Throwing");
+ }
+
+ @Override
+ public void severe(final String msg) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.ERROR, null, msg);
+ }
+
+ /**
+ * @since 3.0.0
+ */
+ @Override
+ public void severe(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.ERROR, null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void warning(final String msg) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.WARN, null, msg);
+ }
+
+ @Override
+ public void warning(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.WARN, null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void info(final String msg) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.INFO, null, msg);
+ }
+
+ @Override
+ public void info(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.INFO, null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void config(final String msg) {
+ logger.logIfEnabled(FQCN, LevelTranslator.CONFIG, null, msg);
+ }
+
+ @Override
+ public void config(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, LevelTranslator.CONFIG, null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void fine(final String msg) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.DEBUG, null, msg);
+ }
+
+ @Override
+ public void fine(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.DEBUG, null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void finer(final String msg) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.TRACE, null, msg);
+ }
+
+ @Override
+ public void finer(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.TRACE, null, toLog4jSupplier(msgSupplier), null);
+ }
+
+ @Override
+ public void finest(final String msg) {
+ logger.logIfEnabled(FQCN, LevelTranslator.FINEST, null, msg);
+ }
+
+ @Override
+ public void finest(Supplier msgSupplier) {
+ logger.logIfEnabled(FQCN, LevelTranslator.FINEST, null, toLog4jSupplier(msgSupplier), null);
+ }
+ //
+}
diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java
new file mode 100644
index 00000000000..8a9b13054b2
--- /dev/null
+++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+/**
+ * Utility classes that can be used in implementing providing implementation of the classes in
+ * {@link org.apache.logging.log4j.jul.spi}.
+ */
+@Export
+@Version("3.0.0")
+package org.apache.logging.jul.tolog4j.support;
+
+import org.osgi.annotation.bundle.Export;
+import org.osgi.annotation.versioning.Version;
diff --git a/log4j-jul/src/main/resources/META-INF/log4j/propertyMapping.json b/jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json
similarity index 100%
rename from log4j-jul/src/main/resources/META-INF/log4j/propertyMapping.json
rename to jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AsyncLoggerThreadsTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java
similarity index 98%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AsyncLoggerThreadsTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java
index bb7553822b9..1ec5eb6b166 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AsyncLoggerThreadsTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test;
import static org.junit.Assert.assertEquals;
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/BracketInNotInterpolatedMessageTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java
similarity index 95%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/BracketInNotInterpolatedMessageTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java
index 18b382ad3be..3bb6fd0afca 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/BracketInNotInterpolatedMessageTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test;
import static java.util.logging.Level.INFO;
import static org.hamcrest.Matchers.hasSize;
@@ -24,9 +24,9 @@
import java.util.List;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.jul.LogManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java
new file mode 100644
index 00000000000..1562b70169e
--- /dev/null
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.jul.tolog4j.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.LogManager;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class CallerInformationTest {
+
+ private static final String PARAM_1 = "PARAM_1";
+ private static final String[] PARAMS = {PARAM_1, "PARAM_2"};
+ private static final String SOURCE_CLASS = "SourceClass";
+ private static final String SOURCE_METHOD = "sourceMethod";
+
+ @Rule
+ public final LoggerContextRule ctx = new LoggerContextRule("CallerInformationTest.xml");
+
+ @BeforeClass
+ public static void setUpClass() {
+ System.setProperty("java.util.logging.manager", LogManager.class.getName());
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ System.clearProperty("java.util.logging.manager");
+ }
+
+ @Test
+ public void testClassLogger() {
+ final ListAppender app = ctx.getListAppender("Class").clear();
+ final Logger logger = Logger.getLogger("ClassLogger");
+ // Eager methods
+ logger.severe("CATASTROPHE INCOMING!");
+ logger.warning("ZOMBIES!!!");
+ logger.info("brains~~~");
+ logger.config("Config!");
+ logger.fine("Itchy. Tasty.");
+ logger.finer("Finer message.");
+ logger.finest("Finest message.");
+ logger.log(Level.FINEST, "Finest message.");
+ logger.log(Level.FINEST, "Message of level {1}.", Level.FINEST);
+ logger.log(Level.FINEST, "Hello {1} and {2}!.", new Object[] {"foo", "bar"});
+ // Lazy methods
+ logger.severe(() -> "CATASTROPHE INCOMING!");
+ logger.warning(() -> "ZOMBIES!!!");
+ logger.info(() -> "brains~~~");
+ logger.config(() -> "Config!");
+ logger.fine(() -> "Itchy. Tasty.");
+ logger.finer(() -> "Finer message.");
+ logger.finest(() -> "Finest message.");
+ logger.log(Level.FINEST, () -> "Finest message.");
+ logger.log(Level.FINEST, new RuntimeException(), () -> "Message with exception.");
+ List messages = app.getMessages();
+ assertEquals("Incorrect number of messages.", 19, messages.size());
+ for (int i = 0; i < messages.size(); i++) {
+ String message = messages.get(i);
+ assertEquals(
+ "Incorrect caller class name for message " + i,
+ this.getClass().getName(),
+ message);
+ }
+
+ // Test passing the location information directly
+ app.clear();
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello!");
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello {1}!", PARAM_1);
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello {1} and {2}!", PARAMS);
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello!", new RuntimeException());
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, () -> "Hello" + PARAM_1 + "!");
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, new RuntimeException(), () -> "Hello " + PARAM_1 + "!");
+ logger.entering(SOURCE_CLASS, SOURCE_METHOD);
+ logger.entering(SOURCE_CLASS, SOURCE_METHOD, PARAM_1);
+ logger.entering(SOURCE_CLASS, SOURCE_METHOD, PARAMS);
+ logger.exiting(SOURCE_CLASS, SOURCE_METHOD);
+ logger.exiting(SOURCE_CLASS, SOURCE_METHOD, PARAM_1);
+ logger.throwing(SOURCE_CLASS, SOURCE_METHOD, new RuntimeException());
+ messages = app.getMessages();
+ assertEquals("Incorrect number of messages.", 12, messages.size());
+ for (int i = 0; i < messages.size(); i++) {
+ String message = messages.get(i);
+ assertEquals("Incorrect caller class name for message " + i, SOURCE_CLASS, message);
+ }
+ }
+
+ @Test
+ public void testMethodLogger() {
+ final ListAppender app = ctx.getListAppender("Method").clear();
+ final Logger logger = Logger.getLogger("MethodLogger");
+ // Eager methods
+ logger.severe("CATASTROPHE INCOMING!");
+ logger.warning("ZOMBIES!!!");
+ logger.info("brains~~~");
+ logger.config("Config!");
+ logger.fine("Itchy. Tasty.");
+ logger.finer("Finer message.");
+ logger.finest("Finest message.");
+ logger.log(Level.FINEST, "Finest message.");
+ logger.log(Level.FINEST, "Message of level {1}.", Level.FINEST);
+ logger.log(Level.FINEST, "Hello {1} and {2}!.", new Object[] {"foo", "bar"});
+ // Lazy methods
+ logger.severe(() -> "CATASTROPHE INCOMING!");
+ logger.warning(() -> "ZOMBIES!!!");
+ logger.info(() -> "brains~~~");
+ logger.config(() -> "Config!");
+ logger.fine(() -> "Itchy. Tasty.");
+ logger.finer(() -> "Finer message.");
+ logger.finest(() -> "Finest message.");
+ logger.log(Level.FINEST, () -> "Finest message.");
+ logger.log(Level.FINEST, new RuntimeException(), () -> "Message with exception.");
+ List messages = app.getMessages();
+ assertEquals("Incorrect number of messages.", 19, messages.size());
+ for (int i = 0; i < messages.size(); i++) {
+ String message = messages.get(i);
+ assertEquals("Incorrect caller class name for message " + i, "testMethodLogger", message);
+ }
+
+ // Test passing the location information directly
+ app.clear();
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello!");
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello {1}!", PARAM_1);
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello {1} and {2}!", PARAMS);
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, "Hello!", new RuntimeException());
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, () -> "Hello " + PARAM_1 + "!");
+ logger.logp(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, new RuntimeException(), () -> "Hello " + PARAM_1 + "!");
+ logger.entering(SOURCE_CLASS, SOURCE_METHOD);
+ logger.entering(SOURCE_CLASS, SOURCE_METHOD, PARAM_1);
+ logger.entering(SOURCE_CLASS, SOURCE_METHOD, PARAMS);
+ logger.exiting(SOURCE_CLASS, SOURCE_METHOD);
+ logger.exiting(SOURCE_CLASS, SOURCE_METHOD, PARAM_1);
+ logger.throwing(SOURCE_CLASS, SOURCE_METHOD, new RuntimeException());
+ messages = app.getMessages();
+ assertEquals("Incorrect number of messages.", 12, messages.size());
+ for (int i = 0; i < messages.size(); i++) {
+ String message = messages.get(i);
+ assertEquals("Incorrect caller class name for message " + i, SOURCE_METHOD, message);
+ }
+ }
+}
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JavaLevelTranslatorTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java
similarity index 96%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JavaLevelTranslatorTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java
index d000d258dc1..76744a3959d 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JavaLevelTranslatorTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java
@@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
+import org.apache.logging.jul.tolog4j.LevelTranslator;
import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.jul.LevelTranslator;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JulTestProperties.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java
similarity index 95%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JulTestProperties.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java
index 4c5e8a0b618..28c4b2f6122 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JulTestProperties.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test;
public final class JulTestProperties {
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jLevelTranslatorTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java
similarity index 95%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jLevelTranslatorTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java
index 2d2d8c2ca30..43b6796a2a0 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jLevelTranslatorTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java
@@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
+import org.apache.logging.jul.tolog4j.LevelTranslator;
import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.jul.LevelTranslator;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java
new file mode 100644
index 00000000000..ed94daa6e47
--- /dev/null
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jul.tolog4j.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.LogManager;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test methods that accept a resource bundle
+ */
+public class ResourceBundleTest {
+
+ private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("ResourceBundleTest");
+ private static final String SOURCE_CLASS = "SourceClass";
+ private static final String SOURCE_METHOD = "sourceMethod";
+
+ private static final String[] EXPECTED_MESSAGES = {"Hello!", "Hello Log4j and JUL!"};
+ private static final String[] EXPECTED_CLASS_NAMES = {ResourceBundleTest.class.getName(), SOURCE_CLASS};
+ private static final String[] EXPECTED_METHOD_NAMES = {"testCorrectMessageAndLocation", SOURCE_METHOD};
+
+ @Rule
+ public final LoggerContextRule ctx = new LoggerContextRule("ResourceBundleTest.xml");
+
+ @BeforeClass
+ public static void setUpClass() {
+ System.setProperty("java.util.logging.manager", LogManager.class.getName());
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ System.clearProperty("java.util.logging.manager");
+ }
+
+ @Test
+ public void testCorrectMessageAndLocation() {
+ ListAppender appender = ctx.getListAppender("LIST").clear();
+ Logger logger = Logger.getLogger(ResourceBundleTest.class.getName());
+
+ Throwable thrown = new RuntimeException();
+ logger.logrb(Level.INFO, BUNDLE, "msg_1", thrown);
+ logger.logrb(Level.INFO, BUNDLE, "msg_2", "Log4j", "JUL");
+ logger.logrb(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, BUNDLE, "msg_1", thrown);
+ logger.logrb(Level.INFO, SOURCE_CLASS, SOURCE_METHOD, BUNDLE, "msg_2", "Log4j", "JUL");
+
+ LogEvent[] logEvents = appender.getEvents().toArray(LogEvent[]::new);
+ for (int idx = 0; idx < logEvents.length; ++idx) {
+ assertEquals(
+ String.format("Message of event %d", idx),
+ EXPECTED_MESSAGES[idx % 2],
+ logEvents[idx].getMessage().getFormattedMessage());
+ assertEquals(
+ String.format("Source class of event %d", idx),
+ EXPECTED_CLASS_NAMES[idx / 2],
+ logEvents[idx].getSource().getClassName());
+ assertEquals(
+ String.format("Source method of event %d", idx),
+ EXPECTED_METHOD_NAMES[idx / 2],
+ logEvents[idx].getSource().getMethodName());
+ assertSame(
+ String.format("Exception of event %d", idx),
+ idx % 2 == 0 ? thrown : null,
+ logEvents[idx].getThrown());
+ }
+ }
+}
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ApiLoggerTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java
similarity index 72%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ApiLoggerTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java
index ce58daf2028..b7da8115fc0 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ApiLoggerTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java
@@ -14,19 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test.internal;
-import static org.apache.logging.log4j.jul.test.JulTestProperties.JUL_LOGGER_ADAPTER;
-import static org.hamcrest.Matchers.equalTo;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
import java.util.logging.Logger;
-import org.apache.logging.log4j.core.test.TestConstants;
+import org.apache.logging.jul.tolog4j.LogManager;
+import org.apache.logging.jul.tolog4j.test.support.AbstractLoggerTest;
import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.jul.ApiLoggerAdapter;
-import org.apache.logging.log4j.jul.LogManager;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -35,25 +32,26 @@
public class ApiLoggerTest extends AbstractLoggerTest {
- private static String oldAdapter;
-
@BeforeClass
public static void setUpClass() {
System.setProperty("java.util.logging.manager", LogManager.class.getName());
- oldAdapter = TestConstants.setSystemProperty(JUL_LOGGER_ADAPTER, ApiLoggerAdapter.class.getName());
}
@AfterClass
public static void tearDownClass() {
System.clearProperty("java.util.logging.manager");
- TestConstants.setSystemProperty(JUL_LOGGER_ADAPTER, oldAdapter);
}
@Before
- public void setUp() throws Exception {
+ public void setUp() {
logger = Logger.getLogger(LOGGER_NAME);
logger.setFilter(null);
- assertThat(logger.getLevel(), equalTo(java.util.logging.Level.FINE));
+ assertThat(logger.isLoggable(java.util.logging.Level.FINE))
+ .as("Level %s is enabled", java.util.logging.Level.FINE)
+ .isTrue();
+ assertThat(logger.isLoggable(java.util.logging.Level.FINER))
+ .as("Level %s is enabled", java.util.logging.Level.FINER)
+ .isFalse();
eventAppender = ListAppender.getListAppender("TestAppender");
flowAppender = ListAppender.getListAppender("FlowAppender");
stringAppender = ListAppender.getListAppender("StringAppender");
@@ -63,7 +61,7 @@ public void setUp() throws Exception {
}
@After
- public void tearDown() throws Exception {
+ public void tearDown() {
if (eventAppender != null) {
eventAppender.clear();
}
@@ -76,18 +74,18 @@ public void tearDown() throws Exception {
}
@Test
- public void testGetParent() throws Exception {
+ public void testGetParent() {
final Logger parent = logger.getParent();
assertNull("No parent logger should be automatically set up using log4j-api", parent);
}
@Test(expected = UnsupportedOperationException.class)
- public void testSetParentFails() throws Exception {
+ public void testSetParentFails() {
logger.setParent(null);
}
@Test
- public void testSetLevelFails() throws Exception {
+ public void testSetLevelFails() {
logger.setLevel(null);
}
}
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterCustomJulLevelsTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java
similarity index 96%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterCustomJulLevelsTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java
index 14b6416eb70..825b476c489 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterCustomJulLevelsTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java
@@ -14,11 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test.internal;
+import org.apache.logging.jul.tolog4j.LevelTranslator;
+import org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter;
import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.jul.DefaultLevelConverter;
-import org.apache.logging.log4j.jul.LevelTranslator;
import org.junit.Assert;
import org.junit.Test;
@@ -31,8 +31,6 @@ public class DefaultLevelConverterCustomJulLevelsTest {
static class CustomLevel extends java.util.logging.Level {
- private static final long serialVersionUID = 1L;
-
static CustomLevel ALL_P_1 = new CustomLevel("ALL_P_1", java.util.logging.Level.ALL.intValue() + 1);
static CustomLevel FINEST_P_1 = new CustomLevel("FINEST_P_1", java.util.logging.Level.FINEST.intValue() + 1);
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java
similarity index 81%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java
index dc7d334fa6b..f93a4f4ca54 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java
@@ -14,10 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test.internal;
-import org.apache.logging.log4j.jul.DefaultLevelConverter;
-import org.junit.Assert;
+import static org.junit.Assert.assertNull;
+
+import org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter;
import org.junit.Test;
public class DefaultLevelConverterTest {
@@ -27,6 +28,6 @@ public class DefaultLevelConverterTest {
*/
@Test
public void testJulSetNull() {
- Assert.assertEquals(null, new DefaultLevelConverter().toLevel(null));
+ assertNull(new DefaultLevelConverter().toLevel(null));
}
}
diff --git a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java
similarity index 76%
rename from log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java
rename to jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java
index 303ff62db33..9e620cdffc9 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java
@@ -14,18 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.logging.log4j.jul.test;
+package org.apache.logging.jul.tolog4j.test.support;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.LevelTranslator;
+import org.apache.logging.jul.tolog4j.support.AbstractLogger;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.impl.MementoLogEvent;
import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.apache.logging.log4j.jul.ApiLogger;
-import org.apache.logging.log4j.jul.LevelTranslator;
import org.junit.Test;
/**
@@ -39,12 +39,12 @@ public abstract class AbstractLoggerTest {
protected ListAppender stringAppender;
@Test
- public void testGetName() throws Exception {
+ public void testGetName() {
assertThat(logger.getName()).isEqualTo(LOGGER_NAME);
}
@Test
- public void testGlobalLogger() throws Exception {
+ public void testGlobalLogger() {
final Logger root = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
root.info("Test info message");
root.config("Test info message");
@@ -58,18 +58,18 @@ public void testGlobalLogger() throws Exception {
}
@Test
- public void testGlobalLoggerName() throws Exception {
+ public void testGlobalLoggerName() {
final Logger root = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
assertThat(root.getName()).isEqualTo(Logger.GLOBAL_LOGGER_NAME);
}
@Test
- public void testIsLoggable() throws Exception {
+ public void testIsLoggable() {
assertThat(logger.isLoggable(java.util.logging.Level.SEVERE)).isTrue();
}
@Test
- public void testLog() throws Exception {
+ public void testLog() {
logger.info("Informative message here.");
final List events = eventAppender.getEvents();
assertThat(events).hasSize(1);
@@ -78,38 +78,7 @@ public void testLog() throws Exception {
assertThat(event.getLevel()).isEqualTo(Level.INFO);
assertThat(event.getLoggerName()).isEqualTo(LOGGER_NAME);
assertThat(event.getMessage().getFormattedMessage()).isEqualTo("Informative message here.");
- assertThat(event.getLoggerFqcn()).isEqualTo(ApiLogger.class.getName());
- }
-
- @Test
- public void testLogFilter() throws Exception {
- logger.setFilter(record -> false);
- logger.severe("Informative message here.");
- logger.warning("Informative message here.");
- logger.info("Informative message here.");
- logger.config("Informative message here.");
- logger.fine("Informative message here.");
- logger.finer("Informative message here.");
- logger.finest("Informative message here.");
- final List events = eventAppender.getEvents();
- assertThat(events).isEmpty();
- }
-
- @Test
- public void testAlteringLogFilter() throws Exception {
- logger.setFilter(record -> {
- record.setMessage("This is not the message you are looking for.");
- return true;
- });
- logger.info("Informative message here.");
- final List events = eventAppender.getEvents();
- assertThat(events).hasSize(1);
- final LogEvent event = events.get(0);
- assertThat(event).isInstanceOf(MementoLogEvent.class);
- assertThat(event.getLevel()).isEqualTo(Level.INFO);
- assertThat(event.getLoggerName()).isEqualTo(LOGGER_NAME);
- assertThat(event.getMessage().getFormattedMessage()).isEqualTo("This is not the message you are looking for.");
- assertThat(event.getLoggerFqcn()).isEqualTo(ApiLogger.class.getName());
+ assertThat(event.getLoggerFqcn()).isEqualTo(AbstractLogger.class.getName());
}
@Test
@@ -121,7 +90,7 @@ public void testLogParamMarkers() {
}
@Test
- public void testLogUsingCustomLevel() throws Exception {
+ public void testLogUsingCustomLevel() {
logger.config("Config level");
final List events = eventAppender.getEvents();
assertThat(events).hasSize(1);
@@ -130,7 +99,7 @@ public void testLogUsingCustomLevel() throws Exception {
}
@Test
- public void testLogWithCallingClass() throws Exception {
+ public void testLogWithCallingClass() {
final Logger log = Logger.getLogger("Test.CallerClass");
log.config("Calling from LoggerTest");
final List messages = stringAppender.getMessages();
diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java
new file mode 100644
index 00000000000..83d90f325dd
--- /dev/null
+++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.jul.tolog4j.test.support;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.logging.Filter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.logging.jul.tolog4j.LogManager;
+import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
+import org.apache.logging.jul.tolog4j.support.AbstractLogger;
+import org.apache.logging.jul.tolog4j.test.JulTestProperties;
+import org.apache.logging.log4j.spi.ExtendedLogger;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Tests if the logger adapter can be customized.
+ */
+public class CustomLoggerAdapterTest {
+
+ private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
+
+ @BeforeClass
+ public static void setUpClass() {
+ System.setProperty("java.util.logging.manager", LogManager.class.getName());
+ System.setProperty(JulTestProperties.JUL_LOGGER_ADAPTER, CustomLoggerAdapter.class.getName());
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ System.clearProperty("java.util.logging.manager");
+ System.clearProperty(JulTestProperties.JUL_LOGGER_ADAPTER);
+ }
+
+ @Test
+ public void testCustomLoggerAdapter() {
+ Logger logger = Logger.getLogger(CustomLoggerAdapterTest.class.getName());
+ assertTrue("CustomLoggerAdapter is used", logger instanceof CustomLogger);
+ }
+
+ public static class CustomLoggerAdapter extends AbstractLoggerAdapter {
+
+ @Override
+ public Logger newLogger(String name, LoggerContext context) {
+ return new CustomLogger(context.getLogger(name));
+ }
+ }
+
+ private static class CustomLogger extends AbstractLogger {
+
+ CustomLogger(ExtendedLogger logger) {
+ super(logger);
+ }
+
+ @Override
+ public void setFilter(Filter newFilter) {}
+
+ @Override
+ public void setLevel(final Level newLevel) throws SecurityException {
+ LOGGER.error("Cannot set JUL log level through Log4j API: ignoring call to Logger.setLevel({})", newLevel);
+ }
+
+ @Override
+ public void addHandler(Handler handler) {}
+
+ @Override
+ public void removeHandler(Handler handler) {}
+
+ @Override
+ public void setUseParentHandlers(boolean useParentHandlers) {}
+
+ @Override
+ public void setParent(Logger parent) {}
+ }
+}
diff --git a/jul-to-log4j/src/test/resources/CallerInformationTest.xml b/jul-to-log4j/src/test/resources/CallerInformationTest.xml
new file mode 100644
index 00000000000..087587ea5df
--- /dev/null
+++ b/jul-to-log4j/src/test/resources/CallerInformationTest.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jul-to-log4j/src/test/resources/ResourceBundleTest.properties b/jul-to-log4j/src/test/resources/ResourceBundleTest.properties
new file mode 100644
index 00000000000..3563a119784
--- /dev/null
+++ b/jul-to-log4j/src/test/resources/ResourceBundleTest.properties
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+##
+# Resource bundle used in ResourceBundleTest
+
+msg_1 = Hello!
+msg_2 = Hello %s and %s!
diff --git a/log4j-jul/src/test/resources/log4j2-calling-class.xml b/jul-to-log4j/src/test/resources/ResourceBundleTest.xml
similarity index 68%
rename from log4j-jul/src/test/resources/log4j2-calling-class.xml
rename to jul-to-log4j/src/test/resources/ResourceBundleTest.xml
index 1af22eaa82c..3d2d891500e 100644
--- a/log4j-jul/src/test/resources/log4j2-calling-class.xml
+++ b/jul-to-log4j/src/test/resources/ResourceBundleTest.xml
@@ -15,22 +15,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
+
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
+
diff --git a/jul-to-log4j/src/test/resources/log4j2-test.xml b/jul-to-log4j/src/test/resources/log4j2-test.xml
new file mode 100644
index 00000000000..9c5bdb23ab9
--- /dev/null
+++ b/jul-to-log4j/src/test/resources/log4j2-test.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/log4j-jul/pom.xml b/log4j-jul/pom.xml
index 5fdabdc7175..fc598b85775 100644
--- a/log4j-jul/pom.xml
+++ b/log4j-jul/pom.xml
@@ -25,91 +25,46 @@
log4j-jul
- Apache Log4j JUL Adapter
- The Apache Log4j implementation of java.util.logging
-
-
-
-
-
- org.apache.logging.log4j.core.*;resolution:=optional
-
-
-
- org.apache.logging.log4j.core;transitive=false
-
-
-
- false
-
+ Apache Log4j JUL Handler
+ A `java.util.logging` Handler that forwards events to the Log4j API.
+
org.apache.logging.log4jlog4j-api
+
+
+ org.apache.logging.log4j
+ jul-to-log4j
+
+
org.apache.logging.log4jlog4j-core
- true
+
org.assertjassertj-coretest
-
-
- com.lmax
- disruptor
- test
-
-
- org.hamcrest
- hamcrest
- test
-
-
- junit
- junit
- test
-
+
- org.apache.logging.log4j
- log4j-async-logger
- test
-
-
- org.apache.logging.log4j
- log4j-core-test
+ org.junit.jupiter
+ junit-jupiter-apitest
+
+
org.apache.maven.pluginsmaven-surefire-plugin
-
-
- true
-
- -Xms256m -Xmx1024m
- 1
- false
-
-
-
-
-
- org.apache.maven.surefire
- surefire-junit47
- ${surefire.version}
-
- default-test
@@ -121,27 +76,14 @@
Log4jBridgeHandlerTest.java
-
-
-
-
- bridgeHandler-test
-
- test
-
- test
-
-
- Log4jBridgeHandlerTest.java
-
- src/test/resources/logging-test.properties
- classpath:log4j2-julBridge-test.xml
+ ${project.basedir}/src/test/resources/logging-test.properties
+
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/AbstractLoggerAdapter.java b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/AbstractLoggerAdapter.java
deleted file mode 100644
index 7c33636a364..00000000000
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/AbstractLoggerAdapter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.jul;
-
-import java.util.logging.Logger;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.spi.LoggerContext;
-import org.apache.logging.log4j.util.StackLocatorUtil;
-
-/**
- * Abstract Logger registry. Due to the optionality of using log4j-core, there are two registries available at runtime
- * to create: {@link ApiLoggerAdapter} and {@link CoreLoggerAdapter}.
- *
- * @since 2.1
- */
-public abstract class AbstractLoggerAdapter extends org.apache.logging.log4j.spi.AbstractLoggerAdapter {
-
- @Override
- protected LoggerContext getContext() {
- return getContext(
- LogManager.getFactory().isClassLoaderDependent()
- ? StackLocatorUtil.getCallerClass(java.util.logging.LogManager.class)
- : null);
- }
-}
diff --git a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLogger.java b/log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLogger.java
deleted file mode 100644
index eee946fc8ce..00000000000
--- a/log4j-jul/src/main/java/org/apache/logging/log4j/jul/ApiLogger.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * 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.jul;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.logging.Filter;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import org.apache.logging.log4j.message.Message;
-import org.apache.logging.log4j.message.MessageFactory;
-import org.apache.logging.log4j.spi.ExtendedLogger;
-import org.apache.logging.log4j.status.StatusLogger;
-
-/**
- * Log4j API implementation of the JUL {@link Logger} class. Note that this implementation does
- * not use the {@link java.util.logging.Handler} class. Instead, logging is delegated to the
- * underlying Log4j {@link org.apache.logging.log4j.Logger} which may be implemented in one of many different ways.
- * Consult the documentation for your Log4j Provider for more details.
- *
Note that the methods {@link #getParent()} and {@link #setLevel(java.util.logging.Level)} are not supported by
- * this implementation. If you need support for these methods, then you'll need to use log4j-core. The
- * {@link #getParent()} method will not fail (thanks to JUL API limitations), but it won't necessarily be
- * accurate!
- *
Also note that {@link #setParent(java.util.logging.Logger)} is explicitly unsupported. Parent loggers are
- * determined using the syntax of the logger name; not through an arbitrary graph of loggers.