1、简单介绍-JCL
JCL( Jakarta Commons Logging ),是 Apache 提供的一个 通用日志 API 。用户可以自由选择第三方的日志组件作为具体实现,像 Log4j 或 JDK 自带的 JUL 。
JCL的原则:如果有log4j优先使用log4j,没有任何的第三方框架就使用JUL。
面向接口开发,不再依赖具体的实现类,可以根据实际需求,灵活的切换日志框架。统一的 API,统一的配置管理便于项目日志的维护工作。
JCL 有两个基本的抽象类:Log(日志记录器)、LogFactory(日志工厂,负责创建 Log 实例)。
1.1、案列
1.依赖:
<dependencies>
<!-- jcl日志门面 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2.代码:
public class JCLTest {
@Test
public void test01(){
// JCL使用原则:有Log4j则优先使用,没有任何第三方日志框架则默认使用JUL
Log log = LogFactory.getLog(JCLTest.class);
log.info("info信息");
}
}
3.运行结果:没有第三方框架,可以看出使用了 JDK 的 JUL 日志框架。
六月 05, 2023 12:01:58 上午 com.xb.JCLTest test01
信息: info信息
4.引入其他框架依赖:log4j的依赖
<!-- log4j日志框架 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
5.创建配置: log4j.properties 文件 ,放在resources目录下
#配置日志级别,引用控制器
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{yyyy-MM-dd HH:mm:ss.SSS}] [%-5p] [%t] [%-4rms] [%c#%M-%L] %m%n
6. 其他代码不变,查看日志信息:使用了log4j框架输出日志信息
[2023-06-05 00:12:44.642] [INFO ] [main] [0 ms] [com.xb.JCLTest] test01 20 info信息
2、介绍-SLF4j
背景:在log4j开发出来出来之后,log4j就受到了广大开发者的爱好,纷纷开始使用log4j,但是后来 log4j的创始人跟apache因为一些矛盾从apache辞职自己去创业了,创始人为了给自己的公司打出一点名声,所以就基于log4j又开发出了一个新的日志框架 logback,logback不管是性能还是功能都比log4j强,但是却很少人使用, 因为jcl门面不支持logback,所以这个创世人又设计出了slf4j,slf4j支持市面上所有主流的日志框架;所以目前为止,使用最多的就是slf4j了; 后来 apache又基于 logback 的源码 设计出了 log4j2 日志,性能上log4j2比logback更胜一筹,并且log4j2既是日志框架,也是门面技术,但是log4j2的门面技术很少人使用,大多还是使用slf4j;
介绍:主要是为了给 Java 日志访问提供一套标准、规范的 API 框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,例如 Log4j 或 Logback 等。
SLF4J 自身也提供了功能较为简单的实现,但是一般很少用到。对于一般的 Java 项目而言,日志框架会选择 slf4j-api 作为门面,配上具体的实现框架,中间使用桥接器完成桥接。所以 SLF4J 最重要的两个功能就是对于日志框架的绑定以及日志框架的桥接。
2.1、 日志级别
只输出级别不低于设定级别的日志信息。
trace:日志追踪信息
debug:日志详细信息
info(默认):日志关键信息
warn:日志警告信息
error:日志错误信息
2.2、入门案例
导入依赖:
<dependencies>
<!-- slf4j核心依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!-- slf4j自带的简单日志实现 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--设置编译版本1.8-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
代码:在没有引入其他的依赖就使用的是slf4j自带的日志框架
@Test
public void test01(){
// 没有集成其它日志实现框架的话,使用自带的简单日志实现框架(slf4j-simple)
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
logger.trace("trace追踪信息");
logger.debug("debug详细信息");
logger.info("info关键信息");
logger.warn("warn警告信息");
logger.error("error错误信息");
//动态拼接使用占位符
logger.info("学生信息:姓名-{};年龄-{}", name, age)
}
运行结果:
[main] INFO com.xb.Slf4jTest - info关键信息
[main] WARN com.xb.Slf4jTest - warn警告信息
[main] ERROR com.xb.Slf4jTest - error错误信息
2.3、动态打印
代码:占位符{}
@Test
public void test02() {
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
String name = "李四";
int age = 23;
// 字符串拼接,麻烦、可读性差
//logger.info("学生信息:姓名-" + name + ";年龄-" + age + "");
// 动态信息打印,使用占位符的形式来代替字符串的拼接
logger.info("学生信息:姓名-{};年龄-{}", name, age);
}
运行结果:
[main] INFO com.xb.Slf4jTest - 学生信息:姓名-李四;年龄-23
2.4、异常信息打印
代码:
@Test
public void test03() {
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
try {
Class.forName("Student");
} catch (ClassNotFoundException e) {
logger.info("异常信息:", e);
}
}
运行结果:
[main] INFO com.xb.Slf4jTest - 异常信息:
java.lang.ClassNotFoundException: Student
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.xb.Slf4jTest.test03(Slf4jTest.java:42)
....
2.5、日志集成
日志集成分为三种情况:
(1)没有绑定任何日志实现的基础上面,门面技术slf4j是不能够实现任何功能的。包括自带的slf4j-simpl官方提供的也必须导入相应的jar包配合使用。
(2)logback和simple(包括nop-禁止打印日志)都是slf4j时间线出现之后提供的日志实现,所以API完全遵循slf4j设计,使用只需要导入对应的jar包即可。
(3)log4j和JUL时间线是在slf4j之前的,要配合使用就必须通过适配桥接技术,完成与日志门面的连接。
注意: 在 SLF4J 环境下,若同时导入多个日志实现框架,默认使用先导入的。在实际应用中,一般只集成一种日志实现。
2.5.1、集成 logback
导入依赖:
<!-- 引入logback依赖-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
代码:
@Test
public void test04() {
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
try {
Class.forName("Student");
} catch (ClassNotFoundException e) {
logger.info("异常信息:", e);
}
}
运行结果:
SLF4J: Found binding in [jar:file:/E:/yc_maven/work/repository/org/slf4j/slf4j-simple/1.7.25/slf4j-simple-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
16:19:39.481 [main] INFO com.xb.Slf4jTest - 异常信息:
java.lang.ClassNotFoundException: Student
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.xb.Slf4jTest.test03(Slf4jTest.java:42)
2.5.2、集成log4j-桥接模式
导入依赖:这里加入的是适配,不是桥接
<!-- log4j适配器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!-- log4j日志框架 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
代码:
@Test
public void test05(){
// 没有集成其它日志实现框架的话,使用自带的简单日志实现框架(slf4j-simple)
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
logger.trace("trace追踪信息");
logger.debug("debug详细信息");
logger.info("info关键信息");
logger.warn("warn警告信息");
logger.error("error错误信息");
}
配置文件:使用log4j的配置文件
#配置日志级别,引用输出器
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{yyyy-MM-dd HH:mm:ss.SSS}] [%-5p] [%t] [%-4rms] [%c] %M %L %m%n
运行结果:
[2023-06-06 16:32:51.825] [INFO ] [main] [1 ms] [com.xb.Slf4jTest] test01 22 info关键信息
[2023-06-06 16:32:51.828] [WARN ] [main] [4 ms] [com.xb.Slf4jTest] test01 23 warn警告信息
[2023-06-06 16:32:51.828] [ERROR] [main] [4 ms] [com.xb.Slf4jTest] test01 24 error错误信息
2.5.3、集成JUL
依赖:
<!-- JUl适配slf4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
</dependency>
代码:
@Test
public void test05(){
// 没有集成其它日志实现框架的话,使用自带的简单日志实现框架(slf4j-simple)
Logger logger = LoggerFactory.getLogger(Slf4jTest.class);
logger.trace("trace追踪信息");
logger.debug("debug详细信息");
logger.info("info关键信息");
logger.warn("warn警告信息");
logger.error("error错误信息");
}
结果:可以看出是JUL日志框架的输出风格
六月 06, 2023 4:37:37 下午 com.xb.Slf4jTest test01
信息: info关键信息
六月 06, 2023 4:37:37 下午 com.xb.Slf4jTest test01
警告: warn警告信息
六月 06, 2023 4:37:37 下午 com.xb.Slf4jTest test01
严重: error错误信息
现在项目使用的是log4j,如何将项目框架转换成为logback?
(1)注释掉log4j依赖
(2)引入slf4j门面依赖和logback依赖
(3)此时代码编译会报错,继续引入log4j的桥接依赖,完成
<dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.25</version> </dependency>注意:桥接器和适配器不能同时存在。