一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
Java官方自带的实现,使用方面,无需额外引入依赖,但是功能相对不怎么强大。
优缺点
优点:
- 集成于jre,无需引入外部依赖,使用方便,官方支持。
缺点:
- Java标准库内置的Logging系统在JVM启动时读取配置文件并完成初始化,一旦开始运行
main()方法,就无法修改配置; - 配置不太方便,需要在JVM启动时传递参数
-Djava.util.logging.config.file=<config-file-name>。
JUL执行流程
JUL的7个日志级别
由高到低:SEVERE(错误、异常)、WARNING(警告)、INFO(信息)、CONFIG(配置)、FINE(详细的调试信息)、FINER(更加详细的调试信息)、FINEST(最详细的调试信息)
两个特殊的级别
OFF:关闭/禁用日志,Integer.MAX_VALUE
ALL:打开所有日志输出,Integer.MIN_VALUE
使用练习
Demo:
package com.yzj;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.*;
/**
* @author shiPengYu
*/
public class JulUseTest {
/**
* description 测试日志记录器的使用
* @param
* @return void
* @author shiPengYu
* @date 2022/2/15
*/
@Test
public void testUseLogger(){
/*
* 创建一个日志记录器对象,Logger类的构造器不是public,不能直接new出来。
* getLogger():记录器的名称。这应该是一个点分隔的名称,并且通常应该基于子系统的包名或类名,例如 java.net 或 javax.swing
*/
Logger logger = Logger.getLogger("com.yzj.JulUse");
//直接带有输出级别的输出API
logger.info("info:Logger对象的获取与简单使用!");
//使用通用API,日志输出比拼接字符串更加高效的方式:占位符
logger.log(Level.INFO,"变量x:{0},加上变量y:{1},和等于{2}",new Object[]{1,2,3});
}
/**
* description 测试使用JUL的7个日志级别
* @param
* @return void
* @author shiPengYu
* @date 2022/2/9
*/
@Test
public void testLoggerLevel(){
Logger logger = Logger.getLogger("com.yzj.JulUse");
/*
* Logger info的七个输出级别
* 7个级别,级别高低判断的标准:在某一级别下,其余还能输出的日志界别,就认为它们高于当前设置的级别
* 级别的顺序记不住可直接通过级别的常量值来判断,值越大,级别越高,输出时输出大于等于当前级别常量值的日志信息。
* 默认的级别是info,所以只会输出info以及比info级别高的日志信息。并且通过API的set方法设置并不能起作用
* */
logger.log(Level.SEVERE,"server级别是最高的,但是常量值是最低的,约定用于输出错误/异常信息。Level.SEVERE:{0}",new Object[]{Level.SEVERE.intValue()});
logger.log(Level.WARNING,"waring的级别次之于server,约定用于输出系统的警告信息。Level.WARNING:{0}",new Object[]{Level.WARNING.intValue()});
logger.log(Level.INFO,"info的级别次之于waring,是默认的日志级别。约定用于输出系统的一些业务或者提示信息等。Level.INFO:{0}",new Object[]{Level.INFO.intValue()});
logger.log(Level.CONFIG,"config的级别次之于waring,一般用于输出系统的配置信息。Level.CONFIG:{0}",new Object[]{Level.CONFIG.intValue()});
logger.log(Level.FINE,"fine的级别次之于config,输出信息详细。Level.FINE:{0}",new Object[]{Level.FINE.intValue()});
logger.log(Level.FINER,"finer的级别次之于fine,输出信息更加详细。Level.FINER:{0}",new Object[]{Level.FINER.intValue()});
logger.log(Level.FINEST,"finest的级别次之于finer,也是最低的级别,输出信息非常详细。Level.FINEST:{0}",new Object[]{Level.FINEST.intValue()});
//两个特殊的级别
logger.log(Level.OFF,"用于关闭日志输出信息。常量值是integer的最大值。Level.OFF:{0}",new Object[]{Level.OFF.intValue()});
logger.log(Level.ALL,"用于打开输出信息。常量值是integer的最小值。Level.ALL:{0}",new Object[]{Level.ALL.intValue()});
}
/**
* description 测试自定义设置日志记录器的日志输出级别
* @param
* @return void
* @author shiPengYu
* @date 2022/2/15
*/
@Test
public void testSetLogger(){
//获取一个logger对象
Logger logger = Logger.getLogger("com.yzj.JulUse");
//关闭使用父级的日志管理器
logger.setUseParentHandlers(false);
//设置自身的日志输出级别
logger.setLevel(Level.FINEST);
//创建一个日志处理器对象
ConsoleHandler consoleHandler = new ConsoleHandler();
//设置处理器的日志输出级别
consoleHandler.setLevel(Level.FINEST);
//创建一个日志格式转换对象
SimpleFormatter simpleFormatter = new SimpleFormatter();
//将格式化对象与处理器进行关联
consoleHandler.setFormatter(simpleFormatter);
//将日志记录器关联到日志管理器
logger.addHandler(consoleHandler);
logger.severe("severe msg");
logger.warning("warning msg");
logger.info("info msg");
logger.config("config msg");
logger.fine("fine msg");
logger.finer("finer msg");
logger.finest("finest msg");
}
/**
* description 测试使用文件出处理器对象将日志输出到日志文件
* @param
* @return void
* @author shiPengYu
* @date 2022/2/15
*/
@Test
public void testOutputFile() throws IOException {
Logger logger = Logger.getLogger("com.yzj.JulUse");
logger.setUseParentHandlers(false);
logger.setLevel(Level.ALL);
//新建一个文件处理器对象,参数true代表追加写
FileHandler fileHandler = new FileHandler("src/com/yzj/log.log",true);
SimpleFormatter simpleFormatter = new SimpleFormatter();
fileHandler.setFormatter(simpleFormatter);
fileHandler.setLevel(Level.ALL);
logger.addHandler(fileHandler);
logger.severe("severe msg");
logger.warning("warning msg");
logger.info("info msg");
logger.config("config msg");
logger.fine("fine msg");
logger.finer("finer msg");
logger.finest("finest msg");
}
/**
* description 测试使用多个管理器、多个格式转换器的情况
* @param
* @return void
* @author shiPengYu
* @date 2022/2/15
*/
@Test
public void testHandlers() throws IOException {
Logger logger = Logger.getLogger("com.yzj.JulUse");
logger.setUseParentHandlers(false);
logger.setLevel(Level.INFO);
//文件处理器
FileHandler fileHandler = new FileHandler("src/com/yzj/log.log",true);
//使用xml格式转换
XMLFormatter xmlFormatter = new XMLFormatter();
fileHandler.setFormatter(xmlFormatter);
fileHandler.setLevel(Level.CONFIG);
logger.addHandler(fileHandler);
//控制台处理器
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINEST);
//简单格式转换
SimpleFormatter simpleFormatter = new SimpleFormatter();
consoleHandler.setFormatter(simpleFormatter);
//consoleHandler.setFormatter(xmlFormatter);
logger.addHandler(consoleHandler);
logger.severe("severe msg");
logger.warning("warning msg");
logger.info("info msg");
logger.config("config msg");
logger.fine("fine msg");
logger.finer("finer msg");
logger.finest("finest msg");
}
/**
* description 默认的日志级别以及其余的配置都位于配置文件%java home%\jre\lib\logging.properties中,
* 将默认日志文件复制一份到项目,进行日志文件的配置方式进行配置日志
* @param
* @return void
* @author shiPengYu
* @date 2022/2/15
*/
@Test
public void testUsePropertiesFile() throws IOException {
//通过本类获取到本类的类加载器,然后加载资源流
InputStream ins = JulUseTest.class.getClassLoader().getResourceAsStream("com/yzj/logging.properties");
//获取LogManager对象
LogManager logManager = LogManager.getLogManager();
//读取配置文件配置
logManager.readConfiguration(ins);
Logger logger = Logger.getLogger("com.yzj.JulUseTest");
logger.severe("severe msg:配置文件的练习使用");
logger.warning("warning msg:配置文件的练习使用");
logger.info("info msg:配置文件的练习使用");
logger.config("config msg:配置文件的练习使用");
logger.fine("fine msg:配置文件的练习使用");
logger.finer("finer msg:配置文件的练习使用");
logger.finest("finest msg:配置文件的练习使用");
}
}
JUL日志配置文件:
#顶级父元素RootLogger,也就是根元素,默认的日志处理器
#handlers= java.util.logging.ConsoleHandler
#同时配置多个日志处理器
handlers= java.util.logging.ConsoleHandler
#根日志处理器的默认输出级别
.level= INFO
#自定义配置
#定义一个顶级包的日志记录器
#日志级别
com.yzj.level=ALL
#关闭使用父级Handler
com.yzj.useParentHandlers=false
#配置自己的Handler
com.yzj.handlers=java.util.logging.FileHandler,java.util.logging.ConsoleHandler
#日志文件的路径
java.util.logging.FileHandler.pattern = ./src/com/yzj/java%u.log
#单个日志文件记录的日志记录条数
java.util.logging.FileHandler.limit = 200
#日志文件的个数
java.util.logging.FileHandler.count = 1
#指定xml格式转换器
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
#配置级别
java.util.logging.FileHandler.level = CONFIG
#追加写
java.util.logging.FileHandler.append=true
#配置编码
java.util.logging.FileHandler.encoding=utf-8
#配置格式化的格式
java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
#控制台输出处理器的输出级别控制
java.util.logging.ConsoleHandler.level = ALL
#指定简单格式转换器
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
#配置编码
java.util.logging.ConsoleHandler.encoding = utf-8
JUL使用总结
1、默认的日志级别为info,是指根Logger的日志级别,Logger具有父子关系,默认会使用从父级Logger继承下来的配置。所以想要自定义日志配置,需要关闭使用父级配置,然后再进行配置。
2、同一个Logger可以具有多个Handler,从而同时将日志输出到不通过的目标上。
3、Logger与Handler都有设置日志级别的作用,但是最终输出需要看: 3.1、Logger级别<Handler级别时,所有的输出信息都以Logger的级别为准 3.2、Logger级别>Handler级别时,具体的输出看Handler的级别。 即:Logger控制在前,Handler控制在后
4、日志输出时注意占位符方式输出,字符串形式性能较低,拼接麻烦
因为新建的Logger默认使用RootLogger的输出级别,而RootLogger默认添加的ConsoleHandler的默认输出级别也是info,所以在自定义输出级别时,别忘了将两个级别都按照自己的需要设置一遍