⽇志体系
- 1.体系概述
- 2.日志的使用
- 1.上古时代的sout
- 2.开创先驱的log4j
- 3.搞事情的JUL
- 4.应运⽽⽣的JCL
- 5.再起波澜的logback
- 6.再度⻘春的log4j2
本篇在jdk21下测试通过
1.体系概述
1.日志接口
- JCL:Apache基⾦会所属的项⽬,是⼀套Java⽇志接⼝,之前叫Jakarta Commons Logging,后更名为Commons Logging,简称JCL
- SLF4J:Simple Logging Facade for Java,缩写Slf4j,是⼀套简易Java⽇志⻔⾯,只提供相关接⼝,和其他⽇志⼯具之间需要桥接
2.⽇志实现
- JUL:JDK中的⽇志⼯具,也称为jdklog、jdk-logging,⾃Java1.4以来sun的官⽅提供
- Log4j:⾪属于Apache基⾦会的⼀套⽇志框架,现已不再维护
- Log4j2:Log4j的升级版本,与Log4j变化很⼤,不兼容
- Logback:⼀个具体的⽇志实现框架,和Slf4j是同⼀个作者,性能很好
2.日志的使用
1.上古时代的sout
在JDK 1.3及以前,Java打⽇志依赖System.out.println(), System.err.println()或者
e.printStackTrace(),Debug⽇志被写到STDOUT流,错误⽇志被写到STDERR流。这样打⽇志有⼀个⾮常⼤的缺陷,⾮常机械,⽆法定制,且⽇志粒度不够细分
System.out.println("123");
System.err.println("456");
2.开创先驱的log4j
注意了:这里案例采用的是log4j2的写法
2001年发布了Log4j,并将其捐献给了Apache软件基⾦会,成为Apache 基⾦会的顶级项⽬。Log4j 在设计上⾮常优秀,它定义的Logger、Appender、Level等概念对后续的 Java Log 框架有深远的影响,如今的很多⽇志框架基本沿⽤了这种思想
1.导入坐标
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.22.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.22.1</version>
</dependency>
2.编写配置文件 log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="MyFile" fileName="logs/app.log">
<PatternLayout>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %c{1} - %msg%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="MyFile"/>
</Root>
</Loggers>
</Configuration>
3.测试类
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class MyLog4j {
private static final Logger logger = LogManager.getLogger(MyLog4j.class);
public static void main(String[] args) {
int i = 1;
String msg = "测试";
String s = null;
// 记录不同级别的日志
logger.debug("Debug message:{},{},{}", i, msg, s);
logger.info("Info message:{},{},{}", i, msg, s);
logger.warn("Warning message:{},{},{}", i, msg, s);
logger.error("Error message:{},{},{}", i, msg, s);
logger.fatal("Fatal error message:{},{},{}", i, msg, s);
}
}
3.搞事情的JUL
sun公司对于log4j的出现内⼼隐隐表示嫉妒。于是在jdk1.4版本后,开始搞事情,增加了⼀个包为java.util.logging,简称为JUL,⽤以对抗log4j ,但是却给开发造成了麻烦。相互引⽤的项⽬之间可能使⽤了不同的⽇志框架,经常将代码搞得⼀⽚混乱
import java.util.logging.Logger;
public class MyJul {
static Logger logger = Logger.getLogger(MyJul.class.getName());
public static void main(String[] args) {
int i = 1;
String msg = "测试";
String s = null;
logger.info( "Info message :" + i + " " + "s" + " " + msg);
}
}
4.应运⽽⽣的JCL
从上⾯可以看出,JUL的api与log4j是完全不同的(参数只接受String)。由于⽇志系统互相没有关联,彼此没有约定,不同⼈的代码使⽤不同⽇志,替换和统⼀也就变成了⽐较棘⼿的⼀件事。假如你的应⽤使⽤log4j,然后项⽬引⽤了⼀个其他团队的库,他们使⽤了JUL,你的应⽤就得使⽤两个⽇志系统了,然后其他团队⼜使⽤了simplelog……这个时候如果要调整⽇志的输出级别,⽤于跟踪某个信息,简直就是⼀场灾难
那这个状况该如何解决呢?答案就是进⾏抽象,抽象出⼀个接⼝层,对每个⽇志实现都适配或者转接,这样这些提供给别⼈的库都直接使⽤抽象层即可 ,以后调⽤的时候,就调⽤这些接⼝。(⾯向接⼝思想)
于是,JCL(Jakarta Commons Logging)应运⽽⽣,也就是commons-logging-xx.jar组件。JCL 只提供 log 接⼝,具体的实现则在运⾏时动态寻找。这样⼀来组件开发者只需要针对 JCL 接⼝开发,⽽调⽤组件的应⽤程序则可以在运⾏时搭配⾃⼰喜好的⽇志实践⼯具
1.导入坐标
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.3.0</version>
</dependency>
2.测试代码
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyJul {
private static Log logger = LogFactory.getLog(MyJul.class);
public static void main(String[] args) {
int i = 1;
String msg = "测试";
String s = null;
logger.info( "Info message :" + i + " " + "s" + " " + msg);
logger.debug("Debug message :" + i + " " + "s" + " " + msg);
logger.fatal("Fatal message :" + i + " " + "s" + " " + msg);
logger.error("Error message :" + i + " " + "s" + " " + msg);
}
}
5.再起波澜的logback
针对以上情况,log4j的作者再次出⼿,他觉得JCL不好⽤,⾃⼰⼜写了⼀个新的接⼝api,就是slf4j,并且为了追求更极致的性能,新增了⼀套⽇志的实现,就是logback,⼀时间烽烟⼜起……
1.导入坐标
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.10</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.4.14</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
2.编写配置文件logback.xml
<configuration>
<!-- 定义日志输出格式 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%-5level] [%date{yyyy-MM-dd HH:mm:ss.SSS}] %logger{96} [%line] [%thread]- %msg%n</pattern>
</encoder>
</appender>
<!-- 定义日志文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天滚动,每天生成一个新的日志文件 -->
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 文件保留策略,只保留最近30天的日志文件 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别 -->
<root level="debug">
<!-- 将控制台和文件Appender关联到根Logger -->
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
<!-- 针对特定包或类设置不同的日志级别 -->
<!-- <logger name="com.andy.log.logback.*" level="debug" /> -->
</configuration>
3.测试代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyLogback {
static final Logger logger = LoggerFactory.getLogger(MyLogback.class);
public static void main(String[] args) {
int i = 1;
String msg = "测试";
String s = null;
// 记录不同级别的日志
logger.debug("Debug message:{}:{}:{}", i, msg, s);
logger.info("Info message:{}:{}:{}", i, msg, s);
logger.warn("Warning message:{},{},{}", i, msg, s);
logger.error("Error message:{}:{}:{}", i, msg, s);
}
}
6.再度⻘春的log4j2
请参考 “开创先驱的log4j” 的写法
log4j2以性能著称,它⽐其前身Log4j 1.x提供了重⼤改进,同时类⽐logback,它提供了Logback中可⽤的许多改进,同时修复了Logback架构中的⼀些固有问题。功能上,它有着和Logback相同的基本操作,同时⼜有⾃⼰独特的部分,⽐如:插件式结构、配置⽂件优化、异步⽇志等
到log4j2,轰轰烈烈的java log战役基本就结束了