在正式的生产环境下是不能使用 System.out 进行日志记录的
因为 System.out 不能提供时间、线程、执行过程 等信息,如果要手动打印输出则会非常麻烦
而日志就帮我们把这些事给干了
接下来我们学一个最简单的日志框架 JUL
JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库
相对其他 日志框架,JUL 功能没那么强大,但是最方便使用,因此比较适合在小型应用中使用
JUL 架构
Logger持有若干个Handler,日志的输出操作是由Handler完成的
在Handler在输出日志前,会经过Filter的过滤,判断哪些日志级别过滤放行哪些拦截,Handler会将日
志内容输出到指定位置(日志文件、控制台等)
JUC 使用方法
// 创建日志记录器对象Logger logger = Logger.getLogger("JULTest");// 通用方法进行日志记录logger.log(Level.INFO, "info msg");
在log中传入日志级别和日志信息,结果如下:
还可以直接调用 info 级别的方法 logger.info("info msg");
还可以使用占位符做拼接
// 1.创建日志记录器对象Logger logger = Logger.getLogger("JULTest");String name = "张三";Integer age = 18;logger.log(Level.INFO, "用户信息:{0},{1}", new Object[]{name, age});
JUL的日志级别
JUL可以任务有9个日志级别
查看 Level 源码:
public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);public static final Level WARNING = new Level("WARNING", 900, defaultBundle);public static final Level INFO = new Level("INFO", 800, defaultBundle);public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);public static final Level FINE = new Level("FINE", 500, defaultBundle);public static final Level FINER = new Level("FINER", 400, defaultBundle);public static final Level FINEST = new Level("FINEST", 300, defaultBundle);public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
每个级别的 Level 都会在构造时传入一个数,并且可以看到从OFF 到ALL 这个数越来越小
- INFO - JUL默认的日志级别是 INFO ,INFO 对应的数值为800 ,那么数值大于等于800
的日志级别是允许被执行的,而小于800 的是不允许执行的,INFO 用于记录常规的信息,比如数据库的连接信息、 IO的传递信息 、 网络的通信信息等 - OFF - 因此当日志界别设置为OFF 时,对应的值是Integer.MAX_VALUE ,此时不会有数值更大的日志级别,也就不会有日志执行,相当于关闭了日志
- ALL - 当日志界别为ALL时,对应的级别为 Integer.MIN_VALUE ,此时所有的日志都会执行
- SEVERE - 错误信息 , 输出会导致程序终止的错误信息
- WARNING - 警告信息 , 输出异常信息,不会使程序终止,但也需要注意
- CONFIG - 配置信息,输出配置文件的加载和读取消息等
- FINE 和 FINER 和 FINEST - DeBug 日志,记录程序的运行状态、执行流程、参数传递过程等,从FINE 到 FINEST ,记录的越来越详细
JUC 配置文件
默认配置文件
如果用户不做配置,那么JUC默认会读取 jre 文件 lib 目录下的 logging.properties 配置文件
在该配置文件中,我们可以看到 默认使用的执行器是 ConsoleHandler ,向控制台输出日志信息
而且制定了 level 为 INFO
下面是完整的配置文件信息(删除了所有的注释),可以看到除了 ConsoleHandler ,还配置了另外一个执行器 FileHandler 的信息,只不过 handlers= java.util.logging.ConsoleHandler 中只设置了ConsoleHandler 而没有设置 FileHandler,
handlers= java.util.logging.ConsoleHandler.level= INFOjava.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatterjava.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormattercom.xyz.foo.level = SEVERE
自定义配置文件
默认控制台输出,现在我们自定义配置文件,将日志信息输出到指定的日志文件中,并把日志级别改为ALL
修改后的 logging.properties 配置文件 如下:
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler.level= ALL## 文件处理器
# 输出日志级别
java.util.logging.FileHandler.level=ALL
# 输出日志文件路径
java.util.logging.FileHandler.pattern = D:/JULlogs/java%u.log
# 输出日志文件限制大小(50000字节)
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 = ALL
# 输出日志格式
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
- 改变了handlers,添加了 java.util.logging.FileHandler ,将配置文件读取到日志文件中
- 改变了.level ,将日志等级改为 ALL
- 改变了 java.util.logging.FileHandler.pattern , 指定了日志文件的文件名和生成位置
其中 java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
指定了生成的日志文件为XML格式
我们将配置文件放到 SpringBoot下的 resources 文件下
编写一个测试类,代码如下:
public class JULTest {@Testpublic void test01() throws IOException {// 读取自定义配置文件InputStream in = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");// 获取日志管理器对象LogManager logManager = LogManager.getLogManager();// 通过日志管理器加载配置文件logManager.readConfiguration(in);Logger logger = Logger.getLogger("JULTest");logger.severe("severe");logger.warning("warning");logger.info("info");logger.config("config");logger.fine("fine");logger.finer("finer");logger.finest("finest");}}
控制台打印结果:
去到指定的 D:/JULlogs 文件下,发现一个 java0.log 文件,内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record><date>2023-08-12T14:31:36</date><millis>1691821896349</millis><sequence>0</sequence><logger>JULTest</logger><level>SEVERE</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>severe</message>
</record>
<record><date>2023-08-12T14:31:36</date><millis>1691821896373</millis><sequence>1</sequence><logger>JULTest</logger><level>WARNING</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>warning</message>
</record>
<record><date>2023-08-12T14:31:36</date><millis>1691821896374</millis><sequence>2</sequence><logger>JULTest</logger><level>INFO</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>info</message>
</record>
<record><date>2023-08-12T14:31:36</date><millis>1691821896375</millis><sequence>3</sequence><logger>JULTest</logger><level>CONFIG</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>config</message>
</record>
<record><date>2023-08-12T14:31:36</date><millis>1691821896376</millis><sequence>4</sequence><logger>JULTest</logger><level>FINE</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>fine</message>
</record>
<record><date>2023-08-12T14:31:36</date><millis>1691821896376</millis><sequence>5</sequence><logger>JULTest</logger><level>FINER</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>finer</message>
</record>
<record><date>2023-08-12T14:31:36</date><millis>1691821896377</millis><sequence>6</sequence><logger>JULTest</logger><level>FINEST</level><class>com.zhuyuanjie.springbootproject.test.JULTest</class><method>test01</method><thread>1</thread><message>finest</message>
</record>
</log>
当前日志文件采用覆盖方式,如果想使用追加方式,在配置文件中添加
java.util.logging.FileHandler.append=true