This is an automated email from the ASF dual-hosted git repository. rgoers pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 8ab11ceb594090ebd821842cc71c55a7a56b4252 Author: Kevin Leturc <[email protected]> AuthorDate: Fri Mar 20 15:18:44 2020 +0100 LOG4J2-1360 - Provide a Log4j implementation of System.Logger --- log4j-jpl/pom.xml | 188 +++++++++++++++++++++ log4j-jpl/src/main/java/module-info.java | 21 +++ .../logging/log4j/jpl/Log4jSystemLogger.java | 136 +++++++++++++++ .../log4j/jpl/Log4jSystemLoggerAdapter.java | 43 +++++ .../logging/log4j/jpl/Log4jSystemLoggerFinder.java | 33 ++++ .../services/java.lang.System$LoggerFinder | 1 + .../logging/log4j/jpl/Log4jSystemLoggerTest.java | 122 +++++++++++++ log4j-jpl/src/test/resources/log4j2-test.xml | 39 +++++ pom.xml | 6 + 9 files changed, 589 insertions(+) diff --git a/log4j-jpl/pom.xml b/log4j-jpl/pom.xml new file mode 100644 index 0000000..c0e5269 --- /dev/null +++ b/log4j-jpl/pom.xml @@ -0,0 +1,188 @@ +<?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"> + <parent> + <artifactId>log4j</artifactId> + <groupId>org.apache.logging.log4j</groupId> + <version>3.0.0-SNAPSHOT</version> + <relativePath>../</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <properties> + <log4jParentDir>${basedir}/..</log4jParentDir> + <module.name>org.apache.logging.log4j.jpl</module.name> + </properties> + + <artifactId>log4j-jpl</artifactId> + <name>Apache Log4j JDK Platform Logging Adapter</name> + <description>The Apache Log4j implementation of java.lang.System.LoggerFinder</description> + + <dependencies> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + </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</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-all</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <!-- Include the standard NOTICE and LICENSE --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-remote-resources-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>process</goal> + </goals> + <configuration> + <skip>false</skip> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <Fragment-Host>org.apache.logging.log4j.core</Fragment-Host> + <Export-Package>org.apache.logging.log4j.jpl</Export-Package> + </instructions> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-toolchains-plugin</artifactId> + <version>1.1</version> + <executions> + <execution> + <goals> + <goal>toolchain</goal> + </goals> + </execution> + </executions> + <configuration> + <toolchains> + <jdk> + <version>[11, )</version> + </jdk> + </toolchains> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <executions> + <execution> + <id>default-compile</id> + <phase>compile</phase> + <goals> + <goal>compile</goal> + </goals> + </execution> + <execution> + <id>default-testCompile</id> + <phase>test-compile</phase> + <goals> + <goal>testCompile</goal> + </goals> + </execution> + </executions> + <configuration> + <source>11</source> + <target>11</target> + <release>11</release> + <proc>none</proc> + <!-- disable errorprone --> + <compilerId>javac</compilerId> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <!-- Do not upgrade until https://issues.apache.org/jira/browse/SUREFIRE-720 is fixed --> + <version>2.13</version> + <configuration> + <excludes combine.self="override" /> + </configuration> + <executions> + <execution> + <id>test</id> + <phase>test</phase> + <goals> + <goal>test</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + <profiles> + <profile> + <id>java11-module</id> + <activation> + <jdk>[11,)</jdk> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <!-- Use Maven Surefire 2.21 which brings module support --> + <version>${surefire.plugin.version}</version> + <!-- Disable forked VM as 2.21 yields https://issues.apache.org/jira/browse/SUREFIRE-720 --> + <configuration combine.self="override"/> + <executions> + <execution> + <id>test</id> + <phase>test</phase> + <goals> + <goal>test</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> diff --git a/log4j-jpl/src/main/java/module-info.java b/log4j-jpl/src/main/java/module-info.java new file mode 100644 index 0000000..2788318 --- /dev/null +++ b/log4j-jpl/src/main/java/module-info.java @@ -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. + */ +module org.apache.logging.log4j.jpl { + requires org.apache.logging.log4j; + + provides java.lang.System.LoggerFinder with org.apache.logging.log4j.jpl.Log4jSystemLoggerFinder; +} diff --git a/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLogger.java b/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLogger.java new file mode 100644 index 0000000..925ca71 --- /dev/null +++ b/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLogger.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.logging.log4j.jpl; + +import java.lang.System.Logger; +import java.util.MissingResourceException; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.function.Supplier; + +import org.apache.logging.log4j.spi.ExtendedLogger; + +/** + * JPL {@link Logger logger} implementation that uses Log4j. + * Implement all default {@link Logger} methods to ensure proper class resolution + * + * @since 2.14 + */ +public class Log4jSystemLogger implements Logger { + + private final ExtendedLogger logger; + + private static final String FQCN = Log4jSystemLogger.class.getName(); + + public Log4jSystemLogger(final ExtendedLogger logger) { + this.logger = logger; + } + + @Override + public String getName() { + return logger.getName(); + } + + @Override + public boolean isLoggable(final Level level) { + return logger.isEnabled(getLevel(level)); + } + + @Override + public void log(Level level, String msg) { + log(level, (ResourceBundle) null, msg, (Object[]) null); + } + + @Override + public void log(Level level, Supplier<String> msgSupplier) { + Objects.requireNonNull(msgSupplier); + if (isLoggable(Objects.requireNonNull(level))) { + log(level, (ResourceBundle) null, msgSupplier.get(), (Object[]) null); + } + } + + @Override + public void log(Level level, Object obj) { + Objects.requireNonNull(obj); + if (isLoggable(Objects.requireNonNull(level))) { + log(level, (ResourceBundle) null, obj.toString(), (Object[]) null); + } + } + + @Override + public void log(Level level, String msg, Throwable thrown) { + log(level, null, msg, thrown); + } + + @Override + public void log(Level level, Supplier<String> msgSupplier, Throwable thrown) { + Objects.requireNonNull(msgSupplier); + if (isLoggable(Objects.requireNonNull(level))) { + log(level, null, msgSupplier.get(), thrown); + } + } + + @Override + public void log(Level level, String format, Object... params) { + log(level, null, format, params); + } + + @Override + public void log(final Level level, final ResourceBundle bundle, final String msg, final Throwable thrown) { + logger.logIfEnabled(FQCN, getLevel(level), null, getResource(bundle, msg), thrown); + } + + @Override + public void log(final Level level, final ResourceBundle bundle, final String format, final Object... params) { + logger.logIfEnabled(FQCN, getLevel(level), null, getResource(bundle, format), params); + } + + private static org.apache.logging.log4j.Level getLevel(final Level level) { + switch (level) { + case OFF: + return org.apache.logging.log4j.Level.OFF; + case ERROR: + return org.apache.logging.log4j.Level.ERROR; + case WARNING: + return org.apache.logging.log4j.Level.WARN; + case INFO: + return org.apache.logging.log4j.Level.INFO; + case DEBUG: + return org.apache.logging.log4j.Level.DEBUG; + case TRACE: + return org.apache.logging.log4j.Level.TRACE; + case ALL: + return org.apache.logging.log4j.Level.ALL; + } + return org.apache.logging.log4j.Level.ERROR; + } + + private static String getResource(ResourceBundle bundle, String msg) { + if (bundle == null || msg == null) { + return msg; + } + try { + return bundle.getString(msg); + } catch (MissingResourceException e) { + // ignore + return msg; + } catch (ClassCastException ex) { + return bundle.getObject(msg).toString(); + } + } +} diff --git a/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerAdapter.java b/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerAdapter.java new file mode 100644 index 0000000..3db9b52 --- /dev/null +++ b/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerAdapter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.logging.log4j.jpl; + +import java.lang.System.Logger; +import java.lang.System.LoggerFinder; + +import org.apache.logging.log4j.spi.AbstractLoggerAdapter; +import org.apache.logging.log4j.spi.LoggerContext; +import org.apache.logging.log4j.util.StackLocatorUtil; + +/** + * {@link Logger} registry implementation using just log4j-api. + * + * @since 2.14 + */ +public class Log4jSystemLoggerAdapter extends AbstractLoggerAdapter<Logger> { + + @Override + protected Logger newLogger(String name, LoggerContext context) { + return new Log4jSystemLogger(context.getLogger(name)); + } + + @Override + protected LoggerContext getContext() { + return getContext(StackLocatorUtil.getCallerClass(LoggerFinder.class)); + } +} diff --git a/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerFinder.java b/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerFinder.java new file mode 100644 index 0000000..cb8670d --- /dev/null +++ b/log4j-jpl/src/main/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerFinder.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.log4j.jpl; + +import java.lang.System.Logger; + +/** + * @since 2.14 + */ +public class Log4jSystemLoggerFinder extends System.LoggerFinder { + + private final Log4jSystemLoggerAdapter loggerAdapter = new Log4jSystemLoggerAdapter(); + + @Override + public Logger getLogger(String name, Module module) { + return loggerAdapter.getLogger(name); + } +} diff --git a/log4j-jpl/src/main/resources/META-INF/services/java.lang.System$LoggerFinder b/log4j-jpl/src/main/resources/META-INF/services/java.lang.System$LoggerFinder new file mode 100644 index 0000000..b959e7e --- /dev/null +++ b/log4j-jpl/src/main/resources/META-INF/services/java.lang.System$LoggerFinder @@ -0,0 +1 @@ +org.apache.logging.log4j.jpl.Log4jSystemLoggerFinder \ No newline at end of file diff --git a/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java b/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java new file mode 100644 index 0000000..ccc4b3c --- /dev/null +++ b/log4j-jpl/src/test/java/org/apache/logging/log4j/jpl/Log4jSystemLoggerTest.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.logging.log4j.jpl; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.lang.System.Logger; +import java.util.List; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.test.appender.ListAppender; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class Log4jSystemLoggerTest { + + public static final String LOGGER_NAME = "Test"; + protected Logger logger; + protected ListAppender eventAppender; + protected ListAppender stringAppender; + + @Before + public void setUp() throws Exception { + logger = System.getLogger(LOGGER_NAME); + assertThat(logger, instanceOf(Log4jSystemLogger.class)); + eventAppender = ListAppender.getListAppender("TestAppender"); + stringAppender = ListAppender.getListAppender("StringAppender"); + assertNotNull(eventAppender); + assertNotNull(stringAppender); + } + + @After + public void tearDown() throws Exception { + if (eventAppender != null) { + eventAppender.clear(); + } + if (stringAppender != null) { + stringAppender.clear(); + } + } + + @Test + public void testGetName() throws Exception { + assertThat(logger.getName(), equalTo(LOGGER_NAME)); + } + + @Test + public void testIsLoggable() throws Exception { + assertThat(logger.isLoggable(Logger.Level.ERROR), equalTo(true)); + } + + @Test + public void testLog() throws Exception { + logger.log(Logger.Level.INFO, "Informative message here."); + final List<LogEvent> events = eventAppender.getEvents(); + assertThat(events, hasSize(1)); + final LogEvent event = events.get(0); + assertThat(event, instanceOf(Log4jLogEvent.class)); + assertEquals(Level.INFO, event.getLevel()); + assertEquals(LOGGER_NAME, event.getLoggerName()); + assertEquals("Informative message here.", event.getMessage().getFormattedMessage()); + assertEquals(Log4jSystemLogger.class.getName(), event.getLoggerFqcn()); + } + + @Test + public void testLogWithCallingClass() throws Exception { + final Logger log = System.getLogger("Test.CallerClass"); + log.log(Logger.Level.INFO, "Calling from LoggerTest"); + final List<String> messages = stringAppender.getMessages(); + assertThat(messages, hasSize(1)); + final String message = messages.get(0); + assertEquals(Log4jSystemLoggerTest.class.getName(), message); + } + + @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) { + logger.log(Logger.Level.INFO, "Test info " + string); + final List<LogEvent> events = eventAppender.getEvents(); + assertThat(events, hasSize(1)); + for (final LogEvent event : events) { + final String message = event.getMessage().getFormattedMessage(); + assertThat(message, equalTo("Test info " + string)); + } + } +} diff --git a/log4j-jpl/src/test/resources/log4j2-test.xml b/log4j-jpl/src/test/resources/log4j2-test.xml new file mode 100644 index 0000000..27cef64 --- /dev/null +++ b/log4j-jpl/src/test/resources/log4j2-test.xml @@ -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. + --> + +<Configuration name="LoggerTest" status="OFF"> + <Appenders> + <List name="TestAppender"/> + <List name="StringAppender"> + <PatternLayout pattern="%class"/> + </List> + <Console name="Console" target="SYSTEM_ERR"> + <PatternLayout pattern="%highlight{%p - %m%n}"/> + </Console> + </Appenders> + <Loggers> + <Logger name="Test" level="DEBUG" additivity="false"> + <AppenderRef ref="TestAppender"/> + </Logger> + <Logger name="Test.CallerClass" level="DEBUG" additivity="false"> + <AppenderRef ref="StringAppender"/> + </Logger> + <Root level="ERROR"> + <AppenderRef ref="Console"/> + </Root> + </Loggers> +</Configuration> diff --git a/pom.xml b/pom.xml index 8b99e05..5fee35c 100644 --- a/pom.xml +++ b/pom.xml @@ -430,6 +430,11 @@ </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-jpl</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-taglib</artifactId> <version>${project.version}</version> </dependency> @@ -1545,6 +1550,7 @@ <module>log4j-perf</module> <module>log4j-iostreams</module> <module>log4j-jul</module> + <module>log4j-jpl</module> <module>log4j-liquibase</module> <module>log4j-appserver</module> <module>log4j-smtp</module>
