本文共 3716 字,大约阅读时间需要 12 分钟。
【基于 jdk 1.8】
【基本使用】import java.util.logging.Logger;public class UserController { private static Logger log = Logger.getLogger(Test.class.getName()); public void login(){ //设置最低log级别 //log.setLevel(Level.FINEST); log.info("in userController login"); }}
jdk logger的配置路径
{jdk_home}/jre/lib/logging.properties
从配置可以知道
【默认配置】 1、默认处理器handlers是一个ConsoleHandler,控制台输出 2、默认所有log最低级别是INFO,ConsoleHandler的level和formatter配置 3、最下面可以配置具体包的log最低级别 level (下面有分析为什么这样配置)com.xyz.foo.level = SEVERE
只有log.info()和log.warning()快捷方法,其他级别的log需要调用log.log(), info()与warning底层也是自动调用的log()方法
import java.util.logging.Level;import java.util.logging.Logger;public class UserController { private static Logger log = Logger.getLogger(Test.class.getName()); public void login(){ //等同于log.info("in userController login"); log.log(Level.INFO,"in userController login"); }}
jdk的logger的所有级别
SEVERE (highest value)WARNINGINFOCONFIGFINEFINERFINEST (lowest value)
【核心流程概述】
1、jdk的logging系统是由一个LogManager管理的, 2、LogManager内部类LoggerContext管理各个context下不同name的logger实例对象(LoggerContext的namedLoggers [hashtable] 快速判断同名实例,LoggerContext的root [LogNode]【树形保存logger】,保证类包下的log层次结构,和继承父类log的级别level和处理handler) 3、每一个logger实例会有多个handlers,我们获取的是某一个name的logger实例 4、每一次的log.info()都是创建new一个LogRecord对象,然后迭代调用logger的loggerHandlers去处理LogRecord (handler.publish(record)) 【简单调用模拟】【可以做个自己log包装类或logutil】//log的ConsoleHandler模拟,同样相同的输出import java.util.logging.*;public class Test { public static void main(String[] args) throws Exception{ //以下相当于log.info("test info log"); LogRecord lr = new LogRecord(Level.INFO,"test info log"); //设置调用类的名字 lr.setSourceClassName(Test.class.getName()); //ConsoleHandler的默认格式化,参看配置文件logging.properties String msg = new SimpleFormatter().format(lr); //设置xml格式log //msg = new XMLFormatter().format(lr); System.out.println(msg); }}
【原理分析】
Logger log = Logger.getLogger(Test.class.getName());
getLogger()是使用LogManager.java通过参数获取一个Logger.java实例,相同name会取得统一对象
import java.util.logging.Logger;public class Test { private static Logger log = Logger.getLogger(Test.class.getName()); public static void main(String[] args) throws Exception{ Logger log = Logger.getLogger(Test.class.getName()); Logger log2 = Logger.getLogger("Test"); Logger log3 = Logger.getLogger("Test2"); System.out.println("同 名logger:" + (log == log2) ); System.out.println("不同名logger:"+ (log2 == log3) ); }}
获取Logger.java实例,LogManager.demandLogger(),
Logger demandLogger(String name, String resourceBundleName, Class caller) { //根据name获取实例,同名会返回相同实例 Logger result = getLogger(name); if (result == null) { ...新建处理 } return result;}
上面的新建会new logger,调用LoggerContext的addLocallogger()管理logger
//代码片段,大致调用过程Logger newLogger = new Logger(name, resourceBundleName, caller, this, false);addLogger(newLogger);cx.addLocalLogger(logger);//这里读取配置,加入新loggersynchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded)//放入LoggerContext的namedLoggers(hashtable)管理namedLoggers.put(name, ref);//读取logging.properties配置,这里就可以看出jdk默认配置的原理,比如加到配置下面的自定义包级别Level level = owner.getLevelProperty(name + ".level", null);
getLogger(name)是防止同一name多个实例具体可以看java.util.logging.LogManager#getLogger (里面是调用java.util.logging.LogManager.LoggerContext#findLogger LoggerContext的 namedLoggers [hashtable])
一个logger实例就这样处理完了
log.info()调用过程比较简单java.util.logging.Logger#info(java.lang.String)java.util.logging.Logger#log(java.util.logging.Level, java.lang.String)//对LogRecord设置一些属性java.util.logging.Logger#doLog(java.util.logging.LogRecord)//最终log处理java.util.logging.Logger#log(java.util.logging.LogRecord)
转载地址:http://hrxlf.baihongyu.com/