Skip to content

Commit

Permalink
Add Tomcat JULI implementation
Browse files Browse the repository at this point in the history
Adds a Tomcat JULI implementation that can replace the one in
`org.apache.logging.log4:log4j-appserver`.

The main differences between this implementation and the official one:

 * it retrieves the correct logger context by setting `fqcn` to
   `org.apache.juli.LogFactory` instead of the class name of the logger,
 * it does not treat the filenames `log4j2-tomcat.*` differently,
   leaving the configuration entirely to the implementation.
  • Loading branch information
ppkarwasz committed Jan 28, 2024
1 parent 561b255 commit 068c1af
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 0 deletions.
75 changes: 75 additions & 0 deletions log4j-tomcat-juli/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright © 2024 Piotr P. Karwasz
~
~ Licensed 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>eu.copernik</groupId>
<artifactId>log4j-plugins-parent</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>

<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-tomcat-juli</artifactId>
<name>Tomcat JULI to Log4j API bridge</name>
<description>Tomcat JULI implementation that forwards to the Log4j API.</description>

<properties>
<bnd.baseline.fail.on.missing>false</bnd.baseline.fail.on.missing>
</properties>

<dependencies>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bnd.annotation</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright © 2024 Piotr P. Karwasz
*
* Licensed 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 eu.copernik.log4j.tomcat.juli;

import aQute.bnd.annotation.Resolution;
import aQute.bnd.annotation.spi.ServiceProvider;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.LoggerContextFactory;

/**
* An implementation of {@link Log} that forwards everything to the appropriate Log4j API logger.
*/
@ServiceProvider(value = Log.class, resolution = Resolution.OPTIONAL)
public class Log4jLog implements Log {

private static final String FQCN = Log4jLog.class.getName();
private static final String LOG_FACTORY_FQCN = LogFactory.class.getName();
private static final Marker TOMCAT_MARKER = MarkerManager.getMarker("TOMCAT");

private ExtendedLogger logger;

// Only used by ServiceLoader
public Log4jLog() {
this(LogManager.ROOT_LOGGER_NAME);
}

public Log4jLog(final String name) {
this(LogManager.getFactory(), name);
}

Log4jLog(final LoggerContextFactory factory, final String name) {
this.logger = factory.getContext(LOG_FACTORY_FQCN, null, null, false).getLogger(name);
}

@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled(TOMCAT_MARKER);
}

@Override
public boolean isErrorEnabled() {
return logger.isDebugEnabled(TOMCAT_MARKER);
}

@Override
public boolean isFatalEnabled() {
return logger.isFatalEnabled(TOMCAT_MARKER);
}

@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled(TOMCAT_MARKER);
}

@Override
public boolean isTraceEnabled() {
return logger.isTraceEnabled(TOMCAT_MARKER);
}

@Override
public boolean isWarnEnabled() {
return logger.isWarnEnabled(TOMCAT_MARKER);
}

@Override
public void trace(final Object message) {
logger.logIfEnabled(FQCN, Level.TRACE, TOMCAT_MARKER, message, null);
}

@Override
public void trace(final Object message, final Throwable t) {
logger.logIfEnabled(FQCN, Level.TRACE, TOMCAT_MARKER, message, t);
}

@Override
public void debug(final Object message) {
logger.logIfEnabled(FQCN, Level.DEBUG, TOMCAT_MARKER, message, null);
}

@Override
public void debug(final Object message, final Throwable t) {
logger.logIfEnabled(FQCN, Level.DEBUG, TOMCAT_MARKER, message, t);
}

@Override
public void info(final Object message) {
logger.logIfEnabled(FQCN, Level.INFO, TOMCAT_MARKER, message, null);
}

@Override
public void info(final Object message, final Throwable t) {
logger.logIfEnabled(FQCN, Level.INFO, TOMCAT_MARKER, message, t);
}

@Override
public void warn(final Object message) {
logger.logIfEnabled(FQCN, Level.WARN, TOMCAT_MARKER, message, null);
}

@Override
public void warn(final Object message, final Throwable t) {
logger.logIfEnabled(FQCN, Level.WARN, TOMCAT_MARKER, message, t);
}

@Override
public void error(final Object message) {
logger.logIfEnabled(FQCN, Level.ERROR, TOMCAT_MARKER, message, null);
}

@Override
public void error(final Object message, final Throwable t) {
logger.logIfEnabled(FQCN, Level.ERROR, TOMCAT_MARKER, message, t);
}

@Override
public void fatal(final Object message) {
logger.logIfEnabled(FQCN, Level.FATAL, TOMCAT_MARKER, message, null);
}

@Override
public void fatal(final Object message, final Throwable t) {
logger.logIfEnabled(FQCN, Level.FATAL, TOMCAT_MARKER, message, t);
}
}
81 changes: 81 additions & 0 deletions log4j-tomcat-juli/src/test/java/Log4jLogTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright © 2024 Piotr P. Karwasz
*
* Licensed 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.
*/
import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.junit.jupiter.api.Test;

class Log4jLogTest {

private static final String MESSAGE = "MESSAGE";
private static final Throwable T = new RuntimeException();

@Test
void location() {
final Log log = LogFactory.getLog("location");
int i = 0;
int currentLine = 37;
log.trace(MESSAGE + i++);
log.trace(MESSAGE + i++, T);
log.debug(MESSAGE + i++);
log.debug(MESSAGE + i++, T);
log.info(MESSAGE + i++);
log.info(MESSAGE + i++, T);
log.warn(MESSAGE + i++);
log.warn(MESSAGE + i++, T);
log.error(MESSAGE + i++);
log.error(MESSAGE + i++, T);
log.fatal(MESSAGE + i++);
log.fatal(MESSAGE + i, T);
// Verification
final LoggerContext context = LoggerContext.getContext(false);
final Configuration config = context.getConfiguration();
final ListAppender list = config.getAppender("list");
final List<LogEvent> events = list.getEvents();
i = 0;
assertThat(events).hasSize(12);
assertLocation(events.get(i), Level.TRACE, MESSAGE + i++, null, ++currentLine);
assertLocation(events.get(i), Level.TRACE, MESSAGE + i++, T, ++currentLine);
assertLocation(events.get(i), Level.DEBUG, MESSAGE + i++, null, ++currentLine);
assertLocation(events.get(i), Level.DEBUG, MESSAGE + i++, T, ++currentLine);
assertLocation(events.get(i), Level.INFO, MESSAGE + i++, null, ++currentLine);
assertLocation(events.get(i), Level.INFO, MESSAGE + i++, T, ++currentLine);
assertLocation(events.get(i), Level.WARN, MESSAGE + i++, null, ++currentLine);
assertLocation(events.get(i), Level.WARN, MESSAGE + i++, T, ++currentLine);
assertLocation(events.get(i), Level.ERROR, MESSAGE + i++, null, ++currentLine);
assertLocation(events.get(i), Level.ERROR, MESSAGE + i++, T, ++currentLine);
assertLocation(events.get(i), Level.FATAL, MESSAGE + i++, null, ++currentLine);
assertLocation(events.get(i), Level.FATAL, MESSAGE + i, T, ++currentLine);
}

private void assertLocation(
final LogEvent event, final Level level, final String message, final Throwable t, final int lineNumber) {
assertThat(event.getLevel()).isEqualTo(level);
assertThat(event.getMessage().getFormattedMessage()).isEqualTo(message);
assertThat(event.getThrown()).isEqualTo(t);
final StackTraceElement location = event.getSource();
assertThat(location.getClassName()).isEqualTo(Log4jLogTest.class.getName());
assertThat(location.getMethodName()).isEqualTo("location");
assertThat(location.getLineNumber()).isEqualTo(lineNumber);
}
}
26 changes: 26 additions & 0 deletions log4j-tomcat-juli/src/test/resources/log4j2-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright © 2024 Piotr P. Karwasz
~
~ Licensed 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 status="OFF">
<Appenders>
<List name="list"/>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="list"/>
</Root>
</Loggers>
</Configuration>
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<modules>
<module>log4j-tomcat</module>
<module>log4j-tomcat-env</module>
<module>log4j-tomcat-juli</module>
</modules>

<scm>
Expand Down
10 changes: 10 additions & 0 deletions src/changelog/.3.x.x/101_add_tomcat_juli.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://logging.apache.org/log4j/changelog"
xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.3.xsd"
type="changed">
<issue id="101" link="https://github.com/copernik-eu/log4j-plugins/issues/101"/>
<description format="asciidoc">
Add Tomcat JULI implementation in artifact `log4j-tomcat-juli`.
</description>
</entry>

0 comments on commit 068c1af

Please sign in to comment.