`
ieye
  • 浏览: 32084 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java日志系统详解

阅读更多

Java日志系统确实比较丰富,常用的有log4j、JUL、logback等等,同时伴随着日志系统的发展,出现了日志框架commons-logging和slf4j。

简短地描述下日志发展,最先出现的是apache开源社区的log4j,这个日志确实是应用最广泛的日志工具,成为了java日志的事实上的标准。然而,当时Sun公司在jdk1.4中增加了JUL日志实现,企图对抗log4j,但是却造成了混乱,这个也是被人诟病的一点。当然也有其他日志工具的出现,这样必然造成开发者的混乱,因为这些日志系统互相没有关联,替换和统一也就变成了比较棘手的一件事。想象下你的应用使用log4j,然后使用了一个其他团队的库,他们使用了JUL,你的应用就得使用两个日志系统了,然后又有第二个库出现了,使用了simplelog。这个时候估计让你崩溃了,这是要闹哪样?这个状况交给你来想想办法,你该如何解决呢?进行抽象,抽象出一个接口层,对每个日志实现都适配或者转接,这样这些提供给别人的库都直接使用抽象层即可。不错,开源社区提供了commons-logging抽象,被称为JCL,也就是日志框架了,确实出色地完成了兼容主流的日志实现(log4j、JUL、simplelog),基本一统江湖,就连顶顶大名的spring也是依赖了JCL。看起来事物确实是美好,但是美好的日子不长,接下来另一个优秀的日志框架slf4j的加入导致了更加混乱的场面。比较巧的是slf4j的作者(Ceki Gülcü)就是log4j的作者,他觉得JCL不够优秀,所以他要自己搞一套更优雅的出来,于是slf4j日志体系诞生了,并为slf4j实现了一个亲子——logback,确实更加优雅,但是由于之前很多代码库已经使用JCL,虽然出现slf4j和JCL之间的桥接转换,但是集成的时候问题依然多多,对很多新手来说确实会很懊恼,因为比单独的log4j时代“复杂”多了,可以关注下这个,抱怨声确实很多。到此本来应该完了,但是Ceki Gülcü觉得还是得回头拯救下自己的“大阿哥”——log4j,于是log4j2诞生了,同样log4j2也参与到了slf4j日志体系中,想必将来会更加混乱。接下来详细解读日志系统的配合使用问题。

 

JCL的实现原理,使用JCL一般(如果是log4j可以不需要)需要一个配置commons-logging.properties在classpath上,这个文件有一行代码:

org.apache.commons.logging.LogFactory= org.apache.commons.logging.impl.LogFactoryImpl

 这个是告诉JCL使用哪个日志实现,JCL会在classpath下去加载对应的日志工厂实现类,具体的日志工厂实现类可以是log4j实现,可以是jul实现等等。用户只需要依赖JCL的api即可,对日志系统的替换只需要修改下commons-logging.properties文件切换到对应的日志工厂实现即可。但是我们也可以看到因为JCL是运行时去加载classpath下的实现类,会有classloader问题。而且因为log4j尚不支持参数占位符打日志的方式,所以JCL也会更加无力。

 

slf4j的设计确实比较优雅,采用比较熟悉的方式——接口和实现分离,有个纯粹的接口层——slf4j-api工程,这个里边基本完全定义了日志的接口,所以对于开发来说,只需要使用这个即可。有接口就要有实现,比较推崇的实现是logback,logback完全实现了slf4j-api的接口,并且性能也比log4j更好,同时实现了变参占位符日志输出方式等等新特性。刚刚也提到log4j的使用比较普遍,所以支持这批用户依然是必须的,slf4j-log4j12也实现了slf4j-api,这个算是对log4j的适配器。同样推理,也会有对JUL的适配器slf4j-jdk14等等。为了使使用JCL等等其他日志系统后者实现的用户可以很简单地切换到slf4j上来,给出了各种桥接工程,比如:jcl-over-slf4j会把对JCL的调用都桥接到slf4j上来,可以看出jcl-over-slf4j的api和JCL是相同的,所以这两个jar是不能共存的。jul-to-slf4j是把对jul的调用桥接到slf4j上,log4j-over-slf4j是把对log4j的调用桥接到slf4j。下边用一个图来表示下这个家族的大致成员


 
 如上图,最上层表示桥阶层,下层表示具体的实现层,中间是接口层,可以看出
这个图中所有的jar都是围绕着slf4j-api活动的,其中slf4j-jul的jar名称是slf4j-jdk14。slf4j-api和具体的实现层是怎么绑定的呢?这个其实是在编译时绑定的,这个可能不好理解,最直接的表达方式是不需要想jcl那样配置一下,只需要把slf4j-api和slf4j-log4j放到classpath上,即实现绑定。原理可以下载slf4j-api的源码查看,这个设计还是很巧妙的,slf4j-api中会去调用StaticLoggerBinder这个类获取绑定的工厂类,而每个日志实现会在自己的jar中提供这样一个类,这样slf4j-api就实现了编译时绑定实现。但是这样接口的源码编译需要依赖具体的实现了,不太合理吧?当时我也有这样的迷惑,因为打开slf4j-api的jar,看不到StaticLoggerBinder,就查看了slf4j-api的源码,在源码中看到了StaticLoggerBinder这个类,猜想应该是slf4j-api在打包过程中有动作,删除了自己保重的那个类,结果不出所料,确实是pom中的ant-task给处理了,pom中处理方式如下:

 

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <phase>process-classes</phase>
            <goals>
             <goal>run</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <tasks>
            <echo>Removing slf4j-api's dummy StaticLoggerBinder and StaticMarkerBinder</echo>
            <delete dir="target/classes/org/slf4j/impl"/>
          </tasks>
        </configuration>
      </plugin>

 

打出来的slf4j-api是不完整的,只有找到包含StaticLoggerBinder这个类的包才可以,于是slf4j-log4j和logback-classic都提供了这个类。另外,slf4j-log4j和logback以及slf4j-jdk14是不能同时和slf4j共存的,也就是说只能有一个实现存在,不然启动会提示有多个绑定,判断多个实现的代码也很简单,如下:

 

private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";

  private static void singleImplementationSanityCheck() {
    try {
      ClassLoader loggerFactoryClassLoader = LoggerFactory.class
          .getClassLoader();
      Enumeration paths;
      if (loggerFactoryClassLoader == null) {
        paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
      } else {
        paths = loggerFactoryClassLoader
            .getResources(STATIC_LOGGER_BINDER_PATH);
      }
      // use Set instead of list in order to deal with  bug #138
      // LinkedHashSet appropriate here because it preserves insertion order during iteration
      Set implementationSet = new LinkedHashSet();
      while (paths.hasMoreElements()) {
        URL path = (URL) paths.nextElement();
        implementationSet.add(path);
      }
      if (implementationSet.size() > 1) {
        Util.report("Class path contains multiple SLF4J bindings.");
        Iterator iterator = implementationSet.iterator();
        while(iterator.hasNext()) {
          URL path = (URL) iterator.next();
          Util.report("Found binding in [" + path + "]");
        }
        Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
      }
    } catch (IOException ioe) {
      Util.report("Error getting resources from path", ioe);
    }
  }

 

同时这个图中桥阶层和对应的实现jar是不能共存的,比如log4j-over-slf4j和slf4j-log4j,jul-to-slf4j和slf4j-jdk14,这个很好理解,会有死循环,启动也会报错。这种想象也就是说jar之前有互斥性,怎么使用maven有效解决“全局排除”会在以后的博文中讲解。jcl-over-slf4j是把对jcl的调用桥接到slf4j上,前文说到它和jcl是互斥的。图中的红线就表示互斥关系。

当然slf4j也提供了可以把对slf4j的调用桥接到JCL上的工程包——slf4j-jcl,可以看出slf4j的设计者考虑非常周到,想想这样的情况:遗留系统使用的是JCL+log4j,因为系统功能演进,依赖了其他业务线的库,恰好那个库依赖了slf4j-api,并且应用需要关心这个库的日志,那么就需要转接日志到JCL上即可。细心的你可能一经发现,slf4j-jcl和jcl-over-slf4j也是互斥的,太多互斥的了:(。

对于log4j2的加入,也很简单,和logback是很相似的,如下图:



 红线依然表示依赖的互斥,当然log4j-slf4j-impl也会和logback-classic、slf4j-log4j、slf4j-jdk14互斥。

 

常见的问题:

1.slf4j-api和实现版本不对应,尤其是1.6.x和1.5.x不兼容,如果没有特殊需求,直接升级到最新版本。

2.slf4j的多个实现同时存在,比如slf4j-log4j和logback-classic,排除其中一个即可。

3.log4j和logback不能同时使用?可以同时使用,这两个并不矛盾,遗留系统可能直接使用了log4j的代码,并且不能通过log4j-over-slf4j桥接,那么可以让他继续使用log4j,这里有详细的介绍。

4.该如何选用这些呢?建议在非特殊情况下,都使用slf4j-api+logback,不要直接使用日志实现,性能没什么影响。对于要提供给别人的类库,建议使用slf4j-api,使用方可以自由选择具体的实现,并且建议类库不要依赖具体的日志实现。对于自己的桌面小应用,可以直接使用log4j,毕竟只是随便做做。

5.logback因为木有spring提供的启动listener,所以要自己写?可以看看这里,开源社区已经做好了。

6.日志系统一般不会影响到系统性能,除非你的系统对性能非常苛刻,如果这样你可以考虑使用Blitz4j,这个是Netflix社区对log4j的性能改进版,不过他们依然建议去使用log4j或者logback。

 

后续继续补充.....

  • 大小: 116.2 KB
  • 大小: 42.3 KB
分享到:
评论
3 楼 zhanggang807 2017-05-23  
不错,学习了
2 楼 ieye 2013-09-21  
inte_sleeper 写道
整理得不错,可以转一个不?会保留出处。

木问题
1 楼 inte_sleeper 2013-09-18  
整理得不错,可以转一个不?会保留出处。

相关推荐

    java日志文件过滤

    总的来说,这个“java日志文件过滤”项目提供了一个便捷的工具,帮助开发者快速处理和分析日志数据,提高了问题排查和系统监控的效率。通过学习和理解这个项目,你可以深化对Java日志处理、文件I/O和条件过滤等技术...

    efk7.13搜集java日志-filebeat配置详解

    efk7.13搜集java日志—filebeat配置详解笔记总结

    java分布式日志系统.zip

    3. **Java日志框架** - Log4j:经典日志框架,提供了灵活的日志配置和多种Appender(如文件、数据库等)。 - Logback:由Log4j作者设计的新一代日志框架,性能优于Log4j。 - SLF4J(Simple Logging Facade for ...

    java 日志系统软件源代码.zip

    Java日志系统软件源代码是Java开发者常用的工具之一,它用于记录应用程序运行过程中的各种信息,包括错误、警告、调试信息等。对于理解和优化程序,以及排查问题具有至关重要的作用。下面将详细介绍Java日志系统的...

    Java日志框架详解.ppt

    Java日志框架详解.ppt

    一个Java写的日志分析工具

    总的来说,这个Java日志分析工具提供了对日志数据进行处理和分析的功能,通过阅读源代码,开发者可以学习到Java日志处理的最佳实践,以及如何构建此类工具。同时,对于需要排查问题或监控系统运行状态的用户,这个...

    使用Java正则表达式分析处理日志

    Java作为广泛使用的编程语言,提供了强大的正则表达式支持,使得我们能够有效地解析和处理日志文件。本篇将围绕“使用Java正则表达式分析处理日志”这一主题,探讨如何利用Java的正则表达式功能来提取、过滤和操作...

    java_java日志详解.pdf

    java_java日志详解.pdf

    日志文件解析MySQL版

    首先,**JAVA日志解析**是整个项目的基础。Java作为一种广泛使用的编程语言,具有丰富的库和工具支持日志处理。通常,我们会使用如`log4j`、`logback`这样的日志框架来生成日志,而解析这些日志文件则需要自定义的...

    java日志.txt

    根据提供的文件信息,我们可以深入探讨Java日志系统的关键概念与技术细节。日志在软件开发过程中扮演着极其重要的角色,它不仅有助于问题诊断,还能帮助我们监控应用的行为和性能。 ### Java日志系统概述 Java日志...

    java日志框架

    Java日志框架是Java开发中不可或缺的部分,它们用于记录应用程序的运行信息,帮助开发者追踪错误、调试代码以及进行性能分析。Log4j和Logback是其中最常用的两个框架,它们都由Ceki Gülcü创建,并且在设计上有着...

    java swing用Logger输出错误日志.docx

    在Java编程中,日志记录是一项非常重要的任务,它帮助开发者追踪程序运行状态,调试问题,以及记录系统事件。在Swing应用中,我们同样可以使用Java内置的`java.util.logging`包来输出错误日志。这篇文档主要讨论了...

    java实时日志解析处理

    在Java开发中,实时日志解析处理是一项至关重要的任务,特别是在大规模分布式系统或者高并发环境中。日志是系统运行状态的记录,对于故障排查、性能优化、安全监控等都有着不可替代的作用。本篇将深入探讨Java如何...

    java_java日志详解[汇编].pdf

    java_java日志详解[汇编].pdf

    LinuxLog.rar_ConnectBean.JAVA_linux_日志 分析 系统_日志系统_系统日志

    本文将深入探讨“LinuxLog.rar”压缩包中涉及到的“ConnectBean.JAVA”与Linux日志分析系统的相关知识。 首先,让我们理解"ConnectBean.JAVA"的角色。在Java编程中,"Bean"通常指的是符合JavaBeans规范的类,它是一...

    java发送syslog日志,支持多目的ip

    Java发送Syslog日志是一种常见的系统日志管理方式,尤其在分布式系统中,它能帮助开发者收集、分析和处理来自不同节点的日志信息。Syslog协议是一个标准的日志消息传递协议,广泛应用于网络设备、操作系统和其他软件...

    Java日志终极指南 - ImportNew1

    《Java日志终极指南》是一篇详细解析Java日志系统的文章,旨在帮助Java开发者更好地理解和使用日志功能。文章主要涵盖了Java日志的基础知识、核心组件、日志框架的选择以及配置方法。 首先,Java日志系统采用自定义...

    Java实现和维护系统详解.pdf

    在Java编程中,性能优化是至关重要的,尤其是在大型系统中,每一行代码的效率都可能影响到整体的系统性能。描述中提到的日志代码优化是一个典型的例子,它使用了条件语句来避免不必要的日志输出,减少计算开销。`if ...

    自己开发的Windows日志获取源码

    《使用Java开发Windows日志获取程序的深度解析》 在信息技术领域,日志记录是系统监控和故障排查的重要环节。Windows操作系统提供了丰富的日志信息,包括Security、Application等多种类型,这些日志对于开发者和...

Global site tag (gtag.js) - Google Analytics