Skip to content

Modernize and split log4j-jul #2935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions jul-to-log4j/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>${revision}</version>
<relativePath>../log4j-parent</relativePath>
</parent>

<artifactId>jul-to-log4j</artifactId>
<name>Apache Log4j JUL LogManager</name>
<description>A `java.util.logging` LogManager that forwards events to the Log4j API.</description>

<properties>
<!--
~ OSGi and JPMS options
-->
<bnd-extra-package-options>
<!-- Optional annotations -->
org.jspecify.*;resolution:=optional
</bnd-extra-package-options>
<bnd-extra-module-options>
<!-- Optional modules can not be `transitive` -->
org.jspecify;transitive=false
</bnd-extra-module-options>
</properties>

<dependencies>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-kit</artifactId>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-async-logger</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<java.awt.headless>true</java.awt.headless>
</systemPropertyVariables>
<argLine>-Xms256m -Xmx1024m</argLine>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
<dependencies>
<!-- The `surefire-junit-platform` provider initializes JUL before tests start -->
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>${surefire.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default-test</id>
<goals>
<goal>test</goal>
</goals>
<phase>test</phase>
<configuration>
<!-- Use custom `j.u.l.LogManager` -->
<systemPropertyVariables>
<java.util.logging.manager>org.apache.logging.jul.tolog4j.LogManager</java.util.logging.manager>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.logging.log4j.jul;
package org.apache.logging.jul.tolog4j;

import org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter;
import org.apache.logging.jul.tolog4j.internal.JulProperties;
import org.apache.logging.jul.tolog4j.spi.LevelConverter;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.kit.env.PropertyEnvironment;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.logging.log4j.jul;
package org.apache.logging.jul.tolog4j;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.logging.log4j.LoggingException;
import org.apache.logging.jul.tolog4j.internal.ApiLoggerAdapter;
import org.apache.logging.jul.tolog4j.internal.JulProperties;
import org.apache.logging.jul.tolog4j.internal.NoOpLogger;
import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
import org.apache.logging.log4j.kit.env.PropertyEnvironment;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;

/**
* Log4j implementation of {@link java.util.logging.LogManager}. Note that the system property
* {@code java.util.logging.manager} must be set to {@code org.apache.logging.log4j.jul.LogManager} in order to use
* this adaptor. This LogManager requires the {@code log4j-api} library to be available. If {@code log4j-core} is
* also available, then more features of {@link java.util.logging.Logger} are supported.
*
* <p>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.</p>
* Log4j implementation of {@link java.util.logging.LogManager}.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
*
* @since 2.1
*/
public class LogManager extends java.util.logging.LogManager {

private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
private static final String CORE_LOGGER_CLASS_NAME = "org.apache.logging.log4j.core.Logger";
private static final String CORE_LOGGER_ADAPTER_CLASS_NAME = "org.apache.logging.log4j.jul.CoreLoggerAdapter";
private static final String API_LOGGER_ADAPTER_CLASS_NAME = "org.apache.logging.log4j.jul.ApiLoggerAdapter";
private final AbstractLoggerAdapter loggerAdapter;
// Contains the set of logger names that are actively being requested using getLogger.
private final ThreadLocal<Set<String>> recursive = ThreadLocal.withInitial(HashSet::new);
Expand All @@ -62,21 +66,9 @@ public LogManager() {
}
}
if (adapter == null) {
// default adapter
String adapterClassName;
try {
// find out if log4j-core is available
LoaderUtil.loadClass(CORE_LOGGER_CLASS_NAME);
adapterClassName = CORE_LOGGER_ADAPTER_CLASS_NAME;
} catch (final ClassNotFoundException ignored) {
adapterClassName = API_LOGGER_ADAPTER_CLASS_NAME;
}
LOGGER.debug("Attempting to use {}", adapterClassName);
try {
adapter = LoaderUtil.newCheckedInstanceOf(adapterClassName, AbstractLoggerAdapter.class);
} catch (final Exception e) {
throw LOGGER.throwing(new LoggingException(e));
}
// Use API by default
// See https://github.com/apache/logging-log4j2/issues/2353
adapter = new ApiLoggerAdapter();
}
loggerAdapter = adapter;
LOGGER.info("Registered Log4j as the java.util.logging.LogManager.");
Expand Down
Original file line number Diff line number Diff line change
@@ -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()`.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.logging.log4j.jul;
package org.apache.logging.jul.tolog4j.internal;

import java.util.logging.Logger;
import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.message.MessageFormatMessageFactory;
import org.apache.logging.log4j.spi.LoggerContext;
Expand All @@ -32,7 +33,7 @@ public class ApiLoggerAdapter extends AbstractLoggerAdapter {
private static final MessageFactory MESSAGE_FACTORY = new MessageFormatMessageFactory();

@Override
protected Logger newLogger(final String name, final LoggerContext context) {
public Logger newLogger(final String name, final LoggerContext context) {
return new ApiLogger(context.getLogger(name, MESSAGE_FACTORY));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.logging.log4j.jul;
package org.apache.logging.jul.tolog4j.internal;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -24,6 +24,8 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.logging.jul.tolog4j.LevelTranslator;
import org.apache.logging.jul.tolog4j.spi.LevelConverter;
import org.apache.logging.log4j.Level;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.logging.log4j.jul;
package org.apache.logging.jul.tolog4j.internal;

import org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter;
import org.apache.logging.jul.tolog4j.spi.LevelConverter;
import org.apache.logging.log4j.kit.env.Log4jProperty;
import org.jspecify.annotations.Nullable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.logging.log4j.jul;
package org.apache.logging.jul.tolog4j.internal;

import java.util.ResourceBundle;
import java.util.function.Supplier;
Expand All @@ -27,7 +27,7 @@
*/
public class NoOpLogger extends Logger {

protected NoOpLogger(final String name) {
public NoOpLogger(final String name) {
super(name, null);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Loading