As there seems to be no solution, we made our own. IIRC it's based on this Log4j solution.
The great thing about it is that we can even enable tracing in the WebSphere console. That means you can use Logback methods isDebugEnabled()
or isTraceEnabled()
to check whether JUL trace level is enabled in WebSphere.
The appender:
package com.example.logging;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import java.util.logging.Level;
import java.util.logging.Logger;
public class JulAppender extends AppenderBase<ILoggingEvent> {
@Override
protected void append(ILoggingEvent event) {
Logger logger = Logger.getLogger(event.getLoggerName());
if (logger == null) {
System.out.println("Cannot obtain JUL " + event.getLoggerName() + ".");
return;
}
ch.qos.logback.classic.Level logbackLevel = event.getLevel();
Level level = JulLogbackEventConverter.convertLogbackToJulLevel(logbackLevel);
logger.log(level, event.getFormattedMessage());
}
}
Convert Logback to JUL log level:
package com.example.logging;
import java.util.logging.Level;
public class JulLogbackEventConverter {
public static Level convertLogbackToJulLevel(ch.qos.logback.classic.Level level) {
if (level.equals(ch.qos.logback.classic.Level.OFF)) {
return Level.OFF;
} else if (level.equals(ch.qos.logback.classic.Level.ERROR)) {
return Level.SEVERE;
} else if (level.equals(ch.qos.logback.classic.Level.WARN)) {
return Level.WARNING;
} else if (level.equals(ch.qos.logback.classic.Level.INFO)) {
return Level.INFO;
} else if (level.equals(ch.qos.logback.classic.Level.DEBUG)) {
return Level.FINER;
} else if (level.equals(ch.qos.logback.classic.Level.TRACE)) {
return Level.FINEST;
} else if (level.equals(ch.qos.logback.classic.Level.ALL)) {
return Level.ALL;
}
return Level.FINER;
}
}
Logback turbo filter for isDebugEnabled()
etc. support
package com.example.logging;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
import org.slf4j.Marker;
public class JulLogbackFilter extends TurboFilter {
@Override
public FilterReply decide(Marker marker, Logger logger, Level level, String s, Object[] objects,
Throwable throwable
) {
java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(logger.getName());
java.util.logging.Level julLevel = JulLogbackEventConverter.convertLogbackToJulLevel(level);
if (julLogger.isLoggable(julLevel)) {
return FilterReply.NEUTRAL;
}
return FilterReply.DENY;
}
}
Example configuration. Our goal with this configuration was to write INFO messages in a separate log file instead of "spamming" WebSphere's SystemOut.log. Warnings and errors should appear in SystemOut.log. If trace is enabled the messages should be written to WebSphere's trace.log:
<configuration>
<turboFilter class="com.example.logging.JulLogbackFilter" />
<appender name="julAppender" class="com.example.logging.JulAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/myapp/myapp-web.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/myapp/myapp-web-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>8GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
</appender>
<root level="TRACE">
<appender-ref ref="julAppender" />
<appender-ref ref="file" />
</root>
</configuration>