JDK自带的java.util.logging.Logger

环境

  • 操作系统:Ubuntu 20.04
  • JDK:17.0.1

Java自带log功能,用的是JDK标准库中的类java.util.logging.Logger 。下面是一个简单的例子:

package pkg1;

import java.util.logging.*;

public class Test0509 {

    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Test0509.class.getName());

        logger.finest("finest");
        logger.finer("finer");
        logger.fine("fine");
        logger.config("config");
        logger.info("info");
        logger.warning("warning");
        logger.severe("severe");
    }
}

运行程序,结果如下:

May 09, 2022 2:57:02 PM pkg1.Test0509 main
INFO: info
May 09, 2022 2:57:02 PM pkg1.Test0509 main
WARNING: warning
May 09, 2022 2:57:02 PM pkg1.Test0509 main
SEVERE: server

可见,默认的log级别是 INFO ,也就是说 INFO 以及更高级别的log会生效。

注:Logger的 info() 等方法都有一个重载方法,参数的类型是 Supplier<String> ,例如:

        logger.info("info1" + "info2");
        logger.info(() -> "info1" + "info2");

两者功能非常类似,区别在于,前者一定会运行 "info1" + "info2" ,而后者只有在log级别为 INFO 或者更低的时候,才会运行 "info1" + "info2" ,避免了不必要的运算,显然后者性能更好。

Logger与Handler

现在我们来尝试调整log级别:

        ......
        logger.setLevel(Level.WARNING);

        logger.finest("finest");
        logger.finer("finer");
        logger.fine("fine");
        logger.config("config");
        logger.info("info");
        logger.warning("warning");
        logger.severe("severe");
        ......

运行程序,结果如下:

May 09, 2022 3:01:00 PM pkg1.Test0509 main
WARNING: warning
May 09, 2022 3:01:00 PM pkg1.Test0509 main
SEVERE: server

可见,把Logger的级别调整到 WARNING 之后,只有 WARNINGSEVERE 级别的log生效。

接下来把Logger的级别换成 FINER 试试看:

        ......
        logger.setLevel(Level.FINER);

        // comment 1

        logger.finest("finest");
        logger.finer("finer");
        logger.fine("fine");
        logger.config("config");
        logger.info("info");
        logger.warning("warning");
        logger.severe("severe");
        ......

运行程序,结果如下:

May 09, 2022 6:56:55 PM pkg1.Test0509_3 main
INFO: info
May 09, 2022 6:56:55 PM pkg1.Test0509_3 main
WARNING: warning
May 09, 2022 6:56:55 PM pkg1.Test0509_3 main
SEVERE: severe

问题来了,为什么还是只有 INFO以及更高的log级别生效呢?

原因在于,Logger可以有多个Handler,比如下面要提到的 ConsoleHandlerFileHandler 。顾名思义,分别把log输出到控制台和文件。默认情况下(参见下面的默认配置文件),是使用 ConsoleHandler ,这就是为什么log默认会输出到命令行。

如果给Logger配置了多个Handler,则多个Handler同时生效,也就是说log可以既输出到控制台,同时也输出到文件。通过文件或者代码,都可以配置Handler。

事实上,Handler也可以设置级别(默认级别也是 INFO ),与Logger的级别相比,最终二者中较高的级别生效。这就解释了为什么把Logger级别设置为 WARNING 生效,而设置为 FINER 却不生效了,因为Handler的级别仍然是 INFO ,二者中 INFO 级别较高,因此 INFO 及以上级别生效。

要使 FINER 级别生效,需要把Handler的级别也设置成 FINER ,在上面的 comment 1 处添加代码:

        for (Handler handler : Logger.getLogger("").getHandlers()) {
            handler.setLevel(Level.FINER);
        }

再次运行程序,结果如下:

May 09, 2022 7:09:44 PM pkg1.Test0509_3 main
FINER: finer
May 09, 2022 7:09:44 PM pkg1.Test0509_3 main
FINE: fine
May 09, 2022 7:09:44 PM pkg1.Test0509_3 main
CONFIG: config
May 09, 2022 7:09:44 PM pkg1.Test0509_3 main
INFO: info
May 09, 2022 7:09:44 PM pkg1.Test0509_3 main
WARNING: warning
May 09, 2022 7:09:44 PM pkg1.Test0509_3 main
SEVERE: severe

可见,这回 Finer 及以上级别生效了。

配置Log

文件配置

默认配置文件是 $JAVA_HOME/conf/logging.properties ,里面可以配置各种日志选项,比如:

  • handlers= java.util.logging.ConsoleHandler :设置Handler,若有多个Handler(比如 FileHandler ),handler之间用 , 隔开;
  • .level= INFO :默认的全局log级别;
  • java.util.logging.FileHandler.pattern = %h/java%u.log :文件日志的命名,其中 %h 表示home目录, %u 表示0、1、2这样的数字;
  • java.util.logging.FileHandler.limit = 50000 :文件日志的大小?
  • java.util.logging.FileHandler.count = 1 :文件日志的数量?
  • java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter :文件日志的格式
  • java.util.logging.ConsoleHandler.level = INFO :控制台日志的级别
  • java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter :控制台日志的格式
  • ……

例如:把 java.util.logging.ConsoleHandler.level = INFO 改为 java.util.logging.ConsoleHandler.level = SEVERE 。再次运行程序,结果如下:

May 09, 2022 3:31:25 PM pkg1.Test0509 main
SEVERE: severe

注意:配置文件里Handler的级别为 SEVERE ,而代码里Logger级别设置为 WARNING ,二者相比,级别较高者生效。

如果要使用自定义配置文件,需要在运行程序时,指定 java.util.logging.config.file 选项。比如 java -Djava.util.logging.config.file=myfile

最后别忘了还原默认配置文件。

代码配置

前面我们已经试过在代码中设置log级别,下面我们再看看其它配置。比如添加一个 FileHandler

        ......
        try {
            Handler handler = new FileHandler();
            // handler.setLevel(Level.INFO);
            logger.addHandler(handler);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        
        logger.setLevel(Level.WARNING);

        logger.finest("finest");
        logger.finer("finer");
        logger.fine("fine");
        logger.config("config");
        logger.info("info");
        logger.warning("warning");
        logger.severe("severe");
        ......

运行程序,除了命令行输出结果以外,在home目录下生成 java0.log 文件(这是默认的log文件路径和命名),内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
  <date>2022-05-09T07:51:05.215198475Z</date>
  <millis>1652082665215</millis>
  <nanos>198475</nanos>
  <sequence>0</sequence>
  <logger>pkg1.Test0509</logger>
  <level>WARNING</level>
  <class>pkg1.Test0509</class>
  <method>main</method>
  <thread>1</thread>
  <message>warning</message>
</record>
<record>
  <date>2022-05-09T07:51:05.265971919Z</date>
  <millis>1652082665265</millis>
  <nanos>971919</nanos>
  <sequence>1</sequence>
  <logger>pkg1.Test0509</logger>
  <level>SEVERE</level>
  <class>pkg1.Test0509</class>
  <method>main</method>
  <thread>1</thread>
  <message>severe</message>
</record>
</log>

可见,对于log文件和命令行log,都是 WARNINGSEVERE 级别的log生效,只不过两种log的格式不同。

如果要指定文件路径和文件名,只需在创建 FileHandler 时指定,比如:

Handler handler = new FileHandler("aaa.log");

现在运行程序,就会在当前目录下生成 aaa.log 文件。注意,在本例中,当前目录指的是项目的根目录。

注意代码中被注释那一行。如果Handler没有设置级别,默认级别是 INFO ,与Logger级别 WARNING 相比,取较高的 WARNING 。如果设置了级别,则二者中级别较高者生效:

  • handler.setLevel(Level.SEVERE); :Handler中 SEVERE 级别生效;
  • handler.setLevel(Level.INFO); :Logger中 WARNING 级别生效;

参考

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值