`

java的log框架全介绍

阅读更多

1.本篇不是什么?

不会告诉你应用系统为什么要引入日志框架?
不会告诉你系统中什么样的异常及错误信息应该记录日志?
不会告诉你怎么可以高效的记录准确(能清晰的反应系统异常或业务异常)的日志?
当然也不会告诉你记录日志的n最佳实践,这些会在后一篇文章中详细介绍的.....
  2.java中主要的日志框架有哪些?
 java.util.Logging(JUL)

Java Logging API是sun公司于2002年5月正式发布的。它是自J2SE 1.4版本开始提供的一个新的应用程序接口。它能够很方便地控制和输出日志信息到文件,控制台或其它用户定义的地方,如数据库,电子邮件等。所以它是为最 终用户,系统管理员,软件服务工程师和开发人员提供的一种捕捉安全漏洞,检查配置正确性,跟踪调查系统运行瓶颈和调查系统运行错误的工具。 Java Logging API提供了七个级别用来控制输出。从高到底分别是:finest,finer,fine,config,info,warning,server

 

Log4j
Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;用户也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,用户能够更加细致地控制日志的生成过程。这些可以通过一个 配置文件来灵活地进行配置,而不需要修改程序代码。配置文件log4j.properties or log4j.xml,Logger的由低到高级别如下: ALL<DEBUG<INFO<WARN<ERROR<FATAL<OFF 

LOGBack 

Logback是由log4j创始人设计的又一个开源日记组件。logback当前分成三个模块:logback-core,logback- classic和logback-access。logback-core是其它两个模块的基础模块。logback-classic是log4j的一个 改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日记系统如log4j或JDK14 Logging。logback-access访问模块与Servlet容器集成提供通过Http来访问日记的功能。配置文件logback.xml。

 
以上都是日志的具体实现方式,我们编写代码的时候一般都不会是直接和这些API交互,而是与下面两个日志的接口(门面)库打交道。
 Apache Common-Logging (JCL) 
目前广泛使用的Java日志门面库。通过动态查找的机制(后面有代码介绍),在程序运行时自动找出真正使用的日志库。但由于它使用了ClassLoader寻找和载入底层的日志库, 导致了象OSGI这样的框架无法正常工作,由于其不同的插件使用自己的ClassLoader。 OSGI的这种机制保证了插件互相独立,然而却使Apache Common-Logging无法工作
 SLF4J 

简单日记门面(Facade)SLF4J是为各种loging APIs提供一个简单统一的接口,从而使得最终用户能够在部署的时候配置自己希望的loging APIs实现。 Logging API实现既可以选择直接实现SLF4J接的loging APIs如: NLOG4J、SimpleLogger。也可以通过SLF4J提供的API实现来开发相应的适配器如Log4jLoggerAdapter、JDK14LoggerAdapter。 

 他们之间的相互比较:

Log4j vs. java.util.Logging

从JDK 1.4.0开始,引入了java.util.logging包。虽然Log4J小组曾竭力游说JCP(Java Community Process)采用Log4J作为JDK 1.4的“标准”日志API,虽然最终因Sun的日志API规范的负责人Graham Hamilton的一句“Merlin的开发已经到了最后阶段,这时不允许再对主要API做出改变”而没有被采纳,但Log4J还是对新的日志API产生 了重要影响。那么,我们到底应该采用Log4J还是java.util.logging包呢?下面仅对两者做一简单的比较。

  1. Log4J更加成熟,从1999年10月开始至今已经有3年的时间,并且已经在许多项目中有着成熟的应用。而JDK中的logging包是在1.4之后才 引入的,并且不能运行于JDK 1.3之前的版本。Log4J则可以良好地运行于JDK 1.1之后的所有版本。

  2. Log4J已经被移植到多种环境下,包括log4c(C)、log4cpp(C++)、log4perl(Perl)、log4net(.net)等。在这些环境下,可以感受到几乎一致的配置和使用方式。这是JDK中的logging API所不能比拟的。

  3. Log4J还具有更加强力的格式化系统,可以使记录输出时实现简单的模式。但是,它不会增加类而导致格式化工具的扩展。众多的附加程序和处理器使得Log4J数据包成为一个绝佳的选择,所有你所需要的都可能加以实现。
  4. Log4J在性能上做了最大的优化。Logging API对于简单的使用是足够的,但它缺少了许多Log4J所具有的功能。所以,如果你需要一个强力的logging机制,就应坚持使用Log4J;而如果只是需要一些简单的控制或文件记录,那么可以使用已经内建在JDK之中的logging API。

虽然Log4J和JDK logging API是一种竞争关系,但在logging API还在JCP中讨论(JSR47)时,两者之间就已经开始相互影响了。
 Log4J vs. LOGBack
LOGBack作为一个通用可靠、快速灵活的日志框架,将作为Log4j的替代和SLF4J组成新的日志系统的完整实现。LOGBack声称具有极佳的性能,“ 某些关键操作,比如判定是否记录一条日志语句的操作,其性能得到了显著的提高。这个操作在LogBack中需要3纳秒,而在Log4J中则需要30纳秒。 LogBack创建记录器(logger)的速度也更快:13微秒,而在Log4J中需要23微秒。更重要的是,它获取已存在的记录器只需94纳秒,而 Log4J需要2234纳秒,时间减少到了1/23。跟JUL相比的性能提高也是显著的”。
另外,LOGBack的所有文档是全面免费提供的,不象Log4J那样只提供部分免费文档而需要用户去购买付费文档。
 SLF4J vs. Apache Common-Logging 
SLF4J库类似于Apache Common-Logging。但是,他在编译时静态绑定真正的Log库。使用SLF4J时,如果你需要使用某一种日志实现,那么你必须选择正确的SLF4J的jar包的集合。 如此便可以在OSGI中使用了。
另外,SLF4J 支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)。拼装消息被推迟到了它能够确定是不是要显示这条消息的时候,但是获取参数的代价并没有幸免。同时,日志中的参数若超过三个,则需要将参数以数组的形式传入,如:现在,Hibernate、Jetty、Spring-OSGi、Wicket和MINA等项目都已经迁移到了SLF4J,由此可见SLF4J的影响力不可忽视。
 
如果在单纯的logging环境中,使用SLF4J意义不大。如果想在各种logger API中切换,SELF4J是理想选择,另外在新的项目中,使用SLF4J+Logback是比较好的日志框架选型
 
 
3.在开发的时候如何组织这些日志框架为我所用?
 
下面这个是比较经典的组合,也是比较趋于理想化的,实际项目中可能会复杂一些。
 

日志组合

JCL+Log4j

SLF4J+Logback

优点

l使用的成熟

l案例丰富

l越来越多选择其作为日志方案,如Hibernate、iBatis

l日志性能高,支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)

缺点

l不再被维护

l不适用OSGi开发

l日志记录性能不高

lLogback作为Log4j的继任者

lLogback兼容Log4j,但提供更多的扩展

目前比较推荐的是后一种,但是老的项目基本上都是前一种。对于后一种组合,如果引用第三方类库时,第三方类库使用了JUL,JCL或者log4j,则需要引入对应的jul-to-slf4j.jar,jcl-over-slf4j.jar,log4j-over-slf4j.jar进行适配,为什么要引入这些,后面后代码说明。下面上一张神图,看过之后,就会明白我写的文字多苍白。


 
4.JCL日志门面动态查找日志框架的源码如下:
 static {
 
        // Is Log4J Available?
        try {
            if (null != Class.forName("org.apache.log4j.Logger")) {
                log4jIsAvailable = true;
            } else {
                log4jIsAvailable = false;
            }
        } catch (Throwable t) {
            log4jIsAvailable = false;
        }
 
        // Is JDK 1.4 Logging Available?
        try {
            if ((null != Class.forName("java.util.logging.Logger")) &&
                (null != Class.forName("org.apache.commons.logging.impl.Jdk14Logger"))) {
                jdk14IsAvailable = true;
            } else {
                jdk14IsAvailable = false;
            }
        } catch (Throwable t) {
            jdk14IsAvailable = false;
        }
 
        // Set the default Log implementation
        String name = null;
        try {
            name = System.getProperty("org.apache.commons.logging.log");
            if (name == null) {
                name = System.getProperty("org.apache.commons.logging.Log");
            }
        } catch (Throwable t) {
        }
        if (name != null) {
            try {
                setLogImplementation(name);
            } catch (Throwable t) {
                try {
                    setLogImplementation
                            ("org.apache.commons.logging.impl.NoOpLog");
                } catch (Throwable u) {
                    ;
                }
            }
        } else {
            try {
                if (log4jIsAvailable) {
                    setLogImplementation
                            ("org.apache.commons.logging.impl.Log4JLogger");
                } else if (jdk14IsAvailable) {
                    setLogImplementation
                            ("org.apache.commons.logging.impl.Jdk14Logger");
                } else {
                    setLogImplementation
                            ("org.apache.commons.logging.impl.NoOpLog");
                }
            } catch (Throwable t) {
                try {
                    setLogImplementation
                            ("org.apache.commons.logging.impl.NoOpLog");
                } catch (Throwable u) {
                    ;
                }
            }
        }
 
    }
 默认会先找Log4j,其次是JUL再次是JCL自己的,不过此时没有任何操作。该类的源码放在https://gist.github.com/yongchun/7595536
5.日志适配代码分析
logback日志框架完全实现了slf4j,而其他的日志框架JUL,log4j(完全实现了JCL)则不是的。那么对于抽象的slf4j日志门面要想使用这些日志框架就需要做些适配。
下面以日志的一个级别warn,说明其在各个日志框架中是怎样定义和实现的。
 
JCL中,定义的接口为
org.apache.commons.logging.Log

 public void warn(Object message);

 public void warn(Object message, Throwable t);
 其自身的实现为:
  public void warn(Object message) {
        getLogger().log(FQCN, Priority.WARN, message, null );
    }

    public void warn(Object message, Throwable t) {
        getLogger().log(FQCN, Priority.WARN, message, t );
    }

 log4j对应的实现为:
org.apache.log4j.Logger
 public
  void warn(Object message) {
    if(repository.isDisabled( Level.WARN_INT))
      return;

    if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel()))
      forcedLog(FQCN, Level.WARN, message, null);
  }


  public
  void warn(Object message, Throwable t) {
    if(repository.isDisabled(Level.WARN_INT))
      return;
    if(Level.WARN.isGreaterOrEqual(this.getEffectiveLevel()))
      forcedLog(FQCN, Level.WARN, message, t);
  }
}
 
其中JCL里的 org.apache.commons.logging.Log.JDK14Logger将JUL的日志级别进行了转换,使其对应到JCL的日志级别。使用JCL可以天然的使用JUL和log4j,因为他们的方法签名是一样的,完全是接口和接口对应的实现嘛。
 
而SLF4J,定义的接口为
 
 public void warn(String msg);

  public void warn(String format, Object arg);

  public void warn(String format, Object... arguments);

  public void warn(String format, Object arg1, Object arg2);

   public void warn (String msg, Throwable t);

 

logback日志框架的实现

 

 public void warn (String msg) {
    filterAndLog_0_Or3Plus(FQCN, null, Level. WARN, msg, null, null );
  }

  public void warn(String msg, Throwable t) {
    filterAndLog_0_Or3Plus(FQCN, null, Level. WARN, msg, null, t);
  }

  public void warn(String format, Object arg) {
    filterAndLog_1(FQCN, null, Level. WARN, format, arg, null);
  }

  public void warn(String format, Object arg1, Object arg2) {
    filterAndLog_2(FQCN, null, Level. WARN, format, arg1, arg2, null);
  }

  public void warn(String format, Object[] argArray) {
    filterAndLog_0_Or3Plus(FQCN, null, Level. WARN, format, argArray, null);
  }

  public void warn(Marker marker, String msg) {
    filterAndLog_0_Or3Plus(FQCN, marker, Level. WARN, msg, null, null );
  }

  public void warn(Marker marker, String format, Object arg) {
    filterAndLog_1(FQCN, marker, Level. WARN, format, arg, null);
  }

  public void warn(Marker marker, String format, Object[] argArray) {
    filterAndLog_0_Or3Plus(FQCN, marker, Level. WARN, format, argArray, null);
  }

  public void warn(Marker marker, String format, Object arg1, Object arg2) {
    filterAndLog_2(FQCN, marker, Level. WARN, format, arg1, arg2, null);
  }

  public void warn(Marker marker, String msg, Throwable t) {
    filterAndLog_0_Or3Plus(FQCN, marker, Level. WARN, msg, null, t);
  }

 

所以slf4j和logback是一套的,是接口和接口实现的关系。

再看下JCL-->slf4j  的转换 jcl-over-slf4j.jar

 

 public void warn(Object message) {
        differentiatedLog(null, CATEGORY_FQCN, LocationAwareLogger.WARN_INT,
                message, null);
    }


    public void warn(Object message, Throwable t) {
        differentiatedLog(null, CATEGORY_FQCN, LocationAwareLogger.WARN_INT,
                message, t);
    } 


  void differentiatedLog(Marker marker, String fqcn, int level, Object message,
            Throwable t) {

        String m = convertToString(message);
        if (locationAwareLogger != null) {
            locationAwareLogger.log(marker, fqcn, level, m, null, t);
        } else {
            switch (level) {
                case LocationAwareLogger.TRACE_INT:
                    slf4jLogger.trace(marker, m);
                    break;
                case LocationAwareLogger.DEBUG_INT:
                    slf4jLogger.debug(marker, m);
                    break;
                case LocationAwareLogger.INFO_INT:
                    slf4jLogger.info(marker, m);
                    break;
                case LocationAwareLogger.WARN_INT:
                    slf4jLogger.warn(marker, m);
                    break;
                case LocationAwareLogger.ERROR_INT:
                    slf4jLogger.error(marker, m);
                    break;
            }
        }
    }

 

  其中:

 locationAwareLogger.log(marker, fqcn, level, m, null, t); 

 

public void log(Marker marker, String fqcn, int level, String message, Object[] argArray, Throwable t);

 这个方法是slf4j的spi

 

  • 大小: 176.1 KB
分享到:
评论

相关推荐

    java后台框架集合

    Java后台框架集合是开发高效、稳定且可扩展的后端应用程序的重要工具箱。SpringMVC、Redis和Quartz是其中的三个关键组件,它们分别在不同的层面上为开发者提供了强大的支持。 SpringMVC是Spring框架的一个模块,...

    java log 日志示例程序

    `log4j`是由Apache组织开发的一个流行的日志框架,它提供了灵活的日志记录功能,可以根据不同的运行环境和需求调整日志级别、格式和输出目的地。`log4j`的核心概念包括Logger(日志器)、Appender(输出端)、Layout...

    JAVA SSH框架最全包合集

    这个最全的JAVA SSH包合集是为开发者,尤其是新手提供的一份宝贵资源,包含了进行SSH开发所需的全部组件和示例。 **Spring框架**: Spring 是一个开源的应用程序框架,主要解决企业应用开发的复杂性。它提供了IOC...

    Java log4j commons文件

    首先,log4j是Apache软件基金会的一个项目,它提供了一个灵活的日志框架,用于在Java应用程序中生成日志。log4j的核心概念包括Appender(输出目的地,如控制台、文件、数据库等)、Layout(格式化输出内容)和Logger...

    Java中Log4j 2日志框架的压缩包,版本是-2.23.0

    Java中的Log4j 2日志框架是一款广泛应用于企业级应用开发的日志处理工具,它在Log4j 1.x的基础上进行了大量的优化和改进,提供了更高效、更灵活的日志记录功能。Log4j 2.23.0是其最新的稳定版本,包含了对性能、安全...

    java日志框架

    Java日志框架是Java开发中不可或缺的部分,它们用于记录应用...综上所述,Log4j和Logback都是强大的日志框架,它们在Java开发中扮演着重要角色。理解并熟练使用这些框架,可以帮助我们更好地监控和维护我们的应用程序。

    log4j.rar java写LOG日志的驱动

    **Java日志框架Log4j详解** 在Java编程中,日志记录是不可或缺的一部分,它帮助开发者追踪程序运行状态,定位错误,以及进行性能分析。Log4j是Apache组织开发的一个开源日志框架,它是Java日志处理领域的经典工具,...

    kafka_Java_Log4j

    Log4j是一个广泛使用的日志记录框架,而Apache Kafka则是一个分布式流处理平台,常用于实时数据传输。当我们需要将Log4j的日志实时地发送到Kafka时,可以借助Kafka提供的Log4jAppender实现这一功能。现在,我们详细...

    Java开源博客系统框架B3log

    Java开源博客系统框架B3log,其核心项目Solo,是一个专为程序员设计的高质量博客平台。 Solo基于Java语言开发,体现了Java在Web开发领域的强大功能和广泛应用。它以专业、简约、稳定和极速的特点,吸引了众多技术...

    Java Log4j使用详解

    本篇文章旨在详细介绍如何在Java中使用Log4j来管理日志,包括其配置方法以及与其他日志框架(如Commons Logging和JDK自带Logger)的对比。 #### 二、Jakarta Commons Logging (JCL) ##### 2.1 概述 Jakarta ...

    JAVA日志框架适配-冲突解决方案.docx

    JAVA日志框架适配-冲突解决方案 本文将对JAVA日志框架适配中可能出现的冲突进行分析和解决,涵盖日志框架的基本概念、常见的冲突原因和解决方案。 日志框架的基本概念: 在JAVA中,日志框架可以分为两种:日志...

    若依框架使用的log4j2.16.0,修复log4j漏洞log4j2下载最新log4j2.16.0下载

    Log4j是一个广泛使用的Java日志记录框架,它允许开发者在应用程序中轻松地记录各种级别的日志信息,如DEBUG、INFO、WARN、ERROR等。在2021年底,一个重大的安全漏洞(CVE-2021-44228)被发现在Log4j2的早期版本中,...

    java Log4j 事例和讲解

    Log4j是Java编程语言中广泛使用的日志记录框架,由Apache软件基金会开发。它提供了一种灵活且高效的方式来管理和记录应用程序的运行时信息,包括错误、警告、调试信息等。在本文中,我们将深入探讨Log4j的基本功能,...

    Java实训教程 Java软件开发实战 Java开发框架 log4jdbc 共5页.pptx

    ### Java实训教程:Java软件开发实战与log4jdbc框架详解 #### 一、log4jdbc框架简介 在Java软件开发过程中,对SQL语句进行跟踪和调试是非常重要的一个环节。log4jdbc作为一款轻量级的SQL日志调试框架,能够帮助...

    Java与log4j2整合mongoDB需要的jar包

    在Java开发过程中,为了实现日志管理,我们通常会使用如log4j2这样的日志框架。Log4j2是一个强大的、灵活的日志系统,它提供了丰富的配置选项和高性能的日志记录能力。当我们的应用程序需要将日志信息存储在数据库中...

    java中log4应用

    Log4j是Apache软件基金会开发的一个开源日志框架,它为Java应用程序提供了一个灵活且高效的日志系统。本文将深入探讨Log4j的基础应用,包括配置、日志级别、布局模式和实际使用场景。 首先,我们来看一下如何在Java...

    java log4j 示例

    Java Log4j 是一个广泛使用的日志记录框架,它为Java应用程序提供了灵活且高效的日志管理。Log4j 提供了丰富的功能,包括配置日志级别、输出格式、日志目的地等,使得开发者可以方便地进行调试、监控和故障排查。在...

    java中log4j的扩展写法

    本文将基于给定文件信息中的描述,详细介绍如何对Log4j进行扩展以支持Struts、iBatis以及自定义日志输出。 #### 二、Log4j配置详解 ##### 2.1 配置文件结构 Log4j的配置文件通常为.properties格式,用于定义日志...

    log4j.jar_java开发包

    **Java日志框架Log4j详解** 在Java编程中,日志记录是一项至关重要的任务,它可以帮助开发者跟踪程序运行过程中的错误、调试信息以及其他关键事件。Log4j是一款广泛使用的开源日志框架,由Apache软件基金会开发,为...

Global site tag (gtag.js) - Google Analytics