Log4J学习【三】复杂一点的例子一

上面我们看了一个使用Log4J的最简单的示例,在这个示例里面,我们只在一个类中使用标准的配置打印了一行日志信息。接下来,我们简单模拟几个常见的日志情况,来看看Log4J的一些对日志的控制能力。
第一个例子,我们来看看Log4J对日志级别的控制。在Log4J中,日志是可以分成不同级别的,这和我们做日志的想法其实是保持一致的。有的时候,我们记录的信息可能是非常细节的,比如读取了一个配置文件,我们需要日志这个文件的地址,可能我们要日志这个配置文件里面每一个配置项的详细信息;而有的时候,我们不需要查看配置文件里面每一个配置项的具体信息,而只想记录当前已经完成了配置文件的读取。下面我们就来模拟这样一个例子:
假设我们的代码要处理一个数据库连接的示例,有一个数据库连接配置文件:db.properties:
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///log4j
username=log4j
password=admin


接下来,我们写一个代码来读取和解析这个配置文件:
package cd.itcast.log4j;

import java.io.IOException;
import java.util.Properties;

public class Configure {

    public void config(){
    config("db.properties");
    }

    public void config(String resourceName){
        try {
            Properties prop=new Properties();
            prop.load(this.getClass().getClassLoader().getResourceAsStream(resourceName));
            for(String key:prop.stringPropertyNames()){
            String value=prop.getProperty(key);
            //doSomeConfigWorkUseKeyAndValue(key,value)
        }
    } catch (IOException e) {
        }
    }
}


这个类很简单,模拟了一个配置对象,在配置对象中提供了两个配置方法,一个是没有资源名称的,使用了默认的db.properties作为资源名称,第二个是允许传入一个资源名称的。在config方法中,简单的从classpath中读取配置文件,并得到配置项的key和value用作系统配置。
现在这段代码是没有添加任何日志的,把日志加上:
package cd.itcast.log4j;

import java.util.Properties;

import org.apache.log4j.Logger;

public class Configure {

// 同样,首先得到和这个类绑定的Logger实例
    private static Logger log = Logger.getLogger(Configure.class);

    public void config() {
        log.info("using default db.properties");
         config("db.properties");
    }

    public void config(String resourceName) {
        log.info("using config file in classpath:" + resourceName);
        try {
            Properties prop = new Properties();
            prop.load(this.getClass().getClassLoader().getResourceAsStream(resourceName));
            log.debug("load properties file success");
            for (String key : prop.stringPropertyNames()) {
            String value = prop.getProperty(key);
            // doSomeConfigWorkUseKeyAndValue(key,value)
            log.debug("[properties] " + key + " : " + value);
        }
    } catch (Exception e) {
            log.error("log properties file failed", e);
        }
    }
}


在改进后的版本中,我们需要注意几个地方:
1,同样,我们仍然需要得到一个和该类绑定的Logger实例
2,我们在该类中并没有做BasicConfigurator基础设置,因为Log4J的配置是可以放在外部的,我们的类本身只需要做日志,而不需要管怎么去配置。
3,在该类中,我们一共使用到了三种Logger实例的方法:
1)info:info表示概要信息记录级别,比如代码中的正在读取配置
2)debug:debug表示很详细的信息记录级别,比如代码中的读取的配置文件内容是什么;
3)error:error表示对错误的记录级别,这里在error方法后面,我们把可能抛出的错误作为参数也传给了方法

完成该类后,我们写一个测试来使用这个类:
package cd.itcast.log4j;

import org.apache.log4j.BasicConfigurator;
import org.junit.Test;

public class LogTest2 {

    @Test
    public void testLog2(){
        BasicConfigurator.configure();
        Configure conf=new Configure();
        conf.config();
    }
}


同样,我们先使用BasicConfigurator.config()方法来完成最基本的配置,运行测试,输出:
0 [main] INFO cd.itcast.log4j.Configure  - using default db.properties
0 [main] INFO cd.itcast.log4j.Configure  - using config file in classpath:db.properties
0 [main] DEBUG cd.itcast.log4j.Configure  - load properties file success
0 [main] DEBUG cd.itcast.log4j.Configure  - [properties] driverClass : com.mysql.jdbc.Driver
0 [main] DEBUG cd.itcast.log4j.Configure  - [properties] url : jdbc:mysql:///log4j
0 [main] DEBUG cd.itcast.log4j.Configure  - [properties] password : admin
0 [main] DEBUG cd.itcast.log4j.Configure  - [properties] username : log4j


可以通过输出看到,所有的INFO和DEBUG级别的日志信息都输出出来了。接下来,我们先修改代码,让代码报个错:
package cd.itcast.log4j;

import org.apache.log4j.BasicConfigurator;
import org.junit.Test;

public class LogTest2 {

    @Test
    public void testLog2(){
        BasicConfigurator.configure();
        Configure conf=new Configure();
        conf.config("aa.properties");
    }
}


这里,我们故意传一个不存在的配置文件,运行测试:
0 [main] INFO cd.itcast.log4j.Configure  - using config file in classpath:aa.properties
16 [main] ERROR cd.itcast.log4j.Configure  - log properties file failed
java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Properties.java:418)
at java.util.Properties.load0(Properties.java:337)
at java.util.Properties.load(Properties.java:325)
at cd.itcast.log4j.Configure.config(Configure.java:20)


可以看到结果里面即打印出了INFO,也打印出了我们想要的ERROR级别,但下面还有错误的栈信息,这个就看你自己了,如果不想要错误栈信息,只需要打印ERROR级别日志,那么在调用Logger.error方法的时候,不要把错误作为第二个参数传入方法就行了。代码写到这里,演示了Log4J中一个非常重要的概念:日志级别。在Log4J中,内置了几种日志级别,分别是:debug;info;warn;error;和fatal;debug、info和error前面都已经见识过了,下面简单介绍下warn和fatal:
warn代表警告级别,表示需要引起注意,可能程序没有按照预期运行等等;
fatal代表致命级别,表示非常严重的错误。
通过这几个级别的解释,大家应该很容易能够感觉到,日志级别是有一定的顺序的,在Log4J中,日志级别的顺序定义为:debug<info<warn<error<fatal;那么这个级别到底有什么用呢?下面接着看这个例子:
假如现在我的应用已经基本测试完成,在客户那里部署了,我现在不想再看到那么详细的日志输出了,我只想看到粗略的步骤即可,即我不想看到DEBUG信息了,那怎么做呢?很简单,我们只需要在代码中加入一句话:
package cd.itcast.log4j;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.Test;

public class LogTest2 {

    @Test
    public void testLog2(){
        BasicConfigurator.configure();
        Logger.getRootLogger().setLevel(Level.INFO);
        Configure conf=new Configure();
        conf.config();
    }
}


在加入的这一句代码中,包含着非常重要的2个内容,大家要非常注意。在讲解之前,我们先看看输出的结果:
0 [main] INFO cd.itcast.log4j.Configure  - using default db.properties
0 [main] INFO cd.itcast.log4j.Configure  - using config file in classpath:db.properties


可以看到,这次就只打印出了INFO级别的信息,而没有打印DEBUG级别了。下面我们来稍微详细的解释一下这段代码。
第一个需要注意的就是,我们在调整打印日志级别的时候,并没有修改Configure这个类里面的代码,换句话说,这再次印证了之前我们说了,控制日志级别是应用之外的事情,而不是应用本身代码控制的。
第二个需要注意的是加粗的代码,从字面意义上来看,我们先通过Logger类的getRootLogger方法得到了一个Logger类实例,这个Logger类实例就是根Logger。接着,我们设置了这个根Logger的日志级别为Level.INFO,结合最后输出的日志,我们很容易想到,我们规定了最小的输出日志级别是INFO。
这句代码反应出了两个非常重要的思想,第一个思想,之前已经提到了,日志级别是有顺序的,这里就能明显看到这个顺序对我们控制应用的中的日志级别的作用,根据刚才的顺序,我们控制了最低打印级别为Level.INFO,那么应用就只会打印出大于或等于这个级别的日志信息,即info<warn<error<fatal这四个。我们可以通过让应用报错,来看看会不会打印出error:
0 [main] INFO cd.itcast.log4j.Configure  - using config file in classpath:aa.properties
0 [main] ERROR cd.itcast.log4j.Configure  - log properties file failed


仍然正常打印出ERROR。第二个思想,代表着Log4J的一个非常重要的体系结构:日志记录器(Logger)是有层次结构的;并且,这个层次结构和类的结构是保持一致的。我们把上面的示例所涉及的两个类的结构画出来:


当我们在LogTest2中使用Logger.getRootLogger()方法的时候,实际上,我们得到了整个应用的根Logger对象,即图中的rootLogger;而我们在Configure类中写的
private static Logger log = Logger.getLogger(Configure.class);

代码的真正含义是,我在cd.itcast.log4j这个Logger体系结构下创建了一个cd.itcast.log4j.Configure名字的Logger实例。这个实例的根Logger就是在LogTest2中得到的rootLogger();因为LogTest2和Configure是在同一个classLoader之下的,所以他们共享同一个RootLogger。而当我们在rootLogger上设置了日志级别,即在该rootLogger的体系之上设置了一个默认的日志级别,即Level.INFO;而我们并没有在cd.itcast.log4j.Configure绑定的Logger上设置日志级别,所以他继承了他的祖先的日志级别,即rootLogger的Level.INFO,所以,打印出来就只有大于或等于INFO的日志级别信息了。关于Logger的体系结构,后面会详细讲到,这里大家只要心理面有一个大概的印象即可。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值