Java日志框架之JUL(java util logging)详解

定义:

JUL全称Java util logging,是java原生的日志框架,使用时不需要另外引入第三方类库,相对于其他框架使用方便,学习简单,能够在小型的应用中灵活使用。

架构:
在这里插入图片描述

  • Application:我们的程序应用。
  • LogManager:管理Logger,是个单例Bean。
  • Logger:日志记录器,我们的应用程序通过获取日志记录器Logger对象,调用其API来发布日志信息,Logger通常是应用程序访问日志系统的入口。
  • Handler:日志处理器,每个Logger会关联持有多个Handler,Logger会把日志交给Handler进行处理,由Handler负责日志记录。Handler在这里是一个抽象,其具体实现决定了日志输出的位置,比如控制台,文件等。
  • Formattter:日志格式转化器,负责对日志的格式进行处理。决定了输出的日志的最终形式。
  • Level:每条日志信息都有一个关联的日志级别,该级别处理指导了日志信息的重要性。我们可以将Level作用于Logger和Handler上。以便于我们过滤消息。
  • Filter:过滤器,根据规则过滤掉某些日志信息。

总体流程:

  1. 初始化LogManager,加载logging.properties配置文件,添加Logger到LogManager中。
  2. 从单例Bean LogManager获取Logger。
  3. 设置日志级别Level。
  4. Handler处理日志输出。
  5. Formatter处理日志格式。
日志的级别:

JUL日志级别由类java.util.logging.Level记录,总共有七个日志级别,由高到低分别是:

SEVERE //错误信息,一般是记录导致系统终止的信息。
WARNING //警告信息,一般记录程序的问题,该问题不会导致系统终止,但是却值得我们关注。
INFO // 一般信息,一般记录一些连接信息,访问信息等。(这是JUL的默认级别)
CONFIG // 一般记录加载配置文件等日志信息。
FINE // Debug日志信息,一般记录程序一般运行的状态。执行的流程参数的传递等信息。
FINER //与FINE 类似,只是记录的颗粒度要高一些。
FINEST //与上面两个类似,只是记录的颗粒度要高一些。

还有两个特殊的级别:
OFF: 可用来关闭日志信息,不输出任何级别的日志。
ALL: 记录所有级别的日志信息。

当Logger或者Handler设置了某一日志级别,低于该级别的日志信息将不会被记录。

入门案例:

public class JULDemo {

    @Test
    public void testHelloWorld(){
        //创建日志记录器,传入参数是日志记录器的名称
        Logger logger = Logger.getLogger("juldemo.JULDemo");

        //记录severe级别信息
        logger.severe("severe信息");
        //记录warning级别信息
        logger.warning("warning信息");
        logger.info("info信息");
        logger.config("config信息");
        logger.fine("fine信息");
        logger.finer("finer信息");
        logger.finest("finest信息");
    }
}

输出结果:
在这里插入图片描述
因为默认的日志级别是INFO,所以比INFO级别低的 CONFIG、FINE、FINER、FINEST的日志记录消息没有记录。

自定义日志级别:
@Test
    public void testCustomLogLevel(){
        //创建日志记录器,传入参数是日志记录器的名称
        Logger logger = Logger.getLogger("juldemo.JULDemo");



        //创建一个输出到控制台的handler
        ConsoleHandler consoleHandler = new ConsoleHandler();
        //设置handler的日志级别为ALL,输出全部日志。
        consoleHandler.setLevel(Level.ALL);

        //把handler添加到logger中
        logger.addHandler(consoleHandler);
        //logger也设置日志级别为ALL
        logger.setLevel(Level.ALL);

        //logger设置不使用父logger的handler,不然日志会重复记录。此处后面会讲
        logger.setUseParentHandlers(false);
        //记录severe级别信息
        logger.severe("severe信息");
        //记录warning级别信息
        logger.warning("warning信息");
        logger.info("info信息");
        logger.config("config信息");
        logger.fine("fine信息");
        logger.finer("finer信息");
        logger.finest("finest信息");
    }

结果:
在这里插入图片描述
七个级别的日志信息都输出了。

Logger之间的父子关系:

JUL的Logger之间会存在父子关系,这种父子关系通过树状关系存储。JUL在初始化时会创建一个顶层的RootLogger作为所有Logger的父Logger。RootLogger作为树结构的根节点,Logger之间的关系通过树路径来关联。Logger记录器是用名称作为标志的。子Logger和默认使用父Logger的Handler。

Logger的父子关系默认是通过名子的层级关系来确定的。层级关系用 . 号分开。
也可以通过手动设置父Logger。

@Test
    public void testLoggerParent(){
        //创建一个名称为aaa的logger
        Logger logger1 = Logger.getLogger("aaa");

        //创建一个名称为aaa.bbb的logger
        Logger logger2 = Logger.getLogger("aaa.bbb");

        //创建一个名称为aaa.bbb.ccc的logger
        Logger logger3 = Logger.getLogger("aaa.bbb.ccc");

        //此时logger3的父Logger是logger2, logger2的父logger是logger1

        //判断logger3的父Logger是不是logger2
        System.out.println(logger3.getParent() == logger2);

        //判断logger2的父logger是不是logger1
        System.out.println(logger2.getParent() == logger1);

        //logger1的父节点是顶级Logger RootLogger
        System.out.println("logger1的父logger是 " + logger1.getParent());

        //RootLogger的父Logger
        System.out.println("RootLogger的父Logger是 " + logger1.getParent().getParent());

        //手动设置父Logger
        logger3.setParent(logger1);
        //判断设置是否成功
        System.out.println(logger3.getParent() == logger1);

    }

执行结果:
在这里插入图片描述
子Logger默认会使用父Logger的Handler:

@Test
    public void testUserParentHandler() throws IOException {
        //创建一个名为aaa的logger
        Logger logger1 = Logger.getLogger("aaa");
        //创建一个名为aaa.bbb的logger,父Logger是handler
        Logger logger2 = Logger.getLogger("aaa.bbb");

        //创建一个handler
        ConsoleHandler consoleHandler  = new ConsoleHandler();

        //把handler添加到logger1和logger2中。
        logger1.addHandler(consoleHandler);
        logger2.addHandler(consoleHandler);

        //使用logger进行日志输出

        //记录severe级别信息
        logger2.severe("severe信息");
        //记录warning级别信息
        logger2.warning("warning信息");
        logger2.info("info信息");
        logger2.config("config信息");
        logger2.fine("fine信息");
        logger2.finer("finer信息");
        logger2.finest("finest信息");

    }

结果:
在这里插入图片描述
分析:
每个级别的日志信息输出了三次,因为logger2使用了父Logger logger1 ,父Logger的父Logger RootLogger、还有自身的handler共三个handler,所以日志会输出三倍。

使用logger2.setUseParentHandlers(false); 设置不使用父Logger的Handler。

结果:
在这里插入图片描述
只用了自身的handler。

使用FileHandler和SimpleFormatter
 @Test
    public void testFileHandler(){
        Logger logger = Logger.getLogger("juldemo.JULDemo");
        logger.setLevel(Level.ALL);
        try {
            //创建一个输出到文件的handler,第一个参数是生成文件名的pattern,第二个参数是是否已追加的方式输出到文件,默认false
            FileHandler fileHandler = new FileHandler("D:\\logs\\java%u.log",true);
            //创建一个SimpleFormatter,输出格式
            SimpleFormatter formatter = new SimpleFormatter();
            //设置formatter
            fileHandler.setFormatter(formatter);
            //设置日志级别
            fileHandler.setLevel(Level.ALL);
            //把handler添加到logger
            logger.addHandler(fileHandler);
            //设置不使用父Logger的handler
            logger.setUseParentHandlers(false);
            logger.severe("severe信息");
            //记录warning级别信息
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
        } catch (IOException e) {
           e.printStackTrace();
        }

    }

输出到文件:
在这里插入图片描述

配置文件详解:

上面的使用方式都是使用硬编码方式进行配置,现在介绍配置文件配置。

默认的配置文件:
$JAVA_HOME/jre/lib/logging.properties
默认配置:

#配置RootLogger的Handler,多个用逗号分隔。默认只有一个输出到控制台的handler
handlers= java.util.logging.ConsoleHandler

#配置RootLogger的日志级别,默认是INFO
.level= INFO

#配置FileHandler
#配置FileHandler的生成文件路径以及文件名的生成方式
java.util.logging.FileHandler.pattern = %h/java%u.log
#默认一个文件最多50000条日志记录
java.util.logging.FileHandler.limit = 50000
#默认生成一个文件
java.util.logging.FileHandler.count = 1
#默认使用XMLFormatter格式器
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

#ConsoleHandler的日志级别默认是INFO
java.util.logging.ConsoleHandler.level = INFO
#ConsoleHandler的默认格式化器时SimpleFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

我们可以使用自定义的文件或者修改默认配置文件进行配置。


#配置RootLogger的Handler,有java.util.logging.ConsoleHandler,java.util.logging.FileHandler
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler

#配置RootLogger的日志级别ALL
.level= ALL

java.util.logging.FileHandler.pattern = D:/logs/java%u.log
#默认一个文件最多50000条日志记录
java.util.logging.FileHandler.limit = 50000
#设置FileHandle的日志级别为ALL
java.util.logging.FileHandler.level= ALL

#配置生成一个文件
java.util.logging.FileHandler.count = 1
#配置使用SimpleFormatter格式器
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
#配置追加模式
java.util.logging.FileHandler.append=true

#ConsoleHandler的日志级别默认是INFO
java.util.logging.ConsoleHandler.level = ALL
#ConsoleHandler的默认格式化器时SimpleFormatter
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter



#设置日志格式
java.util.logging.SimpleFormatter.format= %1$tc %2$s%n%4$s: %5$s%6$s%n



使用:

 @Test
    public void testCustomConfig(){
        LogManager logManager = LogManager.getLogManager();
        try {
            logManager.readConfiguration(this.getClass().getClassLoader().getResourceAsStream("logging.properties"));
            Logger logger = Logger.getLogger("juldemo.JULDemo");
            logger.severe("severe信息");
            //记录warning级别信息
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

结果:
在这里插入图片描述
并且生成了日志文件,这里就不贴了。

如果不想用logmanager加载指定配置文件的话,就直接修改$JAVA_HOME/jre/lib/logging.properties文件也行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值