一、日志门面的意义
当我们的系统变的更加复杂的时候,我们的日志就容易发生混乱。随着系统开发的运行,可能会更新不同的日志框架,造成当前系统中存在不同的日志依赖,让我们难以统一的管理和控制,就算我们强制要求所有的模块使用相同的日志框架,系统中也难以避免使用其他类似spring,mybatis等其他的第三方框架,它们依赖于我们规定不同的日志框架,而且他们自身的日志系统就有着不一致性,依然会出来日志体系的混乱。。。
常见的日志门面:JCL、slf4j
常见的日志实现:JUL、log4j、logback、log4j2
二、Slf4j的使用(http://www.slf4j.org/)
简单日志门面(Simple Logging Facade For Java):Slf4j主要是为了给Java日志访问提供一套标准,规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如log4j和logback等。当然slf4j自己也提供了功能较为简单的实现,但是一般很少用到。对于一般的java项目而言,日志框架会选择slf4j-api作为门面,配上具体的实现框架(log4j、logback等),中间使用桥接器完成桥接。
slf4j是目前世面上最流行的日志门面。现在的项目中,基本上都是使用slf4j作为我们的日志系统。
Slf4j日志门面主要提供两大功能:
1.日志框架的绑定;
slf4j支持各种日志框架。slf4j发行版附带了几个称为“slf4j绑定”的jar文件,每个绑定对应一个受支持的框架。
使用slf4j的日志绑定流程:
(1)添加slf4j-api的依赖
(2)使用slf4j的API在项目中进行统一的日志记录
(3)绑定具体的日志实现框架
绑定已经实现了slf4j的日志框架,直接添加对应依赖
绑定没有实现slf4j的日志框架,先添加日志的适配器,在添加实现类的依赖
(4) slf4j有且仅有一个日志实现框架的绑定(如果出现多个默认使用第一个依赖日志实现)
要切换日志记录框架,只需在类路径上替换slf4j绑定即可。例如,要从java.util.logging切换到log4j,只需将slf4j-jdk14-1.7.28.jar替换为slf4j-log4j12-1.7.28.jar。
SLF4J不依赖任何特殊类的装载机。实际上,每个SLF4J绑定在编译时都 进行了硬连线,以使用一个且仅一个特定的日志记录框架。例如,slf4j-log4j12-1.7.28.jar绑定在编译时绑定为使用log4j。在代码中,除了slf4j-api-1.7.28.jar之外,您只需将选择的一个和仅一个绑定拖放 到适当的类路径位置即可。在类路径上不要放置多个绑定。这是一般想法的图形化说明。
2.日志框架的桥接;
通常,您依赖的某些组件依赖于slf4j以外的日志记录API。您也可以假设这些组件在不久的将来不会切换到slf4j。为了解决这种情况,slf4j附带了几个桥接模块,这些模块将对log4j,JCL和java.util.logging API的调用重定向,就好像它们是对slf4j API一样。
桥接解决的是项目中日志的遗留问题,当系统中存在之前的日志API,可以通过桥接转换到slf4j的实现
1.先去除之前老的日志框架的依赖
2.添加slf4j提供的桥接组件
3.为项目添加slf4j的具体实现
注意问题:
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等对象,将无法产生效果。
三、Slf4j入门
日志框架的绑定:
1.添加依赖:
slf4j绑定内置的日志实现框架
<!-- 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.21</version>
</dependency>
slf4j绑定logback日志实现框架
<!-- slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- logback日志实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
nop日志开关:
<!-- slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- nop日志开关-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.25</version>
</dependency>
slf4j绑定log4j日志实现框架
<!-- slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- 绑定 log4j日志实现,需要导入适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.29</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
绑定 log4j日志实现,不仅需要导入适配器,还需要导入配置文件log4j.properties:
#配置根 Loggers控制日志的输出级别与日志是否输出
log4j.rootLogger=trace,console
#自定义logger对象设置
log4j.logger.LoggerDemo = info,file
#配置输出到控制台 Appenders是指定日志的输出方式
log4j.appender.console=org.apache.log4j.ConsoleAppender
#指定输出控制台
log4j.appender.console.Target = System.out
#指定布局,输出日志的格式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
#指定布局的参数
log4j.appender.console.layout.ConversionPattern=[%-10p] %r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
#配置输出到控制台 Appenders是指定日志的输出方式
log4j.appender.file=org.apache.log4j.FileAppender
#指定布局,输出日志的格式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
#指定布局的参数
log4j.appender.file.layout.ConversionPattern=[%-10p] %r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
#指定日志文件保存路径
log4j.appender.file.file = /logs/log4j.log
#指定日志文件字符集
log4j.appender.file.encoding = UTF-8
#配置输出到控制台 Appenders是指定日志的输出方式
log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
#指定布局,输出日志的格式
log4j.appender.rollingFile.layout=org.apache.log4j.PatternLayout
#指定布局的参数
log4j.appender.rollingFile.layout.ConversionPattern=[%-10p] %r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
#指定日志文件保存路径
log4j.appender.rollingFile.file = /logs/log4j.log
#指定日志文件字符集
log4j.appender.rollingFile.encoding = UTF-8
#指定日志文件内容的大小
log4j.appender.rollingFile.maxFileSize = 1MB
#指定日志文件的数量
log4j.appender.rollingFile.maxBackupIndex = 10
#配置输出到控制台 Appenders是指定日志的输出方式
log4j.appender.dailyRollingFile=org.apache.log4j.DailyRollingFileAppender
#指定布局,输出日志的格式
log4j.appender.dailyRollingFile.layout=org.apache.log4j.PatternLayout
#指定布局的参数
log4j.appender.dailyRollingFile.layout.ConversionPattern=[%-10p] %r %l %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n
#指定日志文件保存路径
log4j.appender.dailyRollingFile.file = /logs/log4j.log
#指定日志文件字符集
log4j.appender.dailyRollingFile.encoding = UTF-8
#指定日志输出规则
log4j.appender.dailyRollingFile.datePattern = '.'yyyy-MM-dd-HH-mm-ss
#mysql
log4j.appender.logDB=org.apache.log4j.jdbc.JDBCAppender
#指定布局,输出日志的格式
log4j.appender.logDB.layout=org.apache.log4j.PatternLayout
log4j.appender.logDB.Driver = com.mysql.jdbc.Driver
log4j.appender.logDB.URL = jdbc:mysql://localhost:3306/logs
log4j.appender.logDB.User = root
log4j.appender.logDB.Password = root
log4j.appender.logDB.Sql = INSERT INTO log(project_name,create_date,level,category,file_name,thread_name,line,all_category,message) values('itcast','%d{yyyy-MM-dd HH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')
slf4j绑定jul日志实现框架
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.6</version>
</dependency>
<!-- 绑定jul日志实现,需要导入适配器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.6</version>
</dependency>
2.测试Demo
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SLF4j {
public static final Logger LOGGER = LoggerFactory.getLogger(SLF4j.class);
// 快速入门
@Test
public void test01() throws Exception{
// 日志输出
LOGGER.error("error");
LOGGER.warn("waring");
LOGGER.info("info");
LOGGER.debug("debug");
LOGGER.trace("trace");
// 使用占位符输出日志消息
String name = "itheima";
Integer age = 14;
LOGGER.info("用户:{},{}",name,age);
// 异常日志输出
try {
int i = 1/0;
} catch (Exception e) {
LOGGER.error("出现异常:",e);
}
}
}
3.测试结果:
slf4j绑定内置的日志实现框架的测试结果:
[main] ERROR SLF4j - error
[main] WARN SLF4j - waring
[main] INFO SLF4j - info
[main] INFO SLF4j - 用户:itheima,14
[main] ERROR SLF4j - 出现异常:
java.lang.ArithmeticException: / by zero
at SLF4j.test01(SLF4j.java:26)
...
slf4j绑定logback日志实现框架的测试结果:
20:25:21.724 [main] ERROR SLF4j - error
20:25:21.739 [main] WARN SLF4j - waring
20:25:21.739 [main] INFO SLF4j - info
20:25:21.739 [main] DEBUG SLF4j - debug
20:25:21.739 [main] INFO SLF4j - 用户:itheima,14
20:25:21.742 [main] ERROR SLF4j - 出现异常:
java.lang.ArithmeticException: / by zero
nop日志开关,打开日志开关的测试结果:
日志开关打开了,关闭了日志打印的功能
F:\DevelopmentTools\Java\jdk1.8.0_152\bin\java.exe -ea -...
Process finished with exit code 0
slf4j绑定log4j日志实现框架的测试结果:
[ERROR ] 0 SLF4j.test01(SLF4j.java:14) 2020-02-20 00:10:50.942 error
[WARN ] 3 SLF4j.test01(SLF4j.java:15) 2020-02-20 00:10:50.945 waring
[INFO ] 3 SLF4j.test01(SLF4j.java:16) 2020-02-20 00:10:50.945 info
[DEBUG ] 3 SLF4j.test01(SLF4j.java:17) 2020-02-20 00:10:50.945 debug
[TRACE ] 4 SLF4j.test01(SLF4j.java:18) 2020-02-20 00:10:50.946 trace
[INFO ] 5 SLF4j.test01(SLF4j.java:23) 2020-02-20 00:10:50.947 用户:itheima,14
[ERROR ] 5 SLF4j.test01(SLF4j.java:28) 2020-02-20 00:10:50.947 出现异常:
java.lang.ArithmeticException: / by zero
slf4j绑定jul日志实现框架的测试结果:
二月 20, 2020 12:31:55 下午 SLF4j test01
严重: error
二月 20, 2020 12:31:55 下午 SLF4j test01
警告: waring
二月 20, 2020 12:31:55 下午 SLF4j test01
信息: info
二月 20, 2020 12:31:55 下午 SLF4j test01
信息: 用户:itheima,14
二月 20, 2020 12:31:55 下午 SLF4j test01
严重: 出现异常:
java.lang.ArithmeticException: / by zero
日志框架的桥接:
1.添加依赖:
log4j的桥接器,替代log4.jar包以及适配器,让logback日志实现log4j日志
<!-- slf4j日志门面-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!-- logback日志实现-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 配置log4j的桥接器-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.26</version>
</dependency>
2.测试demo
import org.apache.log4j.Logger;
import org.junit.Test;
public class Log4jTest {
// 定义 log4j 日志记录器
public static final Logger LOGGER = Logger.getLogger(Log4jTest.class);
// 测试桥接器
@Test
public void test01() throws Exception{
LOGGER.info("hello log4j");
}
}
3.测试结果:
13:20:55.469 [main] INFO Log4jTest - hello log4j