<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
//import对应的信息:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
LoggerFactory.getLogger用法
java开发过程中经常需要打印日志信息,往往会在每个类的第一行加上形如以下代码:
protected static final Logger logger = LoggerFactory.getLogger(XXX.class);
目的:使用指定的类XXX初始化日志对象,方便在日志输出的时候,可以打印出日志信息所属的类。
示例:
protected static final Logger logger = LoggerFactory.getLogger(XYZ.class);
logger.debug("hello world");
输出:XYZ:hello world
*/
2. @Slf4j用作日志输出
@Slf4j是用作日志输出的,一般会在项目每个类的开头加入该注解,如果不写下面这段代码,并且想用log
private final Logger log = LoggerFactory.getLogger(XYZ.class);
@Slf4来代替;这样就省去这段很长的代码【添加了该注释之后,就可以在代码中直接饮用log.info( ) 打印日志了】
import ...
@Slf4j
public class Controller {
public String getInfo() {
log.info("日志信息");
}
}
3. log4j.properties配置文件
### 设置### log4j.rootLogger = debug,stdout,D,E ### 输出信息到控制抬 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n ### 输出DEBUG 级别以上的日志到=E://logs/error.log ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = E://logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n ### 输出ERROR 级别以上的日志到=E://logs/error.log ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =E://logs/error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
上面内容说明
%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH\:mm\:ss},输出类似:2015-12-09 22:05:36
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:TestLog4j:16
1. 引入slf4j的一个疑问。。。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
疑问:为什么单纯的引入slf4j-log4j12就可以实现slf4j了?完全不需要依赖log4j吗?这个不是log4j实现支持slf4j才会引入的依赖库[slf4j-log4j12]吗?
本质上可以看到:slf4j-log4j12已经依赖了log4j和slf4j-api了。所以不需要了哈
2. 附加问题?这里只引入(log4j和slf4j-api是否可行,为什么?)
如上:不可行,在做日志的实现(绑定),slf4j-api提供了接口,log4j是具体的实现,没有东西把这两个联系起来,也就是没有适配层。。。 所以会出错【下图可以看到】
同理:logback类似
还是因为slf4j-api是对应的接口,而实现就是logback-classic/logback-core
3. 为什么说logback-classic实现了slf4j呢?
可以看到引入logback-classic的时候,也会自动依赖slf4j-api(所以说,这里也实现了slf4j,可以直接使用呢)
4. logback-classic是先于slf4j实现的,为什么会实现这个呢?
是因为之前的版本logback-classic还没有实现slf4j。本质上严格意义上需要引入slf4j-api的,版本1.2.3之后加入了(包括之前)实现,所以支持了slf4j呢
早先上怎么支持slf4j呢?(slf4j是一个接口)
来源并整理出的下文,感谢free_coder:【java】20分钟搞清log4j/logback/log4j2/slf4j || 如何统一日志标准_哔哩哔哩_bilibili
注:下文的配置都是输出到控制台,目的是为了方便校验查看
1. log4j+slf4j-log4j12 ——》slf4j
<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- 为了使得log4j支持slf4j,所以刻意引入slf4j-log4j12 目的是为了基础库升级到slf4j标准--> <!-- <dependency>--> <!-- <groupId>org.slf4j</groupId>--> <!-- <artifactId>slf4j-log4j12</artifactId>--> <!-- <version>1.7.30</version>--> <!-- </dependency>--> </dependencies>
### 设置###
log4j.rootLogger = info,console
### 输出信息到控制抬 ###
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 = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %c:%m%n
#log4j.appender.console.layout.ConversionPattern = %c:%m%n
2. log4j2 + log4j-slf4j-impl ——》slf4j
<dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.6.1</version> </dependency> <!-- 为了使得log4j2支持slf4j,所以刻意引入log4j-slf4j-impl目的是为了基础库升级到slf4j标准--> <!-- <dependency>--> <!-- <groupId>org.apache.logging.log4j</groupId>--> <!-- <artifactId>log4j-slf4j-impl</artifactId>--> <!-- <version>2.9.0</version>--> <!-- </dependency>--> </dependencies>
### 设置###
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %c:%m%n
3. logback。 //logback默认已经实现了slf4j这个门面 【标准】
<dependencies> <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> </dependencies>
logback.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%p] %c:%m%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="console" />
</root>
</configuration>
总结:
logback | <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> | import org.slf4j.Logger; import org.slf4j.LoggerFactory; LoggerFactory.getLogger |
log4j | <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> | org.apache.log4j.Logger Logger.getLogger |
log4j2 | <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.6.1</version> </dependency> | org.apache.logging.log4j.LogManager; org.apache.logging.log4j.Logger; LogManager.getLogger |
0. 新工程pom使用本地工程生成的库
本地工程如下,可以通过mvn install的方式安装到本地项目中
新工程pom就可以使用了
当一个项目有多个依赖库,同时是不同日志系统实现,如果该项目里面没有指定配置文件,那么会使用原有库依赖的。。。会在各自的项目中进行查找(这种是无冲突的)
当然,如果该项目中有指定,那就会使用当前配置下的配置文件
代表存在多个multiple slf4j。最后选择了log4j实现的日志系统 。所以最后展示的时候会统一使用new 4j【可以看到,最后统一使用new 4j进行了所有日志的打印】
如何指定日志实现库?【如果系统只有一个实现了slf4j】
使用exclusion方式进行求解
也可使用不存在的依赖
PRO ——》A(log4j)
——》B(slf4j ——log4j2)
——》C(slf4j——logback)
正常如上是没有问题的。也不会冲突(exclusion适配后),那如何让A也满足slf4j的标准呢?也就是说如何让 没支持slf4j的满足slf4j呢?
需要如下:先排除掉log4j,同时强行使用log4j-over-slf4j
log4j2支持slf4j的使用方式
slf4j中的适配器与桥接是怎样工作的?
门面标准slf4j,全称是slf4j-api【门面的设计模式】
1. logback是通过接口实现slf4j-api
桥接:over(依赖使用的日志实现是log4j,当前工程想升级到slf4j,那么可以直接使用桥接)
原理:log4j-over-slf4j把log4j里面的类全部进行了重写(重写的含义是:保持package和类名完全一致,然后把类里面的东西修改了)
注:类名一致的话,会加载第一个。。。
注:maven依赖的前后顺序也很重要呢
所以有两种做法:1(pom中引入不存在的log4j)2(显式的把log4j-over-slf4j写在前面)
情景1。。。最终使用到的是log4j-over-slf4j
情景2。。。最终使用的Logger是log4j
上面两张图的效果一致