Skip to content

[feat] (re-invent) log4j as a logging backend #310

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
Aug 10, 2025
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
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,12 @@ logging system, configure `jruby.rack.logging` as follows:
- `servlet_context` (default): Sends log messages to the servlet context.
- `stdout`: Sends log messages to the standard output stream `System.out`.
- `slf4j`: Sends log messages to SLF4J. SLF4J configuration is left up to you,
please refer to http://www.slf4j.org/docs.html .
- `log4j`: Sends log messages to log4J. Again, Log4J configuration is
left up to you, consult http://logging.apache.org/log4j/ .
please refer to https://www.slf4j.org/manual.html .
- `log4j`: Sends log messages through Log4j. Only Log4j 2.x is supported, for
- configuration please consult https://logging.apache.org/log4j/2.x/index.html .
- `commons_logging`: Routes logs to commons-logging. You still need to configure
an underlying logging implementation with JCL. We recommend using the logger
library wrapper directly if possible, see http://commons.apache.org/logging/ .
an underlying logging implementation with JCL.
We recommend rather using the logger library wrapper directly when possible.
- `jul`: Directs log messages via Java's core logging facilities (util.logging).

For those loggers that require a specific named logger, set it with the
Expand Down
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<jruby.maven.plugins.version>3.0.6</jruby.maven.plugins.version>
<gem.home>${project.build.directory}/rubygems</gem.home>
<slf4j.version>2.0.17</slf4j.version>
<log4j.version>2.22.1</log4j.version>
<spring.version>5.3.39</spring.version>
</properties>

Expand Down Expand Up @@ -128,6 +129,18 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/jruby/rack/DefaultRackConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ private static Map<String,String> getLoggerTypes() {
final Map<String,String> loggerTypes = new HashMap<>(8);
loggerTypes.put("commons_logging", "org.jruby.rack.logging.CommonsLoggingLogger");
loggerTypes.put("clogging", "org.jruby.rack.logging.CommonsLoggingLogger");
loggerTypes.put("log4j", "org.jruby.rack.logging.Log4jLogger");
loggerTypes.put("slf4j", "org.jruby.rack.logging.Slf4jLogger");
loggerTypes.put("jul", "org.jruby.rack.logging.JulLogger");
return loggerTypes;
Expand Down
83 changes: 83 additions & 0 deletions src/main/java/org/jruby/rack/logging/Log4jLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2025 Karol Bucek LTD.
* This source code is available under the MIT license.
* See the file LICENSE.txt for details.
*/
package org.jruby.rack.logging;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jruby.rack.RackLogger;

public class Log4jLogger extends RackLogger.Base {

private Logger logger;

public Log4jLogger() {
this(LogManager.ROOT_LOGGER_NAME);
}

public Log4jLogger(String loggerName) {
setLoggerName(loggerName);
}

public Logger getLogger() {
return logger;
}

public void setLogger(Logger logger) {
this.logger = logger;
}

public void setLoggerName(String loggerName) {
logger = LogManager.getLogger(loggerName);
}

@Override
public boolean isEnabled(Level level) {
if ( level == null ) return logger.isInfoEnabled();
switch ( level ) {
case DEBUG: return logger.isDebugEnabled();
case INFO: return logger.isInfoEnabled();
case WARN: return logger.isWarnEnabled();
case ERROR: return logger.isErrorEnabled();
case FATAL: return logger.isFatalEnabled();
}
return logger.isTraceEnabled();
}

@Override
public void log(Level level, CharSequence message) {
if ( level == null ) { logger.info(message); return; }
switch ( level ) {
case DEBUG: logger.debug(message); break;
case INFO: logger.info(message); break;
case WARN: logger.warn(message); break;
case ERROR: logger.error(message); break;
case FATAL: logger.fatal(message); break;
}
}

@Override
public void log(Level level, CharSequence message, Throwable ex) {
if ( level == null ) { logger.error(message, ex); return; }
switch ( level ) {
case DEBUG: logger.debug(message, ex); break;
case INFO: logger.info(message, ex); break;
case WARN: logger.warn(message, ex); break;
case ERROR: logger.error(message, ex); break;
case FATAL: logger.fatal(message, ex); break;
}
}

@Override
public Level getLevel() {
if ( logger.isDebugEnabled() ) return Level.DEBUG;
if ( logger.isInfoEnabled() ) return Level.INFO ;
if ( logger.isWarnEnabled() ) return Level.WARN ;
if ( logger.isErrorEnabled() ) return Level.ERROR;
if ( logger.isFatalEnabled() ) return Level.FATAL;
return null;
}

}
15 changes: 13 additions & 2 deletions src/spec/ruby/rack/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
logger.should be_a(org.jruby.rack.logging.Slf4jLogger)
end

it "constructs a log4j logger from the context init param" do
@servlet_context.should_receive(:getInitParameter).with("jruby.rack.logging").and_return "log4j"
logger.should be_a(org.jruby.rack.logging.Log4jLogger)
end

it "constructs a commons logging logger from system properties" do
java.lang.System.setProperty("jruby.rack.logging", "commons_logging")
logger.should be_a(org.jruby.rack.logging.CommonsLoggingLogger)
Expand All @@ -50,13 +55,19 @@
@servlet_context.should_receive(:getInitParameter).with("jruby.rack.logging.name").and_return "/myapp"
@servlet_context.should_receive(:getInitParameter).with("jruby.rack.logging").and_return "JUL"
logger.should be_a(org.jruby.rack.logging.JulLogger)
logger.logger.name.should == '/myapp'
logger.getLogger.name.should == '/myapp'
end

it "constructs a slf4j logger with default logger name" do
java.lang.System.setProperty("jruby.rack.logging", "slf4j")
logger.should be_a(org.jruby.rack.logging.Slf4jLogger)
logger.logger.name.should == 'jruby.rack'
logger.getLogger.name.should == 'jruby.rack'
end

it "constructs a log4j logger with default logger name" do
java.lang.System.setProperty("jruby.rack.logging", "log4j")
logger.should be_a(org.jruby.rack.logging.Log4jLogger)
logger.getLogger.name.should == 'jruby.rack'
end

it "constructs a logger from the context init params over system properties" do
Expand Down