Skip to content

Commit 0de1b92

Browse files
committed
Remove CoreLogger and mode level propagator to new module
1 parent cde1fbc commit 0de1b92

File tree

23 files changed

+1005
-859
lines changed

23 files changed

+1005
-859
lines changed

log4j-jul-propagator/pom.xml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to you under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
<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">
19+
<modelVersion>4.0.0</modelVersion>
20+
<parent>
21+
<groupId>org.apache.logging.log4j</groupId>
22+
<artifactId>log4j</artifactId>
23+
<version>${revision}</version>
24+
<relativePath>../log4j-parent</relativePath>
25+
</parent>
26+
27+
<artifactId>log4j-jul-propagator</artifactId>
28+
<name>Apache Log4j API to JUL bridge: level propagator</name>
29+
<description>Propagates Log4j levels from Log4j Core to JUL to improve performance.</description>
30+
31+
<dependencies>
32+
33+
<dependency>
34+
<groupId>org.apache.logging.log4j</groupId>
35+
<artifactId>log4j-api</artifactId>
36+
</dependency>
37+
38+
<dependency>
39+
<groupId>org.apache.logging.log4j</groupId>
40+
<artifactId>log4j-core</artifactId>
41+
</dependency>
42+
43+
<dependency>
44+
<groupId>org.apache.logging.log4j</groupId>
45+
<artifactId>log4j-jul</artifactId>
46+
</dependency>
47+
48+
<dependency>
49+
<groupId>org.assertj</groupId>
50+
<artifactId>assertj-core</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
54+
<dependency>
55+
<groupId>org.junit.jupiter</groupId>
56+
<artifactId>junit-jupiter-api</artifactId>
57+
<scope>test</scope>
58+
</dependency>
59+
60+
</dependencies>
61+
62+
<build>
63+
<plugins>
64+
65+
<plugin>
66+
<groupId>org.apache.maven.plugins</groupId>
67+
<artifactId>maven-surefire-plugin</artifactId>
68+
<executions>
69+
<execution>
70+
<id>default-test</id>
71+
<goals>
72+
<goal>test</goal>
73+
</goals>
74+
<phase>test</phase>
75+
<configuration>
76+
<excludes>
77+
<exclude>Log4jBridgeHandlerTest.java</exclude>
78+
</excludes>
79+
<systemPropertyVariables>
80+
<java.util.logging.config.file>${project.basedir}/src/test/resources/logging-test.properties</java.util.logging.config.file>
81+
</systemPropertyVariables>
82+
</configuration>
83+
</execution>
84+
</executions>
85+
</plugin>
86+
87+
</plugins>
88+
</build>
89+
</project>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.jul.propagator;
18+
19+
import aQute.bnd.annotation.spi.ServiceProvider;
20+
import java.util.Enumeration;
21+
import java.util.HashSet;
22+
import java.util.Map;
23+
import java.util.Set;
24+
import java.util.concurrent.atomic.AtomicInteger;
25+
import java.util.function.Consumer;
26+
import org.apache.logging.log4j.Logger;
27+
import org.apache.logging.log4j.core.LoggerContext;
28+
import org.apache.logging.log4j.core.config.Configuration;
29+
import org.apache.logging.log4j.core.config.LoggerConfig;
30+
import org.apache.logging.log4j.jul.LevelTranslator;
31+
import org.apache.logging.log4j.jul.Log4jBridgeHandler;
32+
import org.apache.logging.log4j.status.StatusLogger;
33+
34+
/**
35+
* Propagates Log4j Core level to JUL.
36+
*/
37+
@ServiceProvider(value = Log4jBridgeHandler.LevelPropagator.class)
38+
public class JulLevelPropagator implements Log4jBridgeHandler.LevelPropagator, Consumer<Configuration> {
39+
40+
private static final Logger LOGGER = StatusLogger.getLogger();
41+
42+
private final AtomicInteger installCount = new AtomicInteger();
43+
private LoggerContext context;
44+
/** Save "hard" references to configured JUL loggers. */
45+
private final Set<java.util.logging.Logger> julLoggerRefs = new HashSet<>();
46+
47+
@Override
48+
public void start() {
49+
if (installCount.getAndIncrement() == 0) {
50+
context = LoggerContext.getContext(false);
51+
LOGGER.info("Installing Log4j Core to JUL level propagator for context `{}`", context);
52+
context.addConfigurationStartedListener(this);
53+
propagateLogLevels(context.getConfiguration());
54+
}
55+
}
56+
57+
@Override
58+
public void stop() {
59+
if (installCount.decrementAndGet() == 0) {
60+
LOGGER.info("Uninstalling Log4j Core to JUL level propagator for context `{}`", context);
61+
context.removeConfigurationStartedListener(this);
62+
context = null;
63+
julLoggerRefs.clear();
64+
}
65+
}
66+
67+
@Override
68+
public void accept(Configuration configuration) {
69+
propagateLogLevels(configuration);
70+
}
71+
72+
private void propagateLogLevels(final Configuration configuration) {
73+
LOGGER.info("Starting Log4j Core to JUL level propagation for configuration `{}`", configuration);
74+
// clear or init. saved JUL logger references
75+
// JUL loggers have to be explicitly referenced because JUL internally uses
76+
// weak references so not instantiated loggers may be garbage collected
77+
// and their level config gets lost then.
78+
julLoggerRefs.clear();
79+
80+
final Map<String, LoggerConfig> log4jLoggers = configuration.getLoggers();
81+
for (LoggerConfig loggerConfig : log4jLoggers.values()) {
82+
final java.util.logging.Logger julLog =
83+
java.util.logging.Logger.getLogger(loggerConfig.getName()); // this also fits for root = ""
84+
final java.util.logging.Level julLevel =
85+
LevelTranslator.toJavaLevel(loggerConfig.getLevel()); // loggerConfig.getLevel() never returns null
86+
julLog.setLevel(julLevel);
87+
julLoggerRefs.add(julLog);
88+
}
89+
final java.util.logging.LogManager julMgr = java.util.logging.LogManager.getLogManager();
90+
for (Enumeration<String> en = julMgr.getLoggerNames(); en.hasMoreElements(); ) {
91+
final java.util.logging.Logger julLog = julMgr.getLogger(en.nextElement());
92+
if (julLog != null
93+
&& julLog.getLevel() != null
94+
&& !"".equals(julLog.getName())
95+
&& !log4jLoggers.containsKey(julLog.getName())) {
96+
julLog.setLevel(null);
97+
}
98+
}
99+
}
100+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.jul.propagator;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import java.util.logging.Level;
22+
import java.util.logging.Logger;
23+
import org.apache.logging.log4j.core.config.Configurator;
24+
import org.apache.logging.log4j.jul.LevelTranslator;
25+
import org.junit.jupiter.api.AfterEach;
26+
import org.junit.jupiter.api.BeforeAll;
27+
import org.junit.jupiter.api.Test;
28+
29+
class JulLevelPropagatorTest {
30+
31+
@BeforeAll
32+
static void setup() {
33+
// Ensure that at least one message was sent.
34+
Logger.getGlobal().info("Initialize");
35+
}
36+
37+
@AfterEach
38+
void cleanup() {
39+
org.apache.logging.log4j.core.LoggerContext.getContext(false).reconfigure();
40+
}
41+
42+
@Test
43+
void initial_synchronization_works() {
44+
// JUL levels are set from config files and the initial propagation
45+
assertThat(Logger.getLogger("").getLevel()).isEqualTo(Level.SEVERE);
46+
assertThat(Logger.getLogger("foo").getLevel()).isEqualTo(Level.WARNING);
47+
assertThat(Logger.getLogger("foo.bar").getLevel()).isEqualTo(Level.INFO);
48+
}
49+
50+
@Test
51+
void synchronization_retained_after_GC() {
52+
initial_synchronization_works();
53+
System.gc(); // a single call is sufficient
54+
initial_synchronization_works();
55+
}
56+
57+
@Test
58+
void when_set_level_synchronization_works() {
59+
Configurator.setLevel("", LevelTranslator.CONFIG);
60+
Configurator.setLevel("foo", org.apache.logging.log4j.Level.DEBUG);
61+
Configurator.setLevel("foo.bar", org.apache.logging.log4j.Level.TRACE);
62+
63+
assertThat(Logger.getLogger("").getLevel()).isEqualTo(Level.CONFIG);
64+
assertThat(Logger.getLogger("foo").getLevel()).isEqualTo(Level.FINE);
65+
assertThat(Logger.getLogger("foo.bar").getLevel()).isEqualTo(Level.FINER);
66+
}
67+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one or more
4+
~ contributor license agreements. See the NOTICE file distributed with
5+
~ this work for additional information regarding copyright ownership.
6+
~ The ASF licenses this file to you under the Apache License, Version 2.0
7+
~ (the "License"); you may not use this file except in compliance with
8+
~ the License. You may obtain a copy of the License at
9+
~
10+
~ http://www.apache.org/licenses/LICENSE-2.0
11+
~
12+
~ Unless required by applicable law or agreed to in writing, software
13+
~ distributed under the License is distributed on an "AS IS" BASIS,
14+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
~ See the License for the specific language governing permissions and
16+
~ limitations under the License.
17+
-->
18+
<Configuration xmlns="https://logging.apache.org/xml/ns">
19+
<Appenders/>
20+
<Loggers>
21+
<Root level="ERROR"/>
22+
<Logger name="foo" level="WARN"/>
23+
<Logger name="foo.bar" level="INFO"/>
24+
</Loggers>
25+
</Configuration>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to you under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
### JUL configuration for JulLevelPropagatorTest
18+
# Install the bridge
19+
handlers=org.apache.logging.log4j.jul.Log4jBridgeHandler
20+
# Propagate levels
21+
org.apache.logging.log4j.jul.Log4jBridgeHandler.propagateLevels=true

log4j-jul/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@
2828
<name>Apache Log4j JUL Adapter</name>
2929
<description>The Apache Log4j implementation of java.util.logging</description>
3030

31+
<properties>
32+
<bnd-extra-package-options>
33+
<!-- Optional annotations -->
34+
org.jspecify.*;resolution:=optional
35+
</bnd-extra-package-options>
36+
<bnd-extra-module-options>
37+
<!-- Optional modules can not be `transitive` -->
38+
org.jspecify;transitive=false
39+
</bnd-extra-module-options>
40+
</properties>
41+
3142
<dependencies>
3243

3344
<dependency>
@@ -110,6 +121,9 @@
110121
<excludes>
111122
<exclude>Log4jBridgeHandlerTest.java</exclude>
112123
</excludes>
124+
<systemPropertyVariables>
125+
<java.util.logging.manager>org.apache.logging.log4j.jul.LogManager</java.util.logging.manager>
126+
</systemPropertyVariables>
113127
</configuration>
114128
</execution>
115129
<execution>

0 commit comments

Comments
 (0)