SLF4J LogBack

SLF4J LogBack初步认识

Commons-Logging + Log4J一直是Java日志的经典组合,不过后来由于Commos Logging中经常在服务器上遇到类加载ClassLoader问题,还有就logger.isDebugEnabled

()的问题,后来就有了SLF4J来取代Commons Logging,并且由于Log4J的性能问题,就使用了LogBack取代了Log4J.

SLF4J综述:类似Commons Logging通过LogFactory或SLF4J通过LoggerFactory得到命名的Logger实例,然后通过该Logger实例调用相应的方法打印日志,

然而不同于Commons Logging的动态绑定机制,SLF4J则采用了一种静态绑定的机制,即每个支持SLF4JLogging框架必须存在一个继承自

LoggerFactoryBinder接口的StaticLoggerBinder类,SLF4J包含一个LoggerFactoryBinder接口,每个支持SLF4J的Logging框架必须有一个

StaticLoggerBinder类,

LoggerFactory调用StaticLoggerBinder类中的getLoggerFactory()方法返回相应的ILoggerFactory实例,最后通过ILoggerFactory实例获取Logger

实例:

public interface LoggerFactoryBinder {

 public ILoggerFactory getLoggerFactory();

   public String getLoggerFactoryClassStr();

}

public interface ILoggerFactory {

 public Logger getLogger(String name);

}

public interface Logger {

   public String getName();

}

也正是因为这个设计,SLF4J在classpath下只支持一个桥接包(slf4j-simple-<version>.jar、slf4j-log4j12-<version>.jar、slf4j-jdk14-<version>.jar、
logback-classic-<version>.jar等)。如果在classpath下存在多个桥接包,则具体用哪个就要看这几个桥接包的加载顺序了,实际中会使用先加载的桥接包。
同时SLF4J会打印使用哪个桥接包,哪些桥接包没有使用。这种静态绑定的设计比Commons Logging在可扩展性上具有更加灵活的机制,对“可插拔”的支持也
更加高效。如果要支持一个新的Logging框架,Commons Logging需要通过在属性配置文件,或虚拟机属性中配置支持这个新的Logging框架的实现类(实现Log接
口),添加到org.apache.commons.logging包下,而SLF4J则只需要编写以下五个相应的类:
1.   实现Logger接口的类
2.   实现ILoggerFactory接口的类
3.   实现LoggerFactoryBinder接口的类StaticLoggerBinder类(必须使用StaticLoggerBinder类名),并且存在一个静态的getSingleton()方法。
4.   实现MarkerFactoryBinder类的StaticMarkerBinder类(必须使用StaticMarkerBinder类名),可选。一般也会存在一个静态的SINGLETON字段,不过也
是可选的。
5.   实现StaticMDCBinder类,可选。一般也会存在一个静态的SINGLETON字段,也可选。
SLF4J实现实例,SLF4J API与SLF4J Simple
由于采用了静态绑定的方式,而不是像Commons Logging中的动态绑定,SLF4J中LoggerFactory的实现要比Commons Logging中LogFactory的实现要简单
的多。即LoggerFactory调用getILoggerFactory()方法,该方法会初始化LoggerFactory,即通过在bind()方法中加载classpath中的StaticLoggerBinder
类,并根据加载结果设置当前LoggerFactory的初始化状态,从而在getILoggerFactory()方法中通过当前LoggerFactory的状态判断返回的ILoggerFactory
实例。
即bind()方法使用调用StaticLoggerBinder.getSingleton()方法来实现绑定,如果该方法调用成功,则将初始化状态设置为
SUCCESSFUL_INITIALIZATION,如果因为没有找到StaticLoggerBinder类而引起的异常,则将状态设置为NOP_FALLBACK_INITIALIZATION,否则将状
态设置为FAILED_INITIALIZATION,并抛出异常。如果在当前classpath下存在多个桥接jar包,在实现绑定前后会记录存在哪些可使用的桥接jar包,绑定了那
个ILoggerFactory类。
在bind()返回后,performInitialization()方法会再做一些版本检查,即StaticLoggerBinder可以定义一个静态的REQUESTED_API_VERSION字段,表示该
StaticLoggerBinder支持的SLF4J版本,如果该版本不在LoggerFactory定义的兼容版本列表中(API_COMPATIBILITY_LIST),SLF4J会打印警告信息,并列
出当前LoggerFactory兼容的版本列表。而后在getILoggerFactory()方法中会根据当前LoggerFactory的初始化状态来决定返回的ILoggerFactory实例:
当LoggerFactory成功初始化,则返回绑定的StaticLoggerBinder中的ILoggerFactory实例;如果为NOP_FALLBACK_INITIALIZATION(没有找到桥接
jar),则返回NOPLoggerFactory,它返回一个单例的NOPLogger实例,该类不会打印任何日志;如果初始化状态为FAILED_INITIALIZATION,抛出
IllegalStateException异常;如果初始化状态为ONGOING_INITIALIZATION,则返回SubstituteLoggerFactory类实例,该状态发生在一个线程正在初始化
LoggerFactory,而另一个线程已经开始请求获取ILoggerFactory实例,SubstituteLoggerFactory会记录当前请求的Logger名称,然后返回NOPLogger实例。
所有这些在LoggerFactory初始化时被忽略的Logger Name会在LoggerFactory初始化成功以后被report出来(在System.err流中打印出来)。
SLF4J实现了一个简单的日志系统:slf4j-simple-<version>.jar。要实现一个兼容SLF4J的日志系统,基本的需要三个类:
1.   StaticLoggerBinder类,实现LoggerFactoryBinder接口。它实现单例模式,存在getSingleton()静态方法,存在REQUESTED_API_VERION静态字段,
不用final避免编译器的优化(将值直接写入源码中,而不使用该字段)。返回的ILoggerFactory实例也一直使用同一个实例(SimpleLoggerFactory)
2.   实现ILoggerFactory接口的SimpleLoggerFactory。它有一个loggerMap字段缓存所有之前创建的SimpleLogger实例,以Logger Name为key,实现每个
相同名字的Logger实例只需要创建一次
3.   SimpleLogger类,实现Logger接口。SimpleLogger继承自MarkerIgnoringBase类,该基类忽略所有存在Marker参数的日志打印方法。SimpleLogger将日
志级别分成五个级别:TRACE、DEBUG、INFO、WARN、ERROR,这些级别对应的INT值一次增大。SimpleLogger还支持对simplelogger.properties配置文
件的解析,它支持的key值有:
org.slf4j.simpleLogger.defaultLogLevel
org.slf4j.simpleLogger.showDateTime
org.slf4j.simpleLogger.dateTimeFormat
org.slf4j.simpleLogger.showThreadName
org.slf4j.simpleLogger.showLogName
org.slf4j.simpleLogger.showShortLogName
org.slf4j.simpleLogger.logFile
org.slf4j.simpleLogger.levelInBrackets
org.slf4j.simpleLogger.warnLevelString(warn提示字符,默认“WARN”
同时SimpleLogger还支持为特定的Logger Name前缀(以”.”作为分隔符)指定level:
org.slf4j.simpleLogger.log.<logNamePrefix>
并且所有这些key都可以定义在系统属性中。
SimpleLogger类的实现主要分成两步:初始化和打印日志:
a.   初始化
加载配置文件,使用加载的配置文件初始化类字段,即对应以上simplelogger.properties支持的key;保存当前Logger Name;计算当前Logger实际的Level
即如果没有为该Logger Name(或其以“.”分隔的前缀)配置特定的Level,则使用默认配置的Level,否则,使用具体的日志,并保存计算出的Level值,如
没有找到Level配置,使用默认值INFO。
b.   打印日志
对使用format字符串的日志打印方法,调用formatAndLog()方法,其内部先调用MessageFormatter.arrayFormat()方法,然后调用log()方法实现打印
息。log()方法的实现只是根据解析出来的配置信息,判断哪些信息需要打印,则打印这些信息,实现比较简单,不再赘述。
 
并不是所有Logging系统支持这些功能,对它们支持最全面的当属LogBack框架了,因而这些类将会在介绍LogBack框架时一起讨论。在slf4j-simple
<version>.jar,StaticMarkerBinder返回BasicMarkerFactory实例,而StaticMDCBinder返回NOPMDCAdapter实例。
 
SLF4J支持上层是SLF4J框架,底层还是通过Commons Logging的动态查找机制,只要将slf4j-jcl-<version>.jar包加入classpath中即可(当然slf4j-api
<version>.jar也要存在)
 
另外SLF4J还支持上层是Commons Logging,而底层交给SLF4J提供的静态绑定机制查找真正的日志实现框架,只需要将jcl-over-slf4j-<version>.jar包加入
到classpath中,此时不需要引入commons-logging-<version>.jar包。它的实现只是重写了Commons Logging框架,并在LogFactory中只使用SLF4JLog
或SLF4JLocationAwareLog类
不过需要注意,slf4j-jcl-<version>.jar包和jcl-over-slf4j-<version>.jar两个包不能同时出现在classpath中,不然会引起循环调用而导致栈溢出的问题,
而slf4j-jcl-<version>.jar在初始化时就会检测这个限制,并抛出异常。
最后SLF4J还支持Log4J作为上层,而底层交给SLF4J静态绑定要真正实现日志打印的框架,可以将log4j-over-slf4j-<version>.jar包加入到classpath中。其
实现也类似jcl-over-slf4j-<version>.jar的实现,重写大部分的Log4J的内部逻辑,而在Logger类实现中,将真正的日志打印逻辑代理给SLF4J的
LoggerFactory。
当项目中有人使用Commons Logging,也有人使用Log4J的时候,Log比较混乱,此时SLF4J可以满足这种情况的迁移,即可以将log4j-over-slf4j-
<version>.jar和jcl-over-slf4j-<version>.jar包同时放到classpath下,将原来的common-logging和log4J的jar包进行删除。
slf4j会根据classpath中存在的这些jar包来slf4j-simple-<version>.jar、slf4j-log4j12-<version>.jar、slf4j-jdk14-<version>.jar、logback-classic-<version>.jar等桥接包来决定使用的日志实现库
若需要将使用了其它logging APIs的第三方类库或已有代码的日志调用迁移到SLF4J,需要替换下面的jar:
jcl-over-slf4j.jar  替换apache commons logging。
log4j-over-slf4j.jar  替换log4j。原有的log4j.properites将失效,需要转换为logback.xml,logback网站上有提供转换器:
http://logback.qos.ch/translator/(将log4j.properties转换成logback.xml)
jul-to-slf4j.jar  替换jdk logging。需要在程序开始时调用SLF4JBridgeHandler.install()来注册listener。




桥接器的执行过程:jcl-over-slf4j.jar --- (redirect) ---> SLF4j ---> slf4j-log4j12-version.jar ---> log4j.jar ---> 输出日志

jcl-over-slf4j-1.5.2.jar和log4j-over-slf4j-1.5.2.jar可以替换掉commons-logging和log4J,接着交由底层的slf4j-api-1.6.1.jar去处理,并且原来创建Logger地方,不用修改,

接着使用logback-core-1.0.13.jar和logback-classic-1.0.13.jar去使用logback来处理具体的日志输出,logback框架的初始化是由ContextInitializer来负责加载完成的,

而实际进行配置的是GenericConfigurator类,它调用SaxEventRecorder类来负责读取logback.xml文件,然后由Interpreter类来进行解析,而最后真正的初始化工作,是由一系

列Action组件来完成。

它在提供LoggerContext之前,就对LoggerContext进行初始化,初始化的入口方法,即是ContextInitializer类的autoConfig()方法

这里首先调用findURLOfDefaultConfigurationFile()方法,来寻找一个配置文件,一般就是logback.xml文件,如果没有找到,则用BasicConfigurator来进行默认配置,否则就

调用configureByResource()方法,根据配置文件进行配置,logback首先查找logback.groovy文件,没有则依次查找logback-test.xml文件,logback.xml文件,没有找到的话

则使用默认配置打印到控制台。






  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot应用程序中,集成SLF4JLogback只需要几个简单的步骤: 1. 添加依赖 在pom.xml文件中添加以下依赖: ``` <!-- SLF4J API --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <!-- Logback Classic Module --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> ``` 2. 配置Logback 在src/main/resources目录下创建logback.xml文件,并添加以下内容: ``` <?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="INFO"> <appender-ref ref="STDOUT" /> </root> </configuration> ``` 这个配置文件中定义了一个名为“STDOUT”的控制台输出的Appender,输出格式为时间戳、线程名称、日志级别、Logger名称和日志信息。根Logger的日志级别设置为INFO,表示只输出INFO及以上级别的日志。 3. 使用SLF4J 在应用程序中使用SLF4J进行日志记录,例如: ``` import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MyService { private static final Logger logger = LoggerFactory.getLogger(MyService.class); public void doSomething() { logger.info("Doing something..."); } } ``` 这个示例中,通过调用LoggerFactory.getLogger()方法获取Logger实例,并使用Logger实例记录日志。 以上就是在Spring Boot应用程序中集成SLF4JLogback的简单步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值