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

本文共 9447 字,大约阅读时间需要 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 适配器组件 

img_9b09a36f6de95886f52ce82fa1e89c88.jpe

作者:

出处: , 如果喜欢我的文章,请关注我的公众号

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出  如有问题, 可留言咨询.

你可能感兴趣的文章
Peeking into Apache Flink's Engine Room
查看>>
Java三大主流开源工作流引擎技术分析
查看>>
Android 底部Dialog显示
查看>>
iOS在xib或storyboard里为控件添加圆角、外框和外框颜色
查看>>
NET下RabbitMQ实践[配置篇]
查看>>
[ilink32 Error] Error: Unresolved external 'SendARP'
查看>>
SecureCRT上传、下载文件 使用rz【上传】& sz【下载】命令
查看>>
golang map to struct
查看>>
jdk1.8.0_101/bin下各文件解释
查看>>
Duilib将UI资源文件打包到exe教程
查看>>
Redis集群(二):Redis的安装
查看>>
Android之消息机制Handler,Looper,Message解析
查看>>
利用Shodan和Censys进行信息侦查
查看>>
关于《ASP.NET MVC企业级实战》
查看>>
shell脚本:Kill掉MySQL中所有sleep的client线程
查看>>
Sublime text 神器小记
查看>>
我对知乎前端相关问题的十问十答(转)
查看>>
FormatMessage函数的使用方法
查看>>
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
查看>>
优化后的组合算法
查看>>