sl4j总结

sl4j简介

slf4j不是具体的日志解决方案,它只服务于各种各样的日志系统。

slf4j是门面模式的典型应用

 

日志门面 commons-logging,slf4j

日志实现 log4j,jdk-logging,logback,log4j2

 

 

门面模式

门面模式,其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。

门面模式的核心为Facade即门面对象,门面对象核心为几个点:

 

  • 知道所有子角色的功能和责任
  • 将客户端发来的请求委派到子系统中,没有实际业务逻辑
  • 不参与子系统内业务逻辑的实现

 

为什么使用sl4j

我们为什么要使用slf4j,举个例子:

 

我们自己的系统中使用了logback这个日志系统

我们的系统使用了A.jar,A.jar中使用的日志系统为log4j

我们的系统又使用了B.jar,B.jar中使用的日志系统为slf4j-simple

 

这样,我们的系统就不得不同时支持并维护logback、log4j、slf4j-simple三种日志框架,非常不便。

解决这个问题的方式就是引入一个适配层,由适配层决定使用哪一种日志系统,而调用端只需要做的事情就是打印日志而不需要关心如何打印日志,slf4j或者commons-logging就是这种适配层,slf4j是本文研究的对象。

slf4的作用

slf4j只是一个日志标准,并不是日志系统的具体实现。

slf4j只做两件事情:

  • 提供日志接口
  • 提供获取具体日志对象的方法

 

slf4j-simple、logback都是slf4j的具体实现,log4j并不直接实现slf4j,但是有专门的一层桥接slf4j-log4j12来实现slf4j。

 

sl4j和日志实现

slf4j不提供日志的具体实现,只有slf4j是无法打印日志的。

如果引入多个日志实现,如系统同时引入logback-classic、slf4j-simple、log4j

可以输出日志,但是会输出一些告警日志,提示我们同时引入了多个slf4j的实现,然后选择其中的一个作为我们使用的日志系统。

 

从例子我们可以得出一个重要的结论,即slf4j的作用:只要所有代码都使用门面对象slf4j,我们就不需要关心其具体实现,最终所有地方使用一种具体实现即可,更换、维护都非常方便。

sl4j使用

maven项目引入

pom文件加入依赖

<!-- log -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.25</version>
    <!-- <scope>test</scope> -->
</dependency>

加入日志配置文件到resources文件下:log4j.properties

log4j.rootLogger=CONSOLE,FILE
log4j.addivity.org.apache=true

# 应用于控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

# 每天新建日志
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=D:/log4j/log
log4j.appender.A1.Encoding=UTF-8
log4j.appender.A1.Threshold=DEBUG
log4j.appender.A1.DatePattern='.'yyyy-MM-dd
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L : %m%n

#应用于文件
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=E:/log4j/file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.Encoding=UTF-8
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

slf4j的用法就是常年不变的一句"Logger logger = LoggerFactory.getLogger(Object.class);"

 

使用方式 :

在系统开发中,统一按照slf4j的API进行开发,在部署时,选择不同的日志系统包,即可自动转换到不同的日志系统上。比如:选择JDK自带的日志系统,则只需要将slf4j-api-1.6.1.jar和slf4j-jdk14-1.6.1.jar放置到classpath中即可,如果中途无法忍受JDK自带的日志系统了,想换成log4j的日志系统,仅需要用slf4j-log4j12-1.6.1.jar替换slf4j- jdk14-1.6.1.jar即可(需要log4j的jar及配置文件log4j.properties文件),也可以使用slg4j提供的 simple log,slf4j-simple-1.6.1.jar替换slf4j-jdk14-1.6.1.jar。

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Sl4jTest {
	// 统一按照slf4j的API进行开
	Logger logger = LoggerFactory.getLogger(Sl4jTest.class);
	@Test
	public void testlog(){
		logger.info("logger");
	}
}

使用JDK自带的log输出

在classpath中加入slf4j-api-1.6.1.jar和slf4j-jdk14-1.6.1.jar两个包,然后运行方法,输出信息如下:

十一月 29, 2016 11:04:43 上午 Sl4jTest testlog
信息: logger

使用slg4j提供的simple log

 slf4j-simple-1.6.1.jar替换slf4j-jdk14-1.6.1.jar,选择使用slf4j提供的simple log,输出信息如下:

2 [main] INFO Sl4jTest - logger

log4j日志输出

用slf4j-log4j12-1.6.1.jar替换slf4j-simple-1.6.1.jar(记得classpath也需要增加log4j依赖jar包),同时增加一个log4j.properties文件

log4j依赖的jar:log4j-1.2.16.jar(核心包)

log4j.properties:

#将等级为INFO的日志信息输出到stdout和R这两个目的地
log4j.rootCategory=INFO, stdout , R 
#定义名为stdout的输出端是哪种类型
log4j.appender.stdout=org.apache.log4j.ConsoleAppender   
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout   
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n   
    
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender   
log4j.appender.R.File=D:\\Tomcat 5.5\\logs\\qc.log   
log4j.appender.R.layout=org.apache.log4j.PatternLayout   
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n   
   
log4j.logger.com.neusoft=DEBUG   
log4j.logger.com.opensymphony.oscache=ERROR   
log4j.logger.net.sf.navigator=ERROR   
log4j.logger.org.apache.commons=ERROR   
log4j.logger.org.apache.struts=WARN   
log4j.logger.org.displaytag=ERROR   
log4j.logger.org.springframework=DEBUG   
log4j.logger.com.ibatis.db=WARN   
log4j.logger.org.apache.velocity=FATAL   
   
log4j.logger.com.canoo.webtest=WARN   
   
log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN   
log4j.logger.org.hibernate=DEBUG   
log4j.logger.org.logicalcobwebs=WARN  

log4j.rootCategory=INFO, stdout , R

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
 
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\Tomcat 5.5\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n

log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL

log4j.logger.com.canoo.webtest=WARN

log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN

我们需要修改下方法,加载一下log4j.properties,如;

@Test
public void testlog(){
    System.setProperty("log4j.configuration","log4j.properties");//直接放在classpath下会自动加载,这里不进行加载也可以运行。
    logger.info("logger");
}

这样就可以以log4j的方式输出了。

[QC] INFO [main] Sl4jTest.testlog(12) | logger

格式化日志

SLF4J还提供了格式化日志的功能,如事例中的语句:

String s1 = "孙悟空";
String s2 = "贝吉塔";
String s3 = "悟吉塔";
logger.info("{}合体{}是{}", s1, s2,s3);
[QC] INFO [main] Sl4jTest.testlog(16) | 孙悟空合体贝吉塔是悟吉塔

(5)日志系统绑定原理

在应用中,通过LoggerFactory类的静态getLogger()获取logger。通过查看该类的代码可以看出,最终是通过StaticLoggerBinder.SINGLETON.getLoggerFactory()方法获取LoggerFactory然后,在通过该具体的LoggerFactory来获取logger的。类org.slf4j.impl.StaticLoggerBinder并不在 slf4j-api-1.6.1.jar包中,仔细查看每个与具体日志系统对应的jar包,就会发现,相应的jar包都有一个 org.slf4j.impl.StaticLoggerBinder的实现,不同的实现返回与该日志系统对应的LoggerFactory,因此就实现了所谓的静态绑定,达到只要选取不同jar包就能简单灵活配置的目的。

 

其他总结

日志输出规范

输出e的不需要{}

logger.error("助力发生错误:",e);
LOGGER.error("\"index={}, type={}\"的文档设置类型映射失败,请检查参数!", index, type);
LOG.error("Couldn't run collection notifications for {}", collection, e);
LOGGER.info("新增文档成功! index: {}, type: {}, id: {}", new Object[] {index , type, documentId});
logger.info("execute http request [{}], status code [{}]", requestBody, statusCode);
LOGGER.info("{} 索引删除成功!", index);

 

posted @ 2024-04-01 23:49  星光闪闪  阅读(149)  评论(0)    收藏  举报