1.log4j与slf4j的关系
SLF4J,即简单日志门面(Simple Logging Facade for Java)。从设计模式的角度考虑,它是用来在log和代码层之间起到门面的作用
。对用户来说只要使用slf4j提供的接口,即可隐藏日志的具体实现。这与jdbc和相似。使用jdbc也就避免了不同的具体数据库。使用了slf4j可以对客户端应用解耦。因为当我们在代码实现中引入log日志的时候,用的是接口,所以可以实时的更具情况来调换具体的日志实现类。这就是slf4j的作用。
SLF4J所提供的核心API是一些接口以及一个LoggerFactory的工厂类
。SLF4J提供了统一的记录日志的接口,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过具体日志系统的配置来实现,因此可以在应用中灵活切换日志系统。
gghjgjh
配置SLF4J是非常简单的一件事,只要将与你打算使用的日志系统对应的jar包加入到项目中,SLF4J就会自动选择使用你加入的日志系统。
2.类的基本继承结构
mavne配置
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<!-- slf4j-log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
一个简单的例子
package demos;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Author:王喜
* @Description :Slf4j 日志门面接口 Test
* @Date: 2018/4/19 0019 13:04
*/
public class Slf4jFacadeTest {
private final static Logger LOGGER = LoggerFactory.getLogger(Slf4jFacadeTest.class);
public static void main(String[] args) {
if(LOGGER.isDebugEnabled()){
LOGGER.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>slf4j-log4j debug message");
}
if(LOGGER.isInfoEnabled()){
LOGGER.info("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<slf4j-log4j info message");
}
if(LOGGER.isTraceEnabled()){
LOGGER.trace("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<slf4j-log4j trace message");
}
System.out.println(Slf4jFacadeTest.class);
System.out.println(Slf4jFacadeTest.class.getName());
}
}
运行结果如下。日志级别下面会有讲到。
"C:\Program Files\Java\jdk1.8.0_144\bin\java" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2017.1.2\lib\idea_rt.jar=60546:D:\Program Files\JetBrains\IntelliJ IDEA 2017.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar;E:\workSpaceJava\maven_demos\target\classes;E:\web-repository\org\slf4j\slf4j-api\1.7.12\slf4j-api-1.7.12.jar;E:\web-repository\org\slf4j\slf4j-log4j12\1.7.12\slf4j-log4j12-1.7.12.jar;E:\web-repository\log4j\log4j\1.2.17\log4j-1.2.17.jar" demos.Slf4jFacadeTest
2018-04-19 19:58:27 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>slf4j-log4j debug message
2018-04-19 19:58:27 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<slf4j-log4j info message
2018-04-19 19:58:27 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<slf4j-log4j trace message
class demos.Slf4jFacadeTest
demos.Slf4jFacadeTest
首先,Logger是slf4j包的接口,LoggerFactory是slf4j下面的类,而且在这个类中有这么一个static方法
public static ILoggerFactory getILoggerFactory() {
if(INITIALIZATION_STATE == 0) {
INITIALIZATION_STATE = 1;
performInitialization();
}
//初始化判断
switch(INITIALIZATION_STATE) {
case 1:
return TEMP_FACTORY;
case 2:
throw new IllegalStateException("org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
case 3:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case 4:
return NOP_FALLBACK_FACTORY;
default:
throw new IllegalStateException("Unreachable code");
}
}
那么这个工厂类的工厂方法的作用是什么呢?往下看:
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
if(DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
if(nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", new Object[]{logger.getName(), autoComputedCallingClass.getName()}));
Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
}
}
return logger;
}
这是LoggerFactory.getLogger()方法源码。获得日志工厂得到Logge。ILoggerFactory是slf4j下面的接口,并且接口下面只有一个方法。
package org.slf4j;
public interface ILoggerFactory {
Logger getLogger(String var1);
}
通过bind()方法可以绑定具体的日志系统。
主要是通过StaticLoggerBinder类进行绑定
package org.slf4j.impl;
import org.apache.log4j.Level;
import org.slf4j.ILoggerFactory;
import org.slf4j.helpers.Util;
import org.slf4j.spi.LoggerFactoryBinder;
public class StaticLoggerBinder implements LoggerFactoryBinder {
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
public static String REQUESTED_API_VERSION = "1.6.99";
private static final String loggerFactoryClassStr = Log4jLoggerFactory.class.getName();
private final ILoggerFactory loggerFactory = new Log4jLoggerFactory(); //在slf4j包下面的StaticLoggerBind类用Log4jLoggerFactory实现了ILoggerFactory接口
public static final StaticLoggerBinder getSingleton() {
return SINGLETON;
}
private StaticLoggerBinder() {
try {
Level var1 = Level.TRACE;
} catch (NoSuchFieldError var2) {
Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
}
}
//返回log4j对象
public ILoggerFactory getLoggerFactory() {
return this.loggerFactory;
}
public String getLoggerFactoryClassStr() {
return loggerFactoryClassStr;
}
}
具体的绑定方法源码可以查看https://my.oschina.net/xianggao/blog/519199
问题:getLog()为什么要传递一个类的字节码参数?
3.log4j的日志级别(由高到低)
- ERROR
- WARN
- INFO
- DEBUG
- TRACE
比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。
程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。
如果设置级别为INFO,则优先级高于等于INFO级别(如:INFO、WARN、
ERROR)的日志信息将可以被输出,小于该级别的如DEBUG将不会被输出。
一段简单的配置
log4j.rootLogger = trace, console
log4j.appender.console = org.apache.log4j.ConsoleAppender //打印到控制台上
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n