Java日志框架 -- 日志框架介绍日志门面技术JUL日志(JUL架构JUL入门示例JUL日志级别JUL日志的配置文件)
Posted CodeJiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java日志框架 -- 日志框架介绍日志门面技术JUL日志(JUL架构JUL入门示例JUL日志级别JUL日志的配置文件)相关的知识,希望对你有一定的参考价值。
1. 日志的概念
日志文件是用于记录系统操作事件的文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。
2. Java日志框架
问题:
- 控制日志输出的内容和格式。
- 控制日志输出的位置。
- 日志优化:异步日志,日志文件的归档和压缩。
- 日志系统的维护。
- 面向接口开发 :日志的门面。
2.1 为什么要用日志框架
因为软件系统发展到今天已经很复杂了,特别是服务器端软件,涉及到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事务处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。
2.2 现有的日志框架
- JUL(java util logging)
- logback
- log4j
- log4j2
- JCL(Jakarta Commons Logging)
- slf4j( Simple Logging Facade for Java)
日志门面(抽象层):是日志实现的抽象类。有JCL、SLF4J
- JCL:当时设计时只考虑了主流的几个日志框架,而对于未来新兴框架并没有提供接口,之后随着slf4j出现就慢慢也不再使用了,最后一次版本更新停在2014年,现不再更新维护已被淘汰,不考虑使用。
- slf4j:能够统一管理所有的日志API,优秀的门面技术,并且其能够支持未来出现的新的日志框架系统并提供日志接口。Springboot推荐slf4j+logback,未来主流会是slf4j+log4j2。
日志实现:具体的日志功能实现。框架有JUL、log4j、log4j2、logback。
- JUL:JDK自带的日志实现依赖。
- logback:第三方的,Springboot默认推荐,搭配slf4j。
- log4j:Apache推出的,之后出现了Logback(性能更好),就开始慢慢被Logback取代了。
- log4j2:Apache根据Logback的设计思想推出了Log4j2,号称日志性能最好的实现技术,其本身也有日志门面只不过大多使用slf4j来作为日志门面。
日志框架出现的历史顺序:
log4j -->JUL-->JCL--> slf4j --> logback --> log4j2
2.3 日志门面技术介绍
当我们的系统变的更加复杂的时候,我们的日志就容易发生混乱。随着系统开发的进行,可能会更新不同的日志框架,造成当前系统中存在不同的日志依赖,让我们难以统一的管理和控制。就算我们强制要求所有的模块使用相同的日志框架,系统中也难以避免使用其他类似spring,mybatis等其他的第三方框架,它们依赖于我们规定不同的日志框架,而且他们自身的日志系统就有着不一致性,依然会出来日志体系的混乱。
所以我们需要借鉴JDBC的思想,为日志系统也提供一套门面,那么我们就可以面向这些接口规范来开发,避免了直接依赖具体的日志框架。这样我们的系统在日志中,就存在了日志的门面和日志的实现。
2.3.1 日志门面技术的优点
- 面向接口开发,不再依赖具体的实现类。减少代码的耦合
- 项目通过导入不同的日志实现类,可以灵活的切换日志框架
- 统一API,方便开发者学习和使用
- 统一配置便于项目日志的管理
2.3.2 日志门面和日志实现的关系
用户可以使用日志门面,然后根据需求,动态的选择具体的日志实现框架。这样就可以使所有日志实现框架拥有统一的规范。
3. JUL
3.1 JUL架构介绍
- Loggers:被称为记录器,应用程序通过获取Logger对象,调用其API来来发布日志信息。Logger通常时应用程序访问日志系统的入口程序。
- Appenders:也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日志等。
- Layouts:也被称为Formatters,它负责对日志事件中的数据进行转换和格式化。Layouts决定了数据在一条日志记录中的最终形式。
- Level:每条日志消息都有一个关联的日志级别。该级别粗略指导了日志消息的重要性和紧迫,我可以将Level和Loggers,Appenders做关联以便于我们过滤消息。
- Filters:过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过。
小结:用户使用Logger来进行日志记录,Logger持有若干个Handler,日志的输出操作是由Handler完成的。在Handler在输出日志前,会经过Filter的过滤,判断哪些日志级别过滤放行哪些拦截,Handler会将日志内容输出到指定位置(日志文件、控制台等)。Handler在输出日志时会使用Layout,将输出内容进行排版。
3.2 JUL入门示例
3.2.1 创建普通Maven项目,导入Junit单元测试依赖
3.2.2 编写测试代码
JULTest.java
package logs;
import org.junit.Test;
import java.util.logging.Level;
import java.util.logging.Logger;
public class JULTest
@Test
public void testQuick() throws Exception
// 1. 创建日志记录器对象, 每个记录器都有自己唯一的标识 一般是当前类的全限定类名作为标识
Logger logger = Logger.getLogger("logs.JULTest");
// 2. 日志记录输出
logger.info("hello jul");
// 3. 通用的方法进行日志的记录
logger.log(Level.INFO, "info msg");
String name = "jack";
Integer age = 18;
// 通过占位符数据变量的值
logger.log(Level.INFO, "用户信息:0 ,1", new Object[]name, age);
运行结果:
3.3 JUL日志的级别
JUL中定义的日志级别在Level当中:
下面我们来看看JUL日志的级别:
3.4 自定义日志级别配置
JULTest.java
@Test
public void testLogConfig() throws Exception
// 1.创建日志记录器对象
Logger logger = Logger.getLogger("logs.JULTest");
// 一、自定义日志级别
// a.关闭系统默认配置
logger.setUseParentHandlers(false);
// b.创建handler对象 把日志输出到控制台
ConsoleHandler consoleHandler = new ConsoleHandler();
// c.创建formatter对象
SimpleFormatter simpleFormatter = new SimpleFormatter();
// d.进行关联
consoleHandler.setFormatter(simpleFormatter);
logger.addHandler(consoleHandler);
// e.设置日志级别
logger.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
// 二、输出到日志文件
FileHandler fileHandler = new FileHandler("./jul.log");
fileHandler.setFormatter(simpleFormatter);
logger.addHandler(fileHandler);
// 2.日志记录输出
logger.severe("severe");
logger.warning("warning");
logger.info("info");
logger.config("config");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
运行结果:
3.5 Logger之间的父子关系
JUL中Logger之间存在父子关系,这种父子关系通过树状结构存储,JUL在初始化时会创建一个顶层RootLogger作为所有Logger父Logger,存储上作为树状结构的根节点。并父子关系通过路径来关联。
测试代码:
@Test
public void testLogParent() throws Exception
// 日志记录器对象父子关系
Logger logger1 = Logger.getLogger("com.tian.log");
Logger logger2 = Logger.getLogger("com.tian");
// 返回True则表示logger1是logger2的孩子
System.out.println(logger1.getParent() == logger2);
// 所有日志记录器对象的顶级父元素 class为java.util.logging.LogManager$RootLogger name为""
System.out.println("logger2 parent:" + logger2.getParent() + ",name:" + logger2.getParent().getName());
运行结果:
3.6 日志的配置文件
默认配置文件路径:$JAVAHOME\\jre\\lib\\logging.properties
我们现在来自定义配置文件进行测试
测试代码:
JULTest.java
@Test
public void testProperties() throws Exception
// 读取自定义配置文件
InputStream in = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
// 获取日志管理器对象
LogManager logManager = LogManager.getLogManager();
// 通过日志管理器加载配置文件
logManager.readConfiguration(in);
Logger logger = Logger.getLogger("com.tian.JULTest");
logger.severe("severe");
logger.warning("warning");
logger.info("info");
logger.config("config");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
自定义配置文件位置
logging.properties
## RootLogger使用的处理器(获取时设置)
handlers=java.util.logging.ConsoleHandler
# RootLogger日志等级
.level=INFO
## 自定义Logger
com.tian.handlers=java.util.logging.FileHandler
# 自定义Logger日志等级
com.tian.level=INFO
# 忽略父日志设置
com.tian.useParentHandlers=false
## 控制台处理器
# 输出日志级别
java.util.logging.ConsoleHandler.level=INFO
# 输出日志格式
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
## 文件处理器
# 输出日志级别
java.util.logging.FileHandler.level=INFO
# 输出日志格式
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
# 输出日志文件路径
java.util.logging.FileHandler.pattern=C:/logs/java.log
# 输出日志文件限制大小(50000字节)
java.util.logging.FileHandler.limit=50000
# 输出日志文件限制个数
java.util.logging.FileHandler.count=1
# 输出日志文件 是否是追加
java.util.logging.FileHandler.append=false
运行结果:
以上是关于Java日志框架 -- 日志框架介绍日志门面技术JUL日志(JUL架构JUL入门示例JUL日志级别JUL日志的配置文件)的主要内容,如果未能解决你的问题,请参考以下文章
Java日志框架 -- JCL日志门面(JCL概念介绍JCL示例)