揭秘java日志系统

来源:互联网 发布:windows chakan elf 编辑:程序博客网 时间:2024/05/16 11:39

概念

日志框架:是一种日志接口,不负责具体的日志输出形式(有点类似于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-apislf4j-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





原创粉丝点击