概念
日志框架:是一种日志接口,不负责具体的日志输出形式(有点类似于JDBC),可以灵活的切换日志输出形式。常见的日志框架有slf4j、jcl,只提供Logger、LoggerFactory等接口
日志系统:是应用实际使用的日志工具,主要有log4j,jul,logback等。一般在程序中应该避免直接使用,可以保证程序具有一定的灵活性。
Logger:日志输出实例,包含Appender和Layout
Appender:日志输出目标,如控制台,文件,数据库等。多个Appender可以被关联到任何Logger上,所以可以到多个输出文件上记录相同的信息。
Layout:定义日志输出格式:时间戳、线程名称、日志级别、日志内容、对应输出该日志的类、对应输出该日志的方法、行号及MDC信息
Level : 日志级别,通过配置不同的日志界别来打印不同的日志信息。
历史
1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j。后来Log4j成为Apache基金会项目中的一员。
期间Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议sun引入Log4j到java的标准库中,但Sun拒绝了。
2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,log4j就已经成为一项成熟的技术,使得log4j在选择上占据了一定的优势。
接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是log4j,也可以是Java Util Logging。
后来(2006年),Ceki Gülcü不适应Apache的工作方式,离开了Apache。然后先后创建了slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架),他们并不属于Apache组织,slf4j用来取代common logging,而logback用来取代log4j。
log4j2 http://logging.apache.org/log4j/2.x/manual/index.html
现今,Java日志领域被划分为两大阵营:Commons Logging阵营和SLF4J阵营。Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,发现slf4j的发展趋势更好.
原理
slf4j运行的时候,会在classpath中寻找org.slf4j.impl.StaticLoggerBinder类(slf4j-api包本身是没有这个类的),slf4j-simple,slf4j-log4j12或logback-classic都包含这个类。
Demo
Log4j
public class Test {
private static Logger LOG = Logger.getLogger(Test.class);
public static void main(String[] args) {
LOG.debug("this is a debug message.");
LOG.info("this is a info message");
LOG.error("this is a error message");
}
}
// log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jakarta.apache.org/log4j/ ">
<appender name="PROJECT" class="org.apache.log4j.ConsoleAppender">
<param name="threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p %c{2} - %m%n"/>
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="PROJECT"/>
</root>
</log4j:configuration>
//Maven
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
jul
import java.util.logging.Logger;
public class Test {
public static void main(String[] args) {
Logger logger = Logger.getLogger("");
logger.info("this is a jul info message");
}
}
//maven自行搜索
jcl + Log4j
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Test {
private static Log LOG = LogFactory.getLog(Test.class);
public static void main(String[] args) {
LOG.debug("this is a debug message.");
LOG.info("this is a info message");
LOG.error("this is a error message");
}
}
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
</dependency>
</dependencies>
jcl + jul
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Test {
public static void main(String[] args) {
Log LOG = LogFactory.getLog(Test.class);
LOG.info("this is a jul info message");
}
}
//maven自行搜索
slf4j
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Test {
private static Logger LOG = LoggerFactory.getLogger(Test.class);
public static void main(String[] args) {
LOG.info("this is a sl4j info message");
}
}
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.6</version>
</dependency>
slf4j + logback
<!-- slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<!-- logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
slf4j+log4j
- slf4j-api
- slf4j-log4j12//将slf4j绑定到了log4j输出
- log4j
转换桥接
jcl转logback
如果应用的日志编码使用的是jcl接口,而想使用logback作为日志系统输出的话,则需要使用将jcl桥接到slf4j,然后再由slf4j+logback进行输出。解决方法是:
- 去掉commons-logging jar包(避免jar包冲突)
- 引入jcl-over-slf4j
- slf4j + logback 的依赖文件
log4j 转 logback
如果想把log4j接口编码的应用,使用logback来进行日志输出,那么需要log4j-over-slf4j这个包将log4j桥接到slf4j,然后使用slf4j+logback进行输出:
- 引入log4j-over-slf4j
- slf4j + logback 的依赖文件
jul 转logback
同理,如果需要将jul编码的应用转logback输出:
- 引入 jul-over-slf4j
- 使用slf4j + logback 的依赖文件
jcl+slf4j+log4j
这种情况下,应用日志代码使用commons-logging编码,同时将jcl桥接到了slf4j上,并使用log4j作为日志输出。与上文提到的jcl转logback类似,只是最后输出的方案是slf4j+log4j而不是slf4j+logback,所需要的jar包如下:
- jcl-over-slf4j
- slf4j-api
- slf4j-log4j12
- log4j