java核心基础--jdk源码分析学习--对jdk logging logger的使用介绍,源码分析,深入研究

【基于 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)
WARNING
INFO
CONFIG
FINE
FINER
FINEST  (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);
//这里读取配置,加入新logger
synchronized 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)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值