JUL 日志模块

Java的生态中,日志系统有log4jlog4j2slf4jlogback等库,实际上JDK也自带java.util.logging.Logger(简称JUL),JDK自带的日志系统虽然和前面的比起来比较简陋,但它使用非常简单,如果是个人开发的小项目、小工具,可以考虑使用。

JUL日志级别

为了便于用户有效的利用日志,JUL日志信息是分级的,比如系统报错和系统正常运行时的日志肯定不是一个级别的,系统管理员在分析系统报错时,只要查找较高级别的日志即可。

JUL日志系统中,日志分为如下级别(从高到低):

  • SEVERE(严重)
  • WARNING(警告)
  • INFO(信息)
  • CONFIG
  • FINE
  • FINER
  • FINEST

实际上,我们一般只使用前三种,系统发生致命错误时,输出SEVERE级别,系统存在异常但仍能正常运行时,输出WARNING级别,系统正常运行,输出INFO级别。

使用代码输出日志

下面代码中,测试了输出各种级别的日志。

package com.gacfox.demo;

import java.util.logging.Logger;

public class Main {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class.getCanonicalName());
        logger.severe("这是severe级别的日志");
        logger.warning("这是warning级别的日志");
        logger.info("这是info级别的日志");
        logger.config("这是config级别的日志");
        logger.fine("这是fine级别的日志");
        logger.finer("这是finer级别的日志");
        logger.finest("这是finest级别的日志");
    }
}

getLogger方法接收一个参数,作为日志记录器logger的名字,该参数建议指定为当前包名或类名。

输出:

九月 09, 2022 10:14:55 上午 com.gacfox.demo.Main main
严重: 这是severe级别的日志
九月 09, 2022 10:14:55 上午 com.gacfox.demo.Main main
警告: 这是warning级别的日志
九月 09, 2022 10:14:55 上午 com.gacfox.demo.Main main
信息: 这是info级别的日志

我们可以发现,默认控制台中只输出了SEVEREWARNINGINFO这三个级别的日志。这是因为,Logger输出的默认级别是INFO,比INFO低级的日志不会输出。

Handler日志处理器

Handler负责对生成的日志信息进行处理,默认的处理方式是打印到控制台,除此之外还可以将日志写入文件或是发送到网络。下面代码中,为一个Logger添加了一个FileHandler,将生成的日志信息写入文件,生成的日志是XML格式的。

package com.gacfox.demo;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;

public class Main {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class.getCanonicalName());
        FileHandler handler;
        try {
            handler = new FileHandler("E:/1.log");
            logger.addHandler(handler);
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.severe("这是severe级别的日志");
        logger.warning("这是warning级别的日志");
        logger.info("这是info级别的日志");
        logger.config("这是config级别的日志");
        logger.fine("这是fine级别的日志");
        logger.finer("这是finer级别的日志");
        logger.finest("这是finest级别的日志");
    }
}

1.log

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
  <date>2022-09-09T10:19:34</date>
  <millis>1662689974894</millis>
  <sequence>0</sequence>
  <logger>com.gacfox.demo.Main</logger>
  <level>SEVERE</level>
  <class>com.gacfox.demo.Main</class>
  <method>main</method>
  <thread>1</thread>
  <message>这是severe级别的日志</message>
</record>
<record>
  <date>2022-09-09T10:19:34</date>
  <millis>1662689974923</millis>
  <sequence>1</sequence>
  <logger>com.gacfox.demo.Main</logger>
  <level>WARNING</level>
  <class>com.gacfox.demo.Main</class>
  <method>main</method>
  <thread>1</thread>
  <message>这是warning级别的日志</message>
</record>
<record>
  <date>2022-09-09T10:19:34</date>
  <millis>1662689974923</millis>
  <sequence>2</sequence>
  <logger>com.gacfox.demo.Main</logger>
  <level>INFO</level>
  <class>com.gacfox.demo.Main</class>
  <method>main</method>
  <thread>1</thread>
  <message>这是info级别的日志</message>
</record>
</log>

Formatter日志格式化器

Formatter负责对输出的日志数据格式化,例如上面将日志写入文件中,默认使用的是XML格式,这是因为默认配置了java.util.logging.XMLFormatter,如果我们不想用XML格式,我们可以选用其他的Formatter。下面例子中,改用简单模式输出日志数据到文件中。

package com.gacfox.demo;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class Main {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(Main.class.getCanonicalName());
        FileHandler handler;
        try {
            handler = new FileHandler("E:/1.log");
            SimpleFormatter formatter = new SimpleFormatter();
            handler.setFormatter(formatter);
            logger.addHandler(handler);
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.severe("这是severe级别的日志");
        logger.warning("这是warning级别的日志");
        logger.info("这是info级别的日志");
        logger.config("这是config级别的日志");
        logger.fine("这是fine级别的日志");
        logger.finer("这是finer级别的日志");
        logger.finest("这是finest级别的日志");
    }
}

和上面代码的区别就是为FileHandler添加了一个SimpleFormatter,覆盖了默认的XMLFormatter

1.log

九月 09, 2022 10:21:15 上午 com.gacfox.demo.Main main
严重: 这是severe级别的日志
九月 09, 2022 10:21:15 上午 com.gacfox.demo.Main main
警告: 这是warning级别的日志
九月 09, 2022 10:21:15 上午 com.gacfox.demo.Main main
信息: 这是info级别的日志

logging.properties配置文件

通过上文,我们发现这个JDK自带的Logger有很多默认配置,实际上这些配置都写在$JAVA_HOME/jre/lib/logging.properties里。

############################################################
#   Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.  
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#   Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
#     <level>: <log message> [<date/time>]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE

里面的具体内容就不详细解释了,自带的注释已经很详尽了,我们也可以根据注释的指引,让我们的应用程序使用我们自定义的日志配置文件。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。