Java日志Log

来源:互联网 发布:淘宝流量和访客 编辑:程序博客网 时间:2024/06/02 01:00

背景

在编写程序的时候应当尽量使用日志,而不是在控制台System.out.println()。因为记录了日志可以方便分析程序出错的位置。查看日志和代码调试是进阶程序员的硬本领。目前大家熟知的记录日志有以下几种方式:

JDK

JDK中提供了日志类:java.util.logging.Logger。可以记录一些简单的日志。但是,在正式项目中,还是推荐使用三方框架。

Commons-logging

Apache提供的日志门面,为了和具体的日志实现进行解耦。这个和JDBC的api一样。在commons-logging内部也有一些简单的实现。在运行时,动态寻找真正需要运行的日志库。Commons-logging原理如下:

1)寻找属性org.apache.commons.logging.LogFactory的值。如果找到,是用该属性值创建LogFactory实例。

            // First, try a global system property
            FACTORY_PROPERTY = org.apache.commons.logging.LogFactory;            String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);            factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);

2)读取META-INF/services/org.apache.commons.logging.LogFactory文件内容,如果找到该文件,以文件中的类名(该类从LogFactory继承)创建实例。譬如jcl-over-slf4j是一款从Commons-logging到Slf4j的适配器。目录文件中的内容是org.apache.commons.logging.imple.SLF4JLogFactory。

        // Second, try to find a service by using the JDK1.3 class discovery mechanism, which involves putting a file with the name        // of an interface class in the META-INF/services directory, where the        // contents of the file is a single line specifying a concrete class         // that implements the desired interface.        if (factory == null) {            SERVICE_ID = "META-INF/services/org.apache.commons.logging.LogFactory";            InputStream is = getResourceAsStream(contextClassLoader,SERVICE_ID);            BufferedReader rd = new BufferedReader(new InputStreamReader(is, "utf-8"));    String factoryClassName = rd.readLine();            rd.close();            factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader );        }

3)如果读取不到,就到classpath下寻找commons-logging.properties属性文件,读取该配置文件中org.apache.commons.logging.LogFactory的属性值。

FACTORY_PROPERTIES ="commons-logging.properties";Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);String factoryClass = props.getProperty(FACTORY_PROPERTY);factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);

4)如果没有该配置,转入默认程序。

FACTORY_DEFAULT ="org.apache.commons.logging.impl.LogFactoryImpl";factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader);

5)在LogFactoryImpl中,如果能找到Log4j的实现则使用Log4jLoger;如果找不到,使用Jdk14Logger;接着尝试Jdk13LumberjackLogger;如果都不可以,使用commons-logging默认的SimpleLog。

Slf4j

全称Simple logging facade for Java,是对不同日志框架的一种门面封装。可以通过占位符的方式打印日志,避免isErrorEnabled()方法的调用。在编译时通过StaticLoggerBinder绑定具体的日志工厂。Slf4j的每一个具体框架中都会有一个org.slf4j.impl.StaticLoggerBinder。StaticLoggerBinder实现了日志方案的绑定接入。例如:

ILoggerFactory loggerFactory = new Log4jLoggerFactory();

log4j

是经典的日志实现方案。可以在项目中添加配置文件(FileName.properties或FileName.xml)。

Logback

是一种日志框架。作为log4j的替换和slf4j组成完整的日志系统。性能上比Log4j快很多。

Commons-logging 到 Slf4j

Commons-logging 和 Slf4j都是日志门面,可以在程序中保留使用Commons-logging,但是实体转移到Slf4j中实现。需要的jar包如下:Commons-logging、jcl-over-slf4j、slf4j-api、slf4j-log4j12或者logback。

  1. Commons-logging的LogFactory.getLog();
  2. jcl-over-slf4j的SLF4jLogFactory的getInstance()调用LoggerFactory.getLogger()方法;
  3. getLogger()调用getILoggerFactory(),返回ILogFactory。ILogFactory是slf4j-api的日志工厂接口。每一个具体的slf4j的具体实现框架中都有具体的实例。如slf4j-log4j12中的Log4jLoggerFactory实现了ILoggerFactory;
  4. getILoggerFactory()中返回StaticLoggerBinder中绑定的LoggerFactory。因此,在一个项目中,不能有两个Slf4j的实现框架,否则Slf4j会不知道调用哪个StaticLoggerBinder类。

总结

使用日志有三种组合:1、基于Commons-logging,可以直接和log4j结合使用;2、基于slf4j-api + log4j或者logback;3、基于Commons-logging,利用jcl-over-slf4j适配器转接到slf4j:Commons-logging + jcl-over-slf4j + slf4j-api + slf4j-log4j12。