1、概述


SLF4J(Simple logging facade for Java)不是一个真正的日志实现,而是一个抽象层,相当于一个统一的接口,它允许你在后台使用任意一个日志类库。我们使用SLF4J提供的接口进行日志记录的编程,当我们需要更换具体的日志实现时,可以不需要更改日志的代码,只要加入响应的jar包和配置就可以切换实现。本文使用log4j+slf4j进行配置。


2、maven配置


       在maven配置文件中加入以下依赖jar包。


[html]  view plain  copy


1. <dependencies>  
2. <dependency>  
3. <groupId>org.apache.logging.log4j</groupId>  
4. <artifactId>log4j-core</artifactId>  
5. <version>2.6.2</version>  
6. </dependency>  
7.   
8. <dependency>  
9. <groupId>org.apache.logging.log4j</groupId>  
10. <artifactId>log4j-api</artifactId>  
11. <version>2.6.2</version>  
12. </dependency>  
13.   
14. <dependency>  
15. <groupId>org.apache.logging.log4j</groupId>  
16. <artifactId>log4j-slf4j-impl</artifactId>  
17. <version>2.6.2</version>  
18. </dependency>  
19.   
20. <dependency>  
21. <groupId>org.slf4j</groupId>  
22. <artifactId>slf4j-api</artifactId>  
23. <version>1.7.21</version>  
24. </dependency>  
25. </dependencies>



3、log4j2配置


        Configuration节点中有两个属性,status表示log4j自己的日志打印级别,如果设置为TRACE,可以看到控制台输出log4j本身的日志信息。monitorInterval表示每隔多少秒自动检测配置文件的更改,单位是秒,最小的时间间隔是5秒。


        Appenders中有一个Appender,表示从控制台输出,name属性为每个Appender的唯一标识。PatternLayout定义了我们日志输出格式。


%d{yyyy-MM-dd HH:mm:ss.SSS}:表示输出的日期格式


%t:表示当前线程名称


%-5level:输出日志级别,-5表示左对齐并且固定输出5个字符


%l:输出语句所在的包名、类名、函数名、行数


%msg:输出日志的内容


%n:换行


%F 输出所在的类文件名

%L 输出行号

%M 输出所在方法名

[html]  view plain  copy

1. <?xml version="1.0" encoding="UTF-8"?>  
2. <Configuration status="WARN" monitorInterval="30">  
3. <Appenders>  
4. <Console name="Console" target="SYSTEM_OUT">  
5. <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>  
6. </Console>  
7. </Appenders>  
8. <Loggers>  
9. <Root level="trace">  
10. <AppenderRef ref="Console"/>  
11. </Root>  
12. </Loggers>  
13. </Configuration>

[java]  view plain  copy


1. import org.slf4j.Logger;  
2. import org.slf4j.LoggerFactory;  
3.   
4. public class Learning1 {  
5. private static final Logger LOGGER = LoggerFactory.getLogger(Learning1.class);  
6.   
7. public static void main(String[] args) {  
8. "learning1 log4j trace");  
9. "learning1 log4j debug");  
10. "learning1 log4j info");  
11. "learning1 log4j warn");  
12. "learning1 log4j error");  
13.     }  
14. }


[html]  view plain  copy



1. 2016-11-26 20:24:17.392 [main] TRACE edu.fjnu.log4j.learning.Learning1.main(Learning1.java:13) - learning1 log4j trace  
2. 2016-11-26 20:24:17.395 [main] DEBUG edu.fjnu.log4j.learning.Learning1.main(Learning1.java:14) - learning1 log4j debug  
3. 2016-11-26 20:24:17.395 [main] INFO  edu.fjnu.log4j.learning.Learning1.main(Learning1.java:15) - learning1 log4j info  
4. 2016-11-26 20:24:17.395 [main] WARN  edu.fjnu.log4j.learning.Learning1.main(Learning1.java:16) - learning1 log4j warn  
5. 2016-11-26 20:24:17.395 [main] ERROR edu.fjnu.log4j.learning.Learning1.main(Learning1.java:17) - learning1 log4j error



4、将日志输出到文件


        如下配置了一个名为RollingFile的Appenders,将日志输出到指定的文件中。fiileName表示日志的位置和文件名,filePattern表示当条件满足时,文件移动和重命名的规则。TimeBasedTriggeringPolicy需要和filePattern配套使用,由于filePattern配置的时间最小粒度是dd天,所以表示每一天新建一个文件保存日志。SizeBasedTriggeringPolicy表示当文件大小大于指定size时,生成新的文件保存日志。


        我们自定义了一个Logger,引用RollingFile这个日志适配器,当我们使用myLearningLog这个Logger来记录日志时,日志信息就会输出到文件中保存。

[html]  view plain  copy




    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <!-- staus:表示log4j自己的日志打印级别, 设置为TRACE可以看到控制台输出log4j的TRACE,DEBUG等信息-->  
    3. <!-- monitorInterval:单位是秒,表示每个多少秒自动检测配置文件的更改,最小的时间间隔为5秒-->  
    4. <Configuration status="WARN" monitorInterval="30">  
    5. <Appenders>  
    6. <Console name="Console" target="SYSTEM_OUT">  
    7. <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %l - %msg%n"/>  
    8. </Console>  
    9.   
    10. <RollingFile name="RollingFile" fileName="D:/logs/app.log"  
    11. filePattern="D:/logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log">  
    12. <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %l - %msg%n">  
    13. </PatternLayout>  
    14. <Policies>  
    15. <TimeBasedTriggeringPolicy interval="1"/>  
    16. <SizeBasedTriggeringPolicy size="250 MB"/>  
    17. </Policies>  
    18. </RollingFile>  
    19. </Appenders>  
    20. <Loggers>  
    21. <Logger name="myLearningLog" level="trace" additivity="false">  
    22. <AppenderRef ref="RollingFile"/>  
    23. </Logger>  
    24. <Root level="trace">  
    25. <AppenderRef ref="Console"/>  
    26. </Root>  
    27. </Loggers>  
    28. </Configuration>



            下面的代码使用自定义的Logger作为日志记录器。当运行下面代码时可以发现,在D:/logs下面生成了一个app.log文件用于保存日志。


    [java]  view plain  copy

    1. import org.slf4j.Logger;  
    2. import org.slf4j.LoggerFactory;  
    3.   
    4. public class Learning2 {  
    5. private static final Logger LOGGER = LoggerFactory.getLogger("myLearningLog");  
    6.   
    7. public static void main(String[] args) {  
    8. "learning2 log4j trace");  
    9. "learning2 log4j debug");  
    10. "learning2 log4j info");  
    11. "learning2 log4j warn");  
    12. "learning2 log4j error");  
    13.     }  
    14. }



    5、ThreadContext



            ThreadContext类似于log4j1中的MDC,可以用于存放当前线程的上下文信息,他是每个线程持有一份,不相互影响。我们可以使用%X{key}的方式,取出在ThreadContext中存放的值,与日志一起输出。如下PatternLayou中的%X{name}和%X{age}。


    [html]  view plain  copy


      1. <Configuration status="WARN" monitorInterval="30">  
      2. <Appenders>  
      3. <Console name="Console" target="SYSTEM_OUT">  
      4. <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %l - %X{name} - %X{age} - %msg%n"/>  
      5. </Console>  
      6. </Appenders>  
      7. <Loggers>  
      8. <Root level="trace">  
      9. <AppenderRef ref="Console"/>  
      10. </Root>  
      11. </Loggers>  
      12. </Configuration>



              在程序中通过ThreadContext中的put方法把我们需要保存的信息通过key-value的形式放进去,有点类似map的操作。需要注意的是,如果使用import org.slf4j.MDC包下的MDC存放数据,对log4j2是不可用的,在输出日志时就无法取到值,这是因为slf4j的MDC底层依赖是log4j1。



      [java]  view plain  copy



      1. import org.apache.logging.log4j.ThreadContext;  
      2. import org.slf4j.Logger;  
      3. import org.slf4j.LoggerFactory;  
      4.   
      5. public class Learning3 {  
      6. private static final Logger LOGGER = LoggerFactory.getLogger(Learning3.class);  
      7.   
      8. public static void main(String[] args) {  
      9. "name", "xiaoming");  
      10. "age", "18");  
      11.   
      12. "Learning3 log4j trace");  
      13. "Learning3 log4j debug");  
      14. "Learning3 log4j info");  
      15. "Learning3 log4j warn");  
      16. "Learning3 log4j error");  
      17.   
      18. "name") + "-" + ThreadContext.get("age"));  
      19.     }  
      20. }


              以下是输出的结果,可以到我们通过ThreadContext中的put方法存放的数据,被一起输出来。

      [html]  view plain  copy




      1. 2016-11-27 13:22:52.101 [main] TRACE edu.fjnu.log4j.learning.Learning3.main(Learning3.java:17) - xiaoming - 18 - Learning3 log4j trace  
      2. 2016-11-27 13:22:52.104 [main] DEBUG edu.fjnu.log4j.learning.Learning3.main(Learning3.java:18) - xiaoming - 18 - Learning3 log4j debug  
      3. 2016-11-27 13:22:52.104 [main] INFO  edu.fjnu.log4j.learning.Learning3.main(Learning3.java:19) - xiaoming - 18 - Learning3 log4j info  
      4. 2016-11-27 13:22:52.104 [main] WARN  edu.fjnu.log4j.learning.Learning3.main(Learning3.java:20) - xiaoming - 18 - Learning3 log4j warn  
      5. 2016-11-27 13:22:52.105 [main] ERROR edu.fjnu.log4j.learning.Learning3.main(Learning3.java:21) - xiaoming - 18 - Learning3 log4j error  
      6. xiaoming-18