日志组件:
我们经常在开发项目的时候,需要打印记录项目过程中的一些日志。那我们经常大概会用到 log4j、jul、jcl、slf4j、simple、nop、logback 等等,那我们就详细介绍下这些组件是怎么做日志打印的
JUL:
JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框架使用方便,学习简单,能够在小型应用中灵活使用。
架构介绍:
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,将输出内容进行排版
案例:
public class JULTest { @Test
public void test01() {
// 1.获取日志记录器对象
Logger logger = Logger.getLogger("jul");
// 2.日志记录输出
logger.info("jul");
}
}
日志的级别:
jul中定义的日志级别
java.util.logging.Level中定义了日志的级别:
SEVERE(最高值)
WARNING 警告信息
INFO (默认级别)
CONFIG 配置信息
FINE debug级别信息,信息颗粒度最小
FINER debug级别信息
FINEST(最低值)debug级别信息,信息颗粒度最大
还有两个特殊的级别:
OFF,可用来关闭日志记录。
ALL,启用所有消息的日志记录。
日志级别案例:
@Test
public void testLogLevel() {
// 1.获取日志对象
Logger logger = Logger.getLogger("jul");
// 2.日志记录输出
logger.severe("severe");
logger.warning("warning");
logger.info("info");
logger.config("config");
logger.fine("fine");
logger.finer("finer");
logger.finest("finest");
}
由于默认级别是info, 所以以上日志只会打印 info以上级别的日志
修改日志级别:
@Test
public void testLogConfig() throws IOException {
// 1.创建日志记录器对象
Logger logger = Logger.getLogger("jul"); // 一、自定义日志级别
// 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.FINE);
consoleHandler.setLevel(Level.FINE); // 二、输出到日志文件
FileHandler fileHandler = new FileHandler("d:/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");
}
JCL:
JCL全称为Jakarta Commons Logging,是Apache提供的一个通用日志API。
它是为 "所有的Java日志实现"提供一个统一的接口,它自身也提供一个日志的实现,但是功能非常弱(SimpleLog)。所以一般不会单独使用它。
他允许开发人员使用不同的具体日志实现工具: Log4j, Jdk自带的日志(JUL)
JCL 有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。
默认使用 jul 的实现
案例:
1.添加依赖
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2. 测试
public class JCLTest { @Test
public void test() {
// 创建日志对象
Log log = LogFactory.getLog("jcl");
// 日志记录输出
log.info("info");
}
}
JCL原理:
1. 通过LogFactory动态加载Log实现类
2 . 日志门面支持的日志实现数组
3 . 获取具体的日志实现
LOG4J:
Log4j是Apache下的一款开源的日志框架,通过在项目中使用 Log4J,我们可以控制日志信息输出到控制台、文件、甚至是数据库中。我们可以控制每一条日志的输出格式,通过定义日志的输出级别,可以更灵活的控制日志的输出过程。方便项目的调试
log4j.properties(最简单配置)
log4j.rootLogger=INFO,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
案例:
1. 添加依赖
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2. 测试
@Test
public void test01() {
// 获取日志记录器对象
Logger logger = Logger.getLogger(Log4jTest.class);
// 日志记录输出
logger.info("hello log4j"); // 日志测试
logger.info("info");
}
日志的级别:
每个Logger都有一个日志级别(log level),用来控制日志信息的输出。日志级别从高到低分为:
fatal 指出每个严重的错误事件将会导致应用程序的退出。
error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
warn 表明会出现潜在的错误情形。
info 一般和在粗粒度级别上,强调应用程序的运行全程。
debug 一般用于细粒度级别上,对调试应用程序非常有帮助。(默认级别)
trace 是程序追踪,可以用于输出程序运行中的变量,显示执行的流程。
还有两个特殊的级别:
OFF,可用来关闭日志记录。
ALL,启用所有消息的日志记录。
注:一般只使用 4个级别,优先级从高到低为 ERROR > WARN > INFO > DEBUG
slf4j:
简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等。当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的Java项目而言,日志框架会选择slf4j-api作为门面,通过绑定器绑定具体的实现框架(log4j、logback等)进行日志打印,与第三方其它框架统一日志的时候,中间使用桥接器完成桥接。
SLF4J是目前市面上最流行的日志门面。现在的项目中,基本上都是使用SLF4J作为日志系统。
SLF4J日志门面主要提供两大功能:
1. 日志框架的绑定
2. 日志框架的桥接
入门案例:
1. 添加依赖
<dependencies>
<!--slf4j core 使用slf4j必須添加-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!--slf4j 自带的简单日志实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.27</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2. 测试
public class Slf4jTest { // 声明日志对象
public final static Logger LOGGER =
LoggerFactory.getLogger("slf4j"); @Test
public void test01() {
//打印日志信息
LOGGER.info("info");
}
}
绑定日志的实现(Binding):
SLF4J支持各种日志框架。SLF4J发行版附带了几个称为“SLF4J绑定”的jar文件,每个绑定对应一个受支持的框架。
使用slf4j的日志绑定流程:
1. 添加slf4j-api的依赖
2. 使用slf4j的API在项目中进行统一的日志记录
3. 绑定具体的日志实现框架
1. 绑定已经实现了slf4j的日志框架,直接添加对应依赖
2. 绑定没有实现slf4j的日志框架,先添加日志的适配器,再添加实现类的依赖
4. slf4j有且仅有一个日志实现框架的绑定(如果出现多个默认使用第一个依赖日志实现)
通过maven引入常见的日志实现框架:(根据实际情况选择使用,除了引入下面其中一个,还不能少了 slf4j-api 的引用)
官方绑定器API地址: http://www.slf4j.org/manual.html
1. logback
<!-- logback 日志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
2. nop
<!-- nop 日志开关(不使用日志功能) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
3. log4j
<!-- 绑定 log4j 日志实现,需要导入适配器,还需要添加 log4j.properties 配置文件 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.26</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
4. jul
<!-- 绑定 jul 日志实现,需要导入适配器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
</dependency>
<!-- 因为是java原生的日志框架,已经内置了具体实现 -->
原理:
桥接其它框架日志的实现(Bridging):
桥接解决的是项目中日志的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现
1. 先去除之前老的日志框架的依赖
2. 添加SLF4J提供的桥接组件
3. 为项目添加SLF4J的具体实现
4. 统一应用和框架的日志实现
迁移的方式:
如果我们要使用SLF4J的桥接器,替换原有的日志框架,那么我们需要做的第一件事情,就是删除掉原有项目中的日志框架的依赖。然后替换成SLF4J提供的桥接器。
官方api地址: http://www.slf4j.org/legacy.html
原理:
1. log4j
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- 配置 log4j 的桥接器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
2. logback
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- 配置 log4j 的桥接器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<!-- logback 日志实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
3. jcl
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- 配置 jcl 的桥接器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.8</version>
</dependency>
4. jul
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- 配置 jul 的桥接器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
注:
1. jcl-over-slf4j.jar(桥接)和 slf4j-jcl.jar(适配)不能同时部署。前一个jar文件将导致JCL将日志系统的选择委托给SLF4J,后一个jar文件将导致SLF4J将日志系统的选择委托给JCL,从而导致无限循环 。
2. log4j-over-slf4j.jar和slf4j-log4j12.jar不能同时出现,原因同上
3 . jul-to-slf4j.jar和slf4j-jdk14.jar不能同时出现,原因同上
4. 所有的桥接都只对Logger日志记录器对象有效,如果程序中调用了内部的配置类或者是Appender,Filter等对象,将无法产生效果。