是否存在可将日志重定向至JUL(java.util.logging)的Logback Appender?
WebSphere环境下Logback对接JUL的可行实现方案
方案核心思路
弃用直接输出System.out/System.err的ConsoleAppender,也不要使用jul-to-slf4j这类双向桥接包(在WebSphere这类由服务器核心托管JUL实例的环境中,桥接包会引发类加载死锁、日志递归打印的问题),直接自定义Logback Appender,将Logback日志事件直接路由到对应类的JUL Logger实例,完整保留日志级别映射,让WebSphere原生日志框架正确识别日志级别、输出标准E/W/I标识,同时可并行配置独立文件Appender给开发人员输出全量日志,两边日志级别独立配置互不干扰。
具体落地步骤
- 第一步:实现自定义Logback JUL Appender
继承Logback官方AppenderBase<ILoggingEvent>抽象类,完成Logback级别到JUL级别的精确映射,直接调用JUL接口提交日志事件:import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.ThrowableProxy; import ch.qos.logback.core.AppenderBase; import java.util.logging.Logger; public class JulAppender extends AppenderBase<ILoggingEvent> { // 级别映射规则和WebSphere原生日志标识完全对齐 private java.util.logging.Level mapLevel(Level logbackLevel) { switch (logbackLevel.levelInt) { case Level.ERROR_INT: return java.util.logging.Level.SEVERE; case Level.WARN_INT: return java.util.logging.Level.WARNING; case Level.INFO_INT: return java.util.logging.Level.INFO; case Level.DEBUG_INT: return java.util.logging.Level.FINE; case Level.TRACE_INT: return java.util.logging.Level.FINER; default: return java.util.logging.Level.INFO; } } @Override protected void append(ILoggingEvent event) { // 按日志发起类获取对应JUL Logger,避免WebSphere日志分类错乱 Logger julLogger = Logger.getLogger(event.getLoggerName()); // 透传格式化后的日志内容、异常栈,不手动拼接破坏日志结构 julLogger.log( mapLevel(event.getLevel()), event.getFormattedMessage(), event.getThrowableProxy() != null ? ((ThrowableProxy)event.getThrowableProxy()).getThrowable() : null ); } } - 第二步:配置logback.xml实现日志分流
同时配置JUL Appender和独立文件Appender,给管理员、开发人员分别设置不同的日志输出阈值:<configuration> <!-- JUL Appender:输出到WebSphere原生日志系统,保留正确级别标识 --> <appender name="WAS_JUL" class="com.your.package.JulAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <!-- 管理员侧仅输出INFO及以上级别日志 --> <level>INFO</level> </filter> </appender> <!-- 独立文件Appender:给开发人员输出全量调试日志 --> <appender name="DEV_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>/var/log/your-app/dev-full.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>/var/log/your-app/dev-full.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <maxFileSize>100MB</maxFileSize> <maxHistory>30</maxHistory> </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"> <!-- 开发侧输出TRACE及以上全量日志 --> <level>TRACE</level> </filter> </appender> <root level="TRACE"> <appender-ref ref="WAS_JUL" /> <appender-ref ref="DEV_FILE" /> </root> </configuration> - 第三步:WebSphere环境配置避坑
- 不要将
jul-to-slf4j、slf4j-jdk14这类桥接包放入应用依赖或WebSphere共享库目录,这类包会造成日志流双向闭环,在托管类加载环境下必然引发故障 - 不需要修改WebSphere全局日志配置,自定义Appender调用的是服务器托管的JUL实例,会自动遵循服务器侧的日志轮转、权限管控规则
- 如果出现日志重复打印问题,在WebSphere对应应用的JVM启动参数中添加
-Djava.util.logging.config.use.parent.handlers=false,关闭JUL父Logger的重复转发即可
- 不要将
常见ConsoleAppender方案失效原因
WebSphere对System.out、System.err流的捕获逻辑是独立的,所有直接写入标准输出流的内容都会被统一标记为
O(SystemOut级别),日志内容里手动拼接的ERROR/WARN字样不会被服务器日志框架识别,只有通过JUL Logger接口提交的日志事件,才会被解析为对应级别,输出标准的E/W/I级别标识。
内容的提问来源于stack exchange,提问作者fishbone
相关产品推荐
相关产品推荐

