From 3ea53e1b41279f5a0eb61746542b9938e0c0a459 Mon Sep 17 00:00:00 2001 From: Ralph Goers Date: Mon, 6 Feb 2012 23:55:13 +0000 Subject: [PATCH 1/4] Make new home for Log4j2 git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/log4j2/trunk@1241269 13f79535-47bb-0310-9956-ffa450edef68 From f650a557036328b5c01e56aec2df642305edb45f Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Tue, 22 Oct 2024 18:57:22 +0200 Subject: [PATCH 2/4] Split new `jul-to-log4j` artifact from `log4j-jul` (#2935) 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 | 88 ++++ .../logging/jul/tolog4j/LogManager.java | 104 +++++ .../jul/tolog4j/internal/ApiLogger.java | 74 +++ .../tolog4j/internal/ApiLoggerAdapter.java | 39 ++ .../internal/DefaultLevelConverter.java | 129 +++++ .../jul/tolog4j/internal/JulProperties.java | 27 ++ .../jul/tolog4j/internal/NoOpLogger.java | 222 +++++++++ .../logging/jul/tolog4j/package-info.java | 22 + .../tolog4j/spi/AbstractLoggerAdapter.java | 67 +++ .../jul/tolog4j/spi/LevelConverter.java | 49 ++ .../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 | 10 + .../tolog4j/test/AsyncLoggerThreadsTest.java | 59 +++ .../BracketInNotInterpolatedMessageTest.java | 58 +++ .../tolog4j/test/CallerInformationTest.java | 162 +++++++ .../tolog4j/test/JavaLevelTranslatorTest.java | 72 +++ .../jul/tolog4j/test/JulTestProperties.java | 24 + .../test/Log4jLevelTranslatorTest.java | 65 +++ .../jul/tolog4j/test/ResourceBundleTest.java | 91 ++++ .../tolog4j/test/internal/ApiLoggerTest.java | 91 ++++ ...aultLevelConverterCustomJulLevelsTest.java | 144 ++++++ .../internal/DefaultLevelConverterTest.java | 33 ++ .../test/support/AbstractLoggerTest.java | 185 ++++++++ .../test/support/CustomLoggerAdapterTest.java | 95 ++++ .../test/resources/CallerInformationTest.xml | 42 ++ .../resources/ResourceBundleTest.properties | 21 + .../src/test/resources/ResourceBundleTest.xml | 31 ++ .../src/test/resources/log4j2-test.xml | 46 ++ 31 files changed, 2675 insertions(+) create mode 100644 jul-to-log4j/pom.xml create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java 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 create mode 100644 jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java 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 create mode 100644 jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java create mode 100644 jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java 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 create mode 100644 jul-to-log4j/src/test/resources/ResourceBundleTest.xml create mode 100644 jul-to-log4j/src/test/resources/log4j2-test.xml diff --git a/jul-to-log4j/pom.xml b/jul-to-log4j/pom.xml new file mode 100644 index 0000000..9e18420 --- /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/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java new file mode 100644 index 0000000..142b19f --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java @@ -0,0 +1,88 @@ +/* + * 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; + +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; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.util.LoaderUtil; + +/** + * Utility class to convert between JDK Levels and Log4j 2 Levels. + * + * @since 2.1 + */ +public final class LevelTranslator { + + /** + * Custom Log4j level corresponding to the {@link java.util.logging.Level#FINEST} logging level. This maps to a + * level more specific than {@link org.apache.logging.log4j.Level#TRACE}. + */ + public static final Level FINEST = Level.forName("FINEST", Level.TRACE.intLevel() + 100); + + /** + * Custom Log4j level corresponding to the {@link java.util.logging.Level#CONFIG} logging level. This maps to a + * level in between {@link org.apache.logging.log4j.Level#INFO} and {@link org.apache.logging.log4j.Level#DEBUG}. + */ + public static final Level CONFIG = Level.forName("CONFIG", Level.INFO.intLevel() + 50); + + private static final Logger LOGGER = StatusLogger.getLogger(); + private static final LevelConverter LEVEL_CONVERTER; + + static { + final Class levelConverterClass = + PropertyEnvironment.getGlobal().getProperty(JulProperties.class).levelConverter(); + if (levelConverterClass != null) { + LevelConverter levelConverter; + try { + levelConverter = LoaderUtil.newInstanceOf(levelConverterClass); + } catch (final Exception e) { + LOGGER.error("Could not create custom LevelConverter [{}].", levelConverterClass.getName(), e); + levelConverter = new DefaultLevelConverter(); + } + LEVEL_CONVERTER = levelConverter; + } else { + LEVEL_CONVERTER = new DefaultLevelConverter(); + } + } + + /** + * Converts a JDK logging Level to a Log4j logging Level. + * + * @param level JDK Level to convert, may be null per the JUL specification. + * @return converted Level or null + */ + public static Level toLevel(final java.util.logging.Level level) { + return LEVEL_CONVERTER.toLevel(level); + } + + /** + * Converts a Log4j logging Level to a JDK logging Level. + * + * @param level Log4j Level to convert. + * @return converted Level. + */ + public static java.util.logging.Level toJavaLevel(final Level level) { + return LEVEL_CONVERTER.toJavaLevel(level); + } + + private LevelTranslator() {} +} diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java new file mode 100644 index 0000000..6e105aa --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java @@ -0,0 +1,104 @@ +/* + * 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; + +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.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.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 final AbstractLoggerAdapter loggerAdapter; + // Contains the set of logger names that are actively being requested using getLogger. + private final ThreadLocal> recursive = ThreadLocal.withInitial(HashSet::new); + + public LogManager() { + AbstractLoggerAdapter adapter = null; + final Class adapterClass = + PropertyEnvironment.getGlobal().getProperty(JulProperties.class).loggerAdapter(); + if (adapterClass != null) { + try { + LOGGER.info("Trying to use LoggerAdapter [{}] specified by Log4j property.", adapterClass.getName()); + adapter = LoaderUtil.newInstanceOf(adapterClass); + } catch (final Exception e) { + LOGGER.error( + "Specified LoggerAdapter [{}] can not be created, using default.", adapterClass.getName(), e); + } + } + if (adapter == null) { + // 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."); + } + + @Override + public boolean addLogger(final Logger logger) { + // in order to prevent non-bridged loggers from being registered, we always return false to indicate that + // the named logger should be obtained through getLogger(name) + return false; + } + + @Override + public Logger getLogger(final String name) { + LOGGER.trace("Call to LogManager.getLogger({})", name); + final Set activeRequests = recursive.get(); + if (activeRequests.add(name)) { + try { + return loggerAdapter.getLogger(name); + } finally { + activeRequests.remove(name); + } + } + LOGGER.warn("Recursive call to getLogger for {} ignored.", name); + return new NoOpLogger(name); + } + + @Override + public Enumeration getLoggerNames() { + return Collections.enumeration( + loggerAdapter.getLoggersInContext(loggerAdapter.getContext()).keySet()); + } +} 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 0000000..bde8a19 --- /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/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java new file mode 100644 index 0000000..6e6778f --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java @@ -0,0 +1,39 @@ +/* + * 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.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; + +/** + * {@link Logger} registry implementation using just log4j-api. This is the fallback registry used when log4j-core is + * not available. + * + * @since 2.1 + */ +public class ApiLoggerAdapter extends AbstractLoggerAdapter { + + private static final MessageFactory MESSAGE_FACTORY = new MessageFormatMessageFactory(); + + @Override + public Logger newLogger(final String name, final LoggerContext context) { + return new ApiLogger(context.getLogger(name, MESSAGE_FACTORY)); + } +} diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java new file mode 100644 index 0000000..9a8ed84 --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java @@ -0,0 +1,129 @@ +/* + * 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.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.List; +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; + +/** + * Default implementation of LevelConverter strategy. + *

+ * Since 2.4, supports custom JUL levels by mapping them to their closest mapped neighbour. + *

+ * + * @since 2.1 + */ +public class DefaultLevelConverter implements LevelConverter { + + static final class JulLevelComparator implements Comparator { + @Override + public int compare(final java.util.logging.Level level1, final java.util.logging.Level level2) { + return Integer.compare(level1.intValue(), level2.intValue()); + } + } + + private final ConcurrentMap julToLog4j = new ConcurrentHashMap<>(9); + private final Map log4jToJul = new IdentityHashMap<>(10); + private final List sortedJulLevels = new ArrayList<>(9); + + public DefaultLevelConverter() { + // Map JUL to Log4j + mapJulToLog4j(java.util.logging.Level.ALL, Level.ALL); + mapJulToLog4j(java.util.logging.Level.FINEST, LevelTranslator.FINEST); + mapJulToLog4j(java.util.logging.Level.FINER, Level.TRACE); + mapJulToLog4j(java.util.logging.Level.FINE, Level.DEBUG); + mapJulToLog4j(java.util.logging.Level.CONFIG, LevelTranslator.CONFIG); + mapJulToLog4j(java.util.logging.Level.INFO, Level.INFO); + mapJulToLog4j(java.util.logging.Level.WARNING, Level.WARN); + mapJulToLog4j(java.util.logging.Level.SEVERE, Level.ERROR); + mapJulToLog4j(java.util.logging.Level.OFF, Level.OFF); + // Map Log4j to JUL + mapLog4jToJul(Level.ALL, java.util.logging.Level.ALL); + mapLog4jToJul(LevelTranslator.FINEST, java.util.logging.Level.FINEST); + mapLog4jToJul(Level.TRACE, java.util.logging.Level.FINER); + mapLog4jToJul(Level.DEBUG, java.util.logging.Level.FINE); + mapLog4jToJul(LevelTranslator.CONFIG, java.util.logging.Level.CONFIG); + mapLog4jToJul(Level.INFO, java.util.logging.Level.INFO); + mapLog4jToJul(Level.WARN, java.util.logging.Level.WARNING); + mapLog4jToJul(Level.ERROR, java.util.logging.Level.SEVERE); + mapLog4jToJul(Level.FATAL, java.util.logging.Level.SEVERE); + mapLog4jToJul(Level.OFF, java.util.logging.Level.OFF); + // Sorted Java levels + sortedJulLevels.addAll(julToLog4j.keySet()); + Collections.sort(sortedJulLevels, new JulLevelComparator()); + } + + private long distance(final java.util.logging.Level javaLevel, final java.util.logging.Level customJavaLevel) { + return Math.abs((long) customJavaLevel.intValue() - (long) javaLevel.intValue()); + } + + /* + * TODO consider making public for advanced configuration. + */ + private void mapJulToLog4j(final java.util.logging.Level julLevel, final Level level) { + julToLog4j.put(julLevel, level); + } + + /* + * TODO consider making public for advanced configuration. + */ + private void mapLog4jToJul(final Level level, final java.util.logging.Level julLevel) { + log4jToJul.put(level, julLevel); + } + + private Level nearestLevel(final java.util.logging.Level customJavaLevel) { + long prevDist = Long.MAX_VALUE; + java.util.logging.Level prevLevel = null; + for (final java.util.logging.Level mappedJavaLevel : sortedJulLevels) { + final long distance = distance(customJavaLevel, mappedJavaLevel); + if (distance > prevDist) { + return julToLog4j.get(prevLevel); + } + prevDist = distance; + prevLevel = mappedJavaLevel; + } + return julToLog4j.get(prevLevel); + } + + @Override + public java.util.logging.Level toJavaLevel(final Level level) { + return log4jToJul.get(level); + } + + @Override + public Level toLevel(final java.util.logging.Level javaLevel) { + if (javaLevel == null) { + return null; + } + final Level level = julToLog4j.get(javaLevel); + if (level != null) { + return level; + } + final Level nearestLevel = nearestLevel(javaLevel); + julToLog4j.put(javaLevel, nearestLevel); + return nearestLevel; + } +} diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java new file mode 100644 index 0000000..1b500b6 --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java @@ -0,0 +1,27 @@ +/* + * 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 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; + +@Log4jProperty(name = "jul") +public record JulProperties( + @Nullable Class levelConverter, + @Nullable Class loggerAdapter) {} diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java new file mode 100644 index 0000000..879d19a --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java @@ -0,0 +1,222 @@ +/* + * 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.ResourceBundle; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +/** + * Dummy version of a java.util.Logger. + */ +public class NoOpLogger extends Logger { + + public NoOpLogger(final String name) { + super(name, null); + } + + @Override + public void log(final LogRecord record) {} + + @Override + public void log(final Level level, final String msg) {} + + @Override + public void log(final Level level, final Supplier msgSupplier) {} + + @Override + public void log(final Level level, final String msg, final Object param1) {} + + @Override + public void log(final Level level, final String msg, final Object[] params) {} + + @Override + public void log(final Level level, final String msg, final Throwable thrown) {} + + @Override + public void log(final Level level, final Throwable thrown, final Supplier msgSupplier) {} + + @Override + public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg) {} + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final Supplier msgSupplier) {} + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final String msg, + final Object param1) {} + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final String msg, + final Object[] params) {} + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final String msg, + final Throwable thrown) {} + + @Override + public void logp( + final Level level, + final String sourceClass, + final String sourceMethod, + final Throwable thrown, + final Supplier msgSupplier) {} + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg) {} + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg, + final Object param1) {} + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg, + final Object[] params) {} + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final ResourceBundle bundle, + final String msg, + final Object... params) {} + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final String bundleName, + final String msg, + final Throwable thrown) {} + + @Override + public void logrb( + final Level level, + final String sourceClass, + final String sourceMethod, + final ResourceBundle bundle, + final String msg, + final Throwable thrown) {} + + @Override + public void entering(final String sourceClass, final String sourceMethod) {} + + @Override + public void entering(final String sourceClass, final String sourceMethod, final Object param1) {} + + @Override + public void entering(final String sourceClass, final String sourceMethod, final Object[] params) {} + + @Override + public void exiting(final String sourceClass, final String sourceMethod) {} + + @Override + public void exiting(final String sourceClass, final String sourceMethod, final Object result) {} + + @Override + public void throwing(final String sourceClass, final String sourceMethod, final Throwable thrown) {} + + @Override + public void severe(final String msg) {} + + @Override + public void warning(final String msg) {} + + @Override + public void info(final String msg) {} + + @Override + public void config(final String msg) {} + + @Override + public void fine(final String msg) {} + + @Override + public void finer(final String msg) {} + + @Override + public void finest(final String msg) {} + + @Override + public void severe(final Supplier msgSupplier) {} + + @Override + public void warning(final Supplier msgSupplier) {} + + @Override + public void info(final Supplier msgSupplier) {} + + @Override + public void config(final Supplier msgSupplier) {} + + @Override + public void fine(final Supplier msgSupplier) {} + + @Override + public void finer(final Supplier msgSupplier) {} + + @Override + public void finest(final Supplier msgSupplier) {} + + @Override + public void setLevel(final Level newLevel) throws SecurityException {} + + @Override + public Level getLevel() { + return Level.OFF; + } + + @Override + public boolean isLoggable(final Level level) { + return false; + } +} 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 0000000..d0fc9b2 --- /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 0000000..8c43dc8 --- /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. + *

+ * + * @see Issue #2353 + * @since 2.1 + */ +public abstract class AbstractLoggerAdapter extends org.apache.logging.log4j.spi.AbstractLoggerAdapter { + + /** + * Creates a new {@link java.util.logging.Logger} + *

+ * 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/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java new file mode 100644 index 0000000..489477e --- /dev/null +++ b/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java @@ -0,0 +1,49 @@ +/* + * 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 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 + */ +public interface LevelConverter { + + /** + * Converts a JDK logging Level to a Log4j logging Level. + * + * @param javaLevel JDK Level to convert, may be null per the JUL specification. + * @return converted Level or {@code null} if the given level could not be converted. + */ + Level toLevel(java.util.logging.Level javaLevel); + + /** + * Converts a Log4j logging Level to a JDK logging Level. + * + * @param level Log4j Level to convert. + * @return converted Level or {@code null} if the given level could not be converted. + */ + java.util.logging.Level toJavaLevel(Level level); +} 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 0000000..b7eb30c --- /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 0000000..f91812b --- /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 0000000..8a9b130 --- /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/jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json b/jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json new file mode 100644 index 0000000..f88a328 --- /dev/null +++ b/jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json @@ -0,0 +1,10 @@ +{ + "jul": { + "levelConverter": [ + "log4j2.julLevelConverter" + ], + "loggerAdapter": [ + "log4j2.julLoggerAdapter" + ] + } +} \ No newline at end of file diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java new file mode 100644 index 0000000..1ec5eb6 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.jul.tolog4j.test; + +import static org.junit.Assert.assertEquals; + +import java.util.List; +import java.util.stream.Collectors; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.async.logger.AsyncLoggerContextSelector; +import org.apache.logging.log4j.core.test.TestConstants; +import org.apache.logging.log4j.core.test.categories.AsyncLoggers; +import org.jspecify.annotations.Nullable; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category(AsyncLoggers.class) +public class AsyncLoggerThreadsTest { + + static @Nullable String oldSelector; + + @BeforeClass + public static void beforeClass() { + oldSelector = TestConstants.setSystemProperty( + TestConstants.LOGGER_CONTEXT_SELECTOR, AsyncLoggerContextSelector.class.getName()); + System.setProperty("java.util.logging.manager", LogManager.class.getName()); + } + + @AfterClass + public static void afterClass() { + TestConstants.setSystemProperty(TestConstants.LOGGER_CONTEXT_SELECTOR, oldSelector); + System.clearProperty("java.util.logging.manager"); + } + + @Test + public void testAsyncLoggerThreads() { + LogManager.getLogger("com.foo.Bar").info("log"); + final List asyncLoggerThreads = Thread.getAllStackTraces().keySet().stream() + .filter(thread -> thread.getName().matches("Log4j2-TF.*AsyncLogger.*")) + .collect(Collectors.toList()); + assertEquals(asyncLoggerThreads.toString(), 1, asyncLoggerThreads.size()); + } +} diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java new file mode 100644 index 0000000..3bb6fd0 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java @@ -0,0 +1,58 @@ +/* + * 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 java.util.logging.Level.INFO; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +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.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class BracketInNotInterpolatedMessageTest { + + @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 noInterpolation() { + final Logger logger = Logger.getLogger("Test"); + logger.info("{raw}"); + logger.log( + new LogRecord(INFO, "{raw}")); // should lead to the same as previous but was not the case LOG4J2-1251 + final List events = + ListAppender.getListAppender("TestAppender").getEvents(); + assertThat(events, hasSize(2)); + assertEquals("{raw}", events.get(0).getMessage().getFormattedMessage()); + assertEquals("{raw}", events.get(1).getMessage().getFormattedMessage()); + } +} 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 0000000..1562b70 --- /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/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java new file mode 100644 index 0000000..76744a3 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java @@ -0,0 +1,72 @@ +/* + * 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.Arrays; +import java.util.Collection; +import org.apache.logging.jul.tolog4j.LevelTranslator; +import org.apache.logging.log4j.Level; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Tests that all JUL levels are mapped to a Log4j level. + */ +@RunWith(Parameterized.class) +public class JavaLevelTranslatorTest { + + private final java.util.logging.Level javaLevel; + private final Level log4jLevel; + + public JavaLevelTranslatorTest(final java.util.logging.Level javaLevel, final Level log4jLevel) { + this.javaLevel = javaLevel; + this.log4jLevel = log4jLevel; + } + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { + // All 9 JUL levels, All 8 Log4j levels and extras + // @formatter:off + {java.util.logging.Level.OFF, Level.OFF}, + {java.util.logging.Level.SEVERE, Level.ERROR}, + {java.util.logging.Level.WARNING, Level.WARN}, + {java.util.logging.Level.INFO, Level.INFO}, + {java.util.logging.Level.CONFIG, LevelTranslator.CONFIG}, + {java.util.logging.Level.FINE, Level.DEBUG}, + {java.util.logging.Level.FINER, Level.TRACE}, + {java.util.logging.Level.FINEST, LevelTranslator.FINEST}, + {java.util.logging.Level.ALL, Level.ALL} + // @formatter:on + }); + } + + @Test + public void testToLevel() throws Exception { + final Level actualLevel = LevelTranslator.toLevel(javaLevel); + assertEquals(log4jLevel, actualLevel); + } + + @Test + public void testToJavaLevel() throws Exception { + final java.util.logging.Level actualLevel = LevelTranslator.toJavaLevel(log4jLevel); + assertEquals(javaLevel, actualLevel); + } +} diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java new file mode 100644 index 0000000..28c4b2f --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java @@ -0,0 +1,24 @@ +/* + * 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; + +public final class JulTestProperties { + + public static final String JUL_LOGGER_ADAPTER = "log4j.jul.loggerAdapter"; + + private JulTestProperties() {} +} diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java new file mode 100644 index 0000000..43b6796 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java @@ -0,0 +1,65 @@ +/* + * 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.Arrays; +import java.util.Collection; +import org.apache.logging.jul.tolog4j.LevelTranslator; +import org.apache.logging.log4j.Level; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * Tests that all Log4j levels are mapped to a JUL level. + */ +@RunWith(Parameterized.class) +public class Log4jLevelTranslatorTest { + + private final java.util.logging.Level javaLevel; + private final Level log4jLevel; + + public Log4jLevelTranslatorTest(final java.util.logging.Level javaLevel, final Level log4jLevel) { + this.javaLevel = javaLevel; + this.log4jLevel = log4jLevel; + } + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { + // Some JUL levels, All 8 Log4j levels + // @formatter:off + {java.util.logging.Level.OFF, Level.OFF}, + {java.util.logging.Level.SEVERE, Level.FATAL}, + {java.util.logging.Level.SEVERE, Level.ERROR}, + {java.util.logging.Level.WARNING, Level.WARN}, + {java.util.logging.Level.INFO, Level.INFO}, + {java.util.logging.Level.FINE, Level.DEBUG}, + {java.util.logging.Level.FINER, Level.TRACE}, + {java.util.logging.Level.ALL, Level.ALL}, + // @formatter:on + }); + } + + @Test + public void testToJavaLevel() throws Exception { + final java.util.logging.Level actualLevel = LevelTranslator.toJavaLevel(log4jLevel); + assertEquals(javaLevel, actualLevel); + } +} 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 0000000..ed94daa --- /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/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java new file mode 100644 index 0000000..b7da811 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.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.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.logging.Logger; +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.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ApiLoggerTest extends AbstractLoggerTest { + + @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"); + } + + @Before + public void setUp() { + logger = Logger.getLogger(LOGGER_NAME); + logger.setFilter(null); + 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"); + assertNotNull(eventAppender); + assertNotNull(flowAppender); + assertNotNull(stringAppender); + } + + @After + public void tearDown() { + if (eventAppender != null) { + eventAppender.clear(); + } + if (flowAppender != null) { + flowAppender.clear(); + } + if (stringAppender != null) { + stringAppender.clear(); + } + } + + @Test + 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() { + logger.setParent(null); + } + + @Test + public void testSetLevelFails() { + logger.setLevel(null); + } +} diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java new file mode 100644 index 0000000..825b476 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java @@ -0,0 +1,144 @@ +/* + * 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.internal; + +import org.apache.logging.jul.tolog4j.LevelTranslator; +import org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter; +import org.apache.logging.log4j.Level; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests {@link DefaultLevelConverter} for custom JUL levels. + * + * @since 2.4 + */ +public class DefaultLevelConverterCustomJulLevelsTest { + + static class CustomLevel extends java.util.logging.Level { + + 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); + static CustomLevel FINEST_M_1 = new CustomLevel("FINEST_M_1", java.util.logging.Level.FINEST.intValue() - 1); + + static CustomLevel FINER_P_1 = new CustomLevel("FINER_P_1", java.util.logging.Level.FINER.intValue() + 1); + static CustomLevel FINER_M_1 = new CustomLevel("FINER_M_1", java.util.logging.Level.FINER.intValue() - 1); + + static CustomLevel FINE_P_1 = new CustomLevel("FINE_P_1", java.util.logging.Level.FINE.intValue() + 1); + static CustomLevel FINE_M_1 = new CustomLevel("FINE_M_1", java.util.logging.Level.FINE.intValue() - 1); + + static CustomLevel CONFIG_P_1 = new CustomLevel("CONFIG_P_1", java.util.logging.Level.CONFIG.intValue() + 1); + static CustomLevel CONFIG_M_1 = new CustomLevel("CONFIG_M_1", java.util.logging.Level.CONFIG.intValue() - 1); + + static CustomLevel INFO_P_1 = new CustomLevel("INFO_P_1", java.util.logging.Level.INFO.intValue() + 1); + static CustomLevel INFO_M_1 = new CustomLevel("INFO_M_1", java.util.logging.Level.INFO.intValue() - 1); + + static CustomLevel WARNING_P_1 = new CustomLevel("WARNING_P_1", java.util.logging.Level.WARNING.intValue() + 1); + static CustomLevel WARNING_M_1 = new CustomLevel("WARNING_M_1", java.util.logging.Level.WARNING.intValue() - 1); + + static CustomLevel SEVERE_P_1 = new CustomLevel("SEVERE_P_1", java.util.logging.Level.SEVERE.intValue() + 1); + static CustomLevel SEVERE_M_1 = new CustomLevel("SEVERE_M_1", java.util.logging.Level.SEVERE.intValue() - 1); + + static CustomLevel OFF_M_1 = new CustomLevel("OFF_M_1", java.util.logging.Level.OFF.intValue() - 1); + + protected CustomLevel(final String name, final int value) { + super(name, value); + } + } + + private final DefaultLevelConverter converter = new DefaultLevelConverter(); + + @Test + public void testCustomJulLevelNearAll() { + // Sanity check: + Assert.assertEquals(Level.ALL, converter.toLevel(java.util.logging.Level.ALL)); + // Test: + Assert.assertEquals(Level.ALL, converter.toLevel(CustomLevel.ALL_P_1)); + } + + @Test + public void testCustomJulLevelNearFinest() { + // Sanity check: + Assert.assertEquals(LevelTranslator.FINEST, converter.toLevel(java.util.logging.Level.FINEST)); + // Test: + Assert.assertEquals(LevelTranslator.FINEST, converter.toLevel(CustomLevel.FINEST_P_1)); + Assert.assertEquals(LevelTranslator.FINEST, converter.toLevel(CustomLevel.FINEST_M_1)); + } + + @Test + public void testCustomJulLevelNearFiner() { + // Sanity check: + Assert.assertEquals(Level.TRACE, converter.toLevel(java.util.logging.Level.FINER)); + // Test: + Assert.assertEquals(Level.TRACE, converter.toLevel(CustomLevel.FINER_P_1)); + Assert.assertEquals(Level.TRACE, converter.toLevel(CustomLevel.FINER_M_1)); + } + + @Test + public void testCustomJulLevelNearFine() { + // Sanity check: + Assert.assertEquals(Level.DEBUG, converter.toLevel(java.util.logging.Level.FINE)); + // Test: + Assert.assertEquals(Level.DEBUG, converter.toLevel(CustomLevel.FINE_P_1)); + Assert.assertEquals(Level.DEBUG, converter.toLevel(CustomLevel.FINE_M_1)); + } + + @Test + public void testCustomJulLevelNearConfig() { + // Sanity check: + Assert.assertEquals(LevelTranslator.CONFIG, converter.toLevel(java.util.logging.Level.CONFIG)); + // Test: + Assert.assertEquals(LevelTranslator.CONFIG, converter.toLevel(CustomLevel.CONFIG_P_1)); + Assert.assertEquals(LevelTranslator.CONFIG, converter.toLevel(CustomLevel.CONFIG_M_1)); + } + + @Test + public void testCustomJulLevelNearInfo() { + // Sanity check: + Assert.assertEquals(Level.INFO, converter.toLevel(java.util.logging.Level.INFO)); + // Test: + Assert.assertEquals(Level.INFO, converter.toLevel(CustomLevel.INFO_P_1)); + Assert.assertEquals(Level.INFO, converter.toLevel(CustomLevel.INFO_M_1)); + } + + @Test + public void testCustomJulLevelNearWarning() { + // Sanity check: + Assert.assertEquals(Level.WARN, converter.toLevel(java.util.logging.Level.WARNING)); + // Test: + Assert.assertEquals(Level.WARN, converter.toLevel(CustomLevel.WARNING_P_1)); + Assert.assertEquals(Level.WARN, converter.toLevel(CustomLevel.WARNING_M_1)); + } + + @Test + public void testCustomJulLevelNearSevere() { + // Sanity check: + Assert.assertEquals(Level.ERROR, converter.toLevel(java.util.logging.Level.SEVERE)); + // Test: + Assert.assertEquals(Level.ERROR, converter.toLevel(CustomLevel.SEVERE_P_1)); + Assert.assertEquals(Level.ERROR, converter.toLevel(CustomLevel.SEVERE_M_1)); + } + + @Test + public void testCustomJulLevelNearOff() { + // Sanity check: + Assert.assertEquals(Level.OFF, converter.toLevel(java.util.logging.Level.OFF)); + // Test: + Assert.assertEquals(Level.OFF, converter.toLevel(CustomLevel.OFF_M_1)); + } +} diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java new file mode 100644 index 0000000..f93a4f4 --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java @@ -0,0 +1,33 @@ +/* + * 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.internal; + +import static org.junit.Assert.assertNull; + +import org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter; +import org.junit.Test; + +public class DefaultLevelConverterTest { + + /** + * (LOG4J2-1108) NullPointerException when passing null to java.util.logging.Logger.setLevel(). + */ + @Test + public void testJulSetNull() { + assertNull(new DefaultLevelConverter().toLevel(null)); + } +} diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java new file mode 100644 index 0000000..9e620cd --- /dev/null +++ b/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java @@ -0,0 +1,185 @@ +/* + * 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.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.junit.Test; + +/** + * + */ +public abstract class AbstractLoggerTest { + public static final String LOGGER_NAME = "Test"; + protected Logger logger; + protected ListAppender eventAppender; + protected ListAppender flowAppender; + protected ListAppender stringAppender; + + @Test + public void testGetName() { + assertThat(logger.getName()).isEqualTo(LOGGER_NAME); + } + + @Test + public void testGlobalLogger() { + final Logger root = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + root.info("Test info message"); + root.config("Test info message"); + root.fine("Test info message"); + final List events = eventAppender.getEvents(); + assertThat(events).hasSize(3); + for (final LogEvent event : events) { + final String message = event.getMessage().getFormattedMessage(); + assertThat(message).isEqualTo("Test info message"); + } + } + + @Test + public void testGlobalLoggerName() { + final Logger root = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + assertThat(root.getName()).isEqualTo(Logger.GLOBAL_LOGGER_NAME); + } + + @Test + public void testIsLoggable() { + assertThat(logger.isLoggable(java.util.logging.Level.SEVERE)).isTrue(); + } + + @Test + public void testLog() { + 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("Informative message here."); + assertThat(event.getLoggerFqcn()).isEqualTo(AbstractLogger.class.getName()); + } + + @Test + public void testLogParamMarkers() { + final Logger flowLogger = Logger.getLogger("TestFlow"); + flowLogger.logp(java.util.logging.Level.FINER, "sourceClass", "sourceMethod", "ENTER {0}", "params"); + final List events = flowAppender.getEvents(); + assertThat(events.get(0).getMessage().getFormattedMessage()).isEqualTo("ENTER params"); + } + + @Test + public void testLogUsingCustomLevel() { + logger.config("Config level"); + final List events = eventAppender.getEvents(); + assertThat(events).hasSize(1); + final LogEvent event = events.get(0); + assertThat(event.getLevel()).isEqualTo(LevelTranslator.CONFIG); + } + + @Test + public void testLogWithCallingClass() { + final Logger log = Logger.getLogger("Test.CallerClass"); + log.config("Calling from LoggerTest"); + final List messages = stringAppender.getMessages(); + assertThat(messages).hasSize(1); + final String message = messages.get(0); + assertThat(message).isEqualTo(AbstractLoggerTest.class.getName()); + } + + @Test + public void testCurlyBraces() { + testMessage("{message}"); + } + + @Test + public void testPercent() { + testMessage("message%s"); + } + + @Test + public void testPercentAndCurlyBraces() { + testMessage("message{%s}"); + } + + private void testMessage(final String string) { + final Logger root = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + root.info("Test info " + string); + root.config("Test info " + string); + root.fine("Test info " + string); + final List events = eventAppender.getEvents(); + assertThat(events).hasSize(3); + for (final LogEvent event : events) { + final String message = event.getMessage().getFormattedMessage(); + assertThat(message).isEqualTo("Test info " + string); + } + } + + @Test + public void testFlowMessages() { + final Logger flowLogger = Logger.getLogger("TestFlow"); + flowLogger.entering("com.example.TestSourceClass1", "testSourceMethod1(String)"); + flowLogger.entering("com.example.TestSourceClass2", "testSourceMethod2(String)", "TestParam"); + flowLogger.entering( + "com.example.TestSourceClass3", "testSourceMethod3(String)", new Object[] {"TestParam0", "TestParam1"}); + final List events = flowAppender.getEvents(); + assertThat(events).hasSize(3); + assertThat(events.get(0).getMessage().getFormattedMessage()).isEqualTo("Enter"); + assertThat(events.get(1).getMessage().getFormattedMessage()).isEqualTo("Enter params(TestParam)"); + assertThat(events.get(2).getMessage().getFormattedMessage()).isEqualTo("Enter params(TestParam0, TestParam1)"); + } + + @Test + public void testLambdasGlobalLogger() { + testLambdaMessages("message"); + } + + @Test + public void testLambdasCurlyBraces() { + testLambdaMessages("{message}"); + } + + @Test + public void testLambdasPercent() { + testLambdaMessages("message%s"); + } + + @Test + public void testLambdasPercentAndCurlyBraces() { + testLambdaMessages("message{%s}"); + } + + private void testLambdaMessages(final String string) { + final Logger root = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + root.info(() -> "Test info " + string); + root.config(() -> "Test info " + string); + root.fine(() -> "Test info " + string); + final List events = eventAppender.getEvents(); + assertThat(events).hasSize(3); + for (final LogEvent event : events) { + final String message = event.getMessage().getFormattedMessage(); + assertThat(message).isEqualTo("Test info " + string); + } + } +} 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 0000000..83d90f3 --- /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 0000000..087587e --- /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 0000000..3563a11 --- /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/jul-to-log4j/src/test/resources/ResourceBundleTest.xml b/jul-to-log4j/src/test/resources/ResourceBundleTest.xml new file mode 100644 index 0000000..3d2d891 --- /dev/null +++ b/jul-to-log4j/src/test/resources/ResourceBundleTest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + 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 0000000..9c5bdb2 --- /dev/null +++ b/jul-to-log4j/src/test/resources/log4j2-test.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 538c3e92d6b664dc93685cd34f5fa37b725a4318 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Wed, 6 Nov 2024 12:58:49 +0100 Subject: [PATCH 3/4] Rename `jul-to-log4j` to `jul-to-log4j-api` --- {jul-to-log4j => jul-to-log4j-api}/pom.xml | 0 .../main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java | 0 .../src/main/java/org/apache/logging/jul/tolog4j/LogManager.java | 0 .../java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java | 0 .../org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java | 0 .../logging/jul/tolog4j/internal/DefaultLevelConverter.java | 0 .../org/apache/logging/jul/tolog4j/internal/JulProperties.java | 0 .../java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java | 0 .../main/java/org/apache/logging/jul/tolog4j/package-info.java | 0 .../org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java | 0 .../java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java | 0 .../java/org/apache/logging/jul/tolog4j/spi/package-info.java | 0 .../org/apache/logging/jul/tolog4j/support/AbstractLogger.java | 0 .../java/org/apache/logging/jul/tolog4j/support/package-info.java | 0 .../src/main/resources/META-INF/log4j/propertyMapping.json | 0 .../apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java | 0 .../jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java | 0 .../apache/logging/jul/tolog4j/test/CallerInformationTest.java | 0 .../apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java | 0 .../org/apache/logging/jul/tolog4j/test/JulTestProperties.java | 0 .../apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java | 0 .../org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java | 0 .../apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java | 0 .../test/internal/DefaultLevelConverterCustomJulLevelsTest.java | 0 .../jul/tolog4j/test/internal/DefaultLevelConverterTest.java | 0 .../logging/jul/tolog4j/test/support/AbstractLoggerTest.java | 0 .../logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java | 0 .../src/test/resources/CallerInformationTest.xml | 0 .../src/test/resources/ResourceBundleTest.properties | 0 .../src/test/resources/ResourceBundleTest.xml | 0 .../src/test/resources/log4j2-test.xml | 0 31 files changed, 0 insertions(+), 0 deletions(-) rename {jul-to-log4j => jul-to-log4j-api}/pom.xml (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/package-info.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/main/resources/META-INF/log4j/propertyMapping.json (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/resources/CallerInformationTest.xml (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/resources/ResourceBundleTest.properties (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/resources/ResourceBundleTest.xml (100%) rename {jul-to-log4j => jul-to-log4j-api}/src/test/resources/log4j2-test.xml (100%) diff --git a/jul-to-log4j/pom.xml b/jul-to-log4j-api/pom.xml similarity index 100% rename from jul-to-log4j/pom.xml rename to jul-to-log4j-api/pom.xml diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/LevelTranslator.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/LogManager.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLogger.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/ApiLoggerAdapter.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/DefaultLevelConverter.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/JulProperties.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/internal/NoOpLogger.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/package-info.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/package-info.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/package-info.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/package-info.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/spi/AbstractLoggerAdapter.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/spi/LevelConverter.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/spi/package-info.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/support/AbstractLogger.java diff --git a/jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java b/jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java similarity index 100% rename from jul-to-log4j/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java rename to jul-to-log4j-api/src/main/java/org/apache/logging/jul/tolog4j/support/package-info.java diff --git a/jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json b/jul-to-log4j-api/src/main/resources/META-INF/log4j/propertyMapping.json similarity index 100% rename from jul-to-log4j/src/main/resources/META-INF/log4j/propertyMapping.json rename to jul-to-log4j-api/src/main/resources/META-INF/log4j/propertyMapping.json diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/AsyncLoggerThreadsTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/BracketInNotInterpolatedMessageTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/CallerInformationTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/JavaLevelTranslatorTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/JulTestProperties.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/Log4jLevelTranslatorTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/ResourceBundleTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/internal/ApiLoggerTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterCustomJulLevelsTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/internal/DefaultLevelConverterTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/support/AbstractLoggerTest.java diff --git a/jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java b/jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java similarity index 100% rename from jul-to-log4j/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java rename to jul-to-log4j-api/src/test/java/org/apache/logging/jul/tolog4j/test/support/CustomLoggerAdapterTest.java diff --git a/jul-to-log4j/src/test/resources/CallerInformationTest.xml b/jul-to-log4j-api/src/test/resources/CallerInformationTest.xml similarity index 100% rename from jul-to-log4j/src/test/resources/CallerInformationTest.xml rename to jul-to-log4j-api/src/test/resources/CallerInformationTest.xml diff --git a/jul-to-log4j/src/test/resources/ResourceBundleTest.properties b/jul-to-log4j-api/src/test/resources/ResourceBundleTest.properties similarity index 100% rename from jul-to-log4j/src/test/resources/ResourceBundleTest.properties rename to jul-to-log4j-api/src/test/resources/ResourceBundleTest.properties diff --git a/jul-to-log4j/src/test/resources/ResourceBundleTest.xml b/jul-to-log4j-api/src/test/resources/ResourceBundleTest.xml similarity index 100% rename from jul-to-log4j/src/test/resources/ResourceBundleTest.xml rename to jul-to-log4j-api/src/test/resources/ResourceBundleTest.xml diff --git a/jul-to-log4j/src/test/resources/log4j2-test.xml b/jul-to-log4j-api/src/test/resources/log4j2-test.xml similarity index 100% rename from jul-to-log4j/src/test/resources/log4j2-test.xml rename to jul-to-log4j-api/src/test/resources/log4j2-test.xml From f857117f586e384326b2488706ae415881c6f165 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Wed, 6 Nov 2024 13:52:04 +0100 Subject: [PATCH 4/4] Fix build --- jul-to-log4j-api/pom.xml | 85 +++++++++++++++++++++++++--------------- parent/pom.xml | 11 +++--- pom.xml | 7 ++++ 3 files changed, 65 insertions(+), 38 deletions(-) diff --git a/jul-to-log4j-api/pom.xml b/jul-to-log4j-api/pom.xml index 9e18420..02d8f8b 100644 --- a/jul-to-log4j-api/pom.xml +++ b/jul-to-log4j-api/pom.xml @@ -19,16 +19,23 @@ 4.0.0 org.apache.logging.log4j - log4j + log4j-jdk-parent ${revision} - ../log4j-parent + ../parent - jul-to-log4j - Apache Log4j JUL LogManager + jul-to-log4j-api + JUL to Log4j API logging bridge A `java.util.logging` LogManager that forwards events to the Log4j API. + + false + + + 17 + ${maven.compiler.release} + ${maven.compiler.release} @@ -40,6 +47,9 @@ org.jspecify;transitive=false + + + 3.0.0-SNAPSHOT @@ -60,18 +70,6 @@ test - - org.hamcrest - hamcrest - test - - - - junit - junit - test - - org.apache.logging.log4j log4j-async-logger @@ -89,6 +87,7 @@ log4j-core-test test + @@ -96,22 +95,6 @@ org.apache.maven.plugins maven-surefire-plugin - - - true - - -Xms256m -Xmx1024m - 1 - false - - - - - org.apache.maven.surefire - surefire-junit47 - ${surefire.version} - - default-test @@ -120,12 +103,50 @@ test + + **/AsyncLoggerThreadsTest.class + **/CustomLoggerAdapterTest.class + org.apache.logging.jul.tolog4j.LogManager + + async-logger-test + + test + + test + + + **/AsyncLoggerThreadsTest.class + + + + org.apache.logging.jul.tolog4j.LogManager + org.apache.logging.log4j.async.logger.AsyncLoggerContextSelector + + + + + custom-logger-adapter-test + + test + + test + + + **/CustomLoggerAdapterTest.class + + + + org.apache.logging.jul.tolog4j.LogManager + org.apache.logging.jul.tolog4j.test.support.CustomLoggerAdapterTest$CustomLoggerAdapter + + + diff --git a/parent/pom.xml b/parent/pom.xml index 01efcec..1fe30f7 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -34,6 +34,11 @@ false + + 9 + ${maven.compiler.release} + ${maven.compiler.release} + 3.26.3 7.0.0 @@ -71,12 +76,6 @@ import - - org.hamcrest - hamcrest - ${hamcrest.version} - - org.junit junit-bom diff --git a/pom.xml b/pom.xml index 1b8ff72..cef6b71 100644 --- a/pom.xml +++ b/pom.xml @@ -60,6 +60,7 @@ jpl-to-log4j-api + jul-to-log4j-api log4j-api-to-jul @@ -107,6 +108,12 @@ ${project.version} + + org.apache.logging.log4j + jul-to-log4j-api + ${project.version} + + org.apache.logging.log4j log4j-api-to-jul