博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现jul 日志重定向到 slf4j
阅读量:6312 次
发布时间:2019-06-22

本文共 9411 字,大约阅读时间需要 31 分钟。

需求背景

    jul 指的是java.util.logging,是 java 内置的日志模块,目前流行的Java日志组件还包括 jcl(common-logging)、slf4j/log4j/logback 等等 

不同日志框架的定位和特性都存在差异,如 jcl、slf4j 提供的是日志门面(api)定义,log4j、logback则侧重于实现。

通常一个团队会采用统一的日志组件,slf4j 目前的受欢迎程度较高,其在易用性、可移植性方面都优于jul; 

然而项目中采用的一些开源组件可能直接采用了jul 进行日志输出,为保证日志的统一配置管理,需将其迁移到slf4j 日志框架上;

关键要求

  1. 不改动现有开源组件代码;

  2. 按需进行迁移,不影响其他模块的 logging 记录;

  3. 模块支持可插拔,可动态集成和撤销;

方案分析

java.util.logging 架构定义如下: 

 

Logger 以名称(如package) 为标识,Logger之间为树级结构,与log4j类似; 
Handler 接口实现了真正的日志处理,如实现过滤、输出到文件、网络IO..

public abstract class Handler{    /**     * Publish a LogRecord.     * 

* The logging request was made initially to a Logger object, * which initialized the LogRecord and forwarded it here. *

* The Handler is responsible for formatting the message, when and * if necessary. The formatting should include localization. * * @param record description of the log event. A null record is * silently ignored and is not published */ public abstract void publish(LogRecord record); }

 

为实现slf4j 的桥接,考虑以下方法: 

1 定义日志级别映射,将jul level 映射为 slf4j level; 
比如

FINEST/FINER/FINE/=TRACECONFIG=DEBUGINFO=INFOWARNING=WARNSEVERE=ERROR

2 自定义jul 的日志handler, 将jul LogRecord 使用slf4j 进行输出; 

3 为避免所有的日志都生成LogRecord对象产生内存浪费,需提前为jul Logger 设置过滤级别;

代码样例

1. LoggerLevel 映射定义

public enum LoggerLevel {    TRACE(Level.ALL),    DEBUG(Level.CONFIG),    INFO(Level.INFO),    WARN(Level.WARNING),    ERROR(Level.SEVERE);    private Level julLevel;    private LoggerLevel(Level julLevel) {        this.julLevel = julLevel;    }    public Level getJulLevel() {        return this.julLevel;    }}

 

2. JulLoggerWrapper 实现 Handler

public class JulLoggerWrapper extends Handler {    // SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST    // ERROR > WARN > INFO > DEBUG    private static final int TRACE_LEVEL_THRESHOLD = Level.FINEST.intValue() - 1;    private static final int DEBUG_LEVEL_THRESHOLD = Level.CONFIG.intValue();    private static final int INFO_LEVEL_THRESHOLD = Level.INFO.intValue();    private static final int WARN_LEVEL_THRESHOLD = Level.WARNING.intValue();    private List
julHandlers; private boolean julUseParentHandlers = false; private Level julLevel; private Level targetLevel; private String name; public JulLoggerWrapper(String name) { this.name = name; } /** * install the wrapper */ public void install() { java.util.logging.Logger julLogger = this.getJulLogger(); // remove old handlers julHandlers = new ArrayList
(); for (Handler handler : julLogger.getHandlers()) { julHandlers.add(handler); julLogger.removeHandler(handler); } // disable parent handler this.julUseParentHandlers = julLogger.getUseParentHandlers(); julLogger.setUseParentHandlers(false); // record previous level this.julLevel = julLogger.getLevel(); if (this.targetLevel != null) { julLogger.setLevel(this.targetLevel); } // install wrapper julLogger.addHandler(this); } /** * uninstall the wrapper */ public void uninstall() { java.util.logging.Logger julLogger = this.getJulLogger(); // uninstall wrapper for (Handler handler : julLogger.getHandlers()) { if (handler == this) { julLogger.removeHandler(handler); } } // recover work.. julLogger.setUseParentHandlers(this.julUseParentHandlers); if (this.julLevel != null) { julLogger.setLevel(julLevel); } if (this.julHandlers != null) { for (Handler handler : this.julHandlers) { julLogger.addHandler(handler); } this.julHandlers = null; } } private java.util.logging.Logger getJulLogger() { return java.util.logging.Logger.getLogger(name); } private Logger getWrappedLogger() { return LoggerFactory.getLogger(name); } /** * 更新级别 * * @param targetLevel */ public void updateLevel(LoggerLevel targetLevel) { if (targetLevel == null) { return; } updateLevel(targetLevel.getJulLevel()); } /** * 更新级别 * * @param targetLevel */ public void updateLevel(Level targetLevel) { if (targetLevel == null) { return; } java.util.logging.Logger julLogger = this.getJulLogger(); if (this.julLevel == null) { this.julLevel = julLogger.getLevel(); } this.targetLevel = targetLevel; julLogger.setLevel(this.targetLevel); } @Override public void publish(LogRecord record) { // Silently ignore null records. if (record == null) { return; } Logger wrappedLogger = getWrappedLogger(); String message = record.getMessage(); if (message == null) { message = ""; } if (wrappedLogger instanceof LocationAwareLogger) { callWithLocationAwareMode((LocationAwareLogger) wrappedLogger, record); } else { callWithPlainMode(wrappedLogger, record); } } /** * get the record's i18n message * * @param record * @return */ private String getMessageI18N(LogRecord record) { String message = record.getMessage(); if (message == null) { return null; } ResourceBundle bundle = record.getResourceBundle(); if (bundle != null) { try { message = bundle.getString(message); } catch (MissingResourceException e) { } } Object[] params = record.getParameters(); // avoid formatting when 0 parameters. if (params != null && params.length > 0) { try { message = MessageFormat.format(message, params); } catch (RuntimeException e) { } } return message; } private void callWithPlainMode(Logger slf4jLogger, LogRecord record) { String i18nMessage = getMessageI18N(record); int julLevelValue = record.getLevel().intValue(); if (julLevelValue <= TRACE_LEVEL_THRESHOLD) { slf4jLogger.trace(i18nMessage, record.getThrown()); } else if (julLevelValue <= DEBUG_LEVEL_THRESHOLD) { slf4jLogger.debug(i18nMessage, record.getThrown()); } else if (julLevelValue <= INFO_LEVEL_THRESHOLD) { slf4jLogger.info(i18nMessage, record.getThrown()); } else if (julLevelValue <= WARN_LEVEL_THRESHOLD) { slf4jLogger.warn(i18nMessage, record.getThrown()); } else { slf4jLogger.error(i18nMessage, record.getThrown()); } } private void callWithLocationAwareMode(LocationAwareLogger lal, LogRecord record) { int julLevelValue = record.getLevel().intValue(); int slf4jLevel; if (julLevelValue <= TRACE_LEVEL_THRESHOLD) { slf4jLevel = LocationAwareLogger.TRACE_INT; } else if (julLevelValue <= DEBUG_LEVEL_THRESHOLD) { slf4jLevel = LocationAwareLogger.DEBUG_INT; } else if (julLevelValue <= INFO_LEVEL_THRESHOLD) { slf4jLevel = LocationAwareLogger.INFO_INT; } else if (julLevelValue <= WARN_LEVEL_THRESHOLD) { slf4jLevel = LocationAwareLogger.WARN_INT; } else { slf4jLevel = LocationAwareLogger.ERROR_INT; } String i18nMessage = getMessageI18N(record); lal.log(null, java.util.logging.Logger.class.getName(), slf4jLevel, i18nMessage, null, record.getThrown()); } @Override public void flush() { // TODO Auto-generated method stub } @Override public void close() throws SecurityException { // TODO Auto-generated method stub }}

 

3. 集成代码

public class JulRouter {    private static String loggerName = JulRouter.class.getPackage().getName();    private static Logger logger = Logger.getLogger(loggerName);    private static void writeLogs() {        logger.warning("this the warining message");        logger.severe("this the severe message");        logger.info("this the info message");        logger.finest("this the finest message");    }    public static void main(String[] args) {        Thread.currentThread().setName("JUL-Thread");        JulLoggerWrapper wrapper = new JulLoggerWrapper(loggerName);        wrapper.updateLevel(LoggerLevel.DEBUG);        System.out.println("slf4j print===========");        wrapper.install();        writeLogs();        System.out.println("jul print===========");        wrapper.uninstall();        writeLogs();    }}

 

4. log4j,properties 配置

采用slf4j + log4j的方案,在classpath中设置log4j.properties即可

log4j.rootLogger=INFO, console# simple console loglog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %p ~ %m%n## for jul logginglog4j.logger.org.zales.dmo.samples.logging=TRACE,julAppenderlog4j.additivity.org.zales.dmo.samples.logging=falselog4j.appender.julAppender=org.apache.log4j.ConsoleAppenderlog4j.appender.julAppender.layout=org.apache.log4j.PatternLayoutlog4j.appender.julAppender.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}]--[%t] [%p] -%l - %m%n

 

参考资料

Java Util Logging 组件介绍 

 
Jul API Turturial 
 
Log4j -Jul 适配器组件 

转载于:https://www.cnblogs.com/littleatp/p/6354441.html

你可能感兴趣的文章
bash数组
查看>>
Richard M. Stallman 给《自由开源软件本地化》写的前言
查看>>
oracle数据库密码过期报错
查看>>
修改mysql数据库的默认编码方式 .
查看>>
zip
查看>>
How to recover from root.sh on 11.2 Grid Infrastructure Failed
查看>>
rhel6下安装配置Squid过程
查看>>
《树莓派开发实战(第2版)》——1.1 选择树莓派型号
查看>>
在 Linux 下使用 fdisk 扩展分区容量
查看>>
结合AlphaGo算法和大数据的量化基本面分析法探讨
查看>>
如何在 Ubuntu Linux 16.04 LTS 中使用多个连接加速 apt-get/apt
查看>>
《OpenACC并行编程实战》—— 导读
查看>>
机器学习:用初等数学解读逻辑回归
查看>>
如何在 Ubuntu 中管理和使用逻辑卷管理 LVM
查看>>
Oracle原厂老兵:从负面案例看Hint的最佳使用方式
查看>>
把自己Github上的代码添加Cocoapods支持
查看>>
C语言OJ项目参考(2493)四则运算
查看>>
零基础入门深度学习(二):神经网络和反向传播算法
查看>>
find和xargs
查看>>
数据结构例程—— 交换排序之快速排序
查看>>