(工作中遇到的那些坑01)JAVA WEB 项目中错误捕获,日志输出

  最近在工作中,发现一个线上人员同步的定时任务总是同步失败,能收到同步失败发送的短信但是去日志里搜不到对应的信息,最后发现是在log.error()方法中参数给错了,导致日志里找到的错误只有错误信息,没有堆栈信息,一直没有办法定位错误发生的具体位置。所以这里做一个小小的总结,学习一下java web项目中使用log4j和commons- logging来完成错误捕获和日志输出。

common-logging

  1.简介

Jakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具体的日志实现工具。它提供给中间件/日志工具开发者一个简单的日志操作抽象,允许程序开发人员使用不同的具体日志实现工具。用户被假定已熟悉某种日志实现工具的更高级别的细节。JCL提供的接口,对其它一些日志工具,包括Log4J, Avalon LogKit, and JDK 1.4等,进行了简单的包装,此接口更接近于Log4J和LogKit的实现。

  2.基本信息

  JCL有两个基本的抽象类:Log(基本记录器)和LogFactory(负责创建Log实例)。当commons-logging.jar被加入到 CLASSPATH之后,它会合理地猜测你想用的日志工具,然后进行自我设置,用户根本不需要做任何设置。默认的LogFactory是按照下列的步骤去发现并决定那个日志工具将被使用的(按照顺序,寻找过程会在找到第一个工具时中止):

   1. 寻找当前factory中名叫org.apache.commons.logging.Log配置属性的值

   2. 寻找系统中属性中名叫org.apache.commons.logging.Log的值

   3. 如果应用程序的classpath中有log4j,则使用相关的包装(wrapper)类(Log4JLogger)

   4. 如果应用程序运行在jdk1.4的系统中,使用相关的包装类(Jdk14Logger)

   5. 使用简易日志包装类(SimpleLog)

  这里贴上commons-logging中LogSource.java的源代码,不难看出实现顺序

package log.sample;

public class ca {
     static {
            // Is Log4J Available?用户Log4J是否可用
            try {
                /**
                 * 通过Class.forName("org.apache.log4j.Logger"))来查找Log4J,
                 * 只有将log4j.jar添加到classpath以后才能找到,
                 * 这也是为什么默认情况下只要将log4j.jar文件放在lib文件夹中
                 * 而不需要在common-logging.properties配置文件中进行配置就能自动使用log4j的原因
                 */
                if (null != Class.forName("org.apache.log4j.Logger")) {
                    log4jIsAvailable = true;
                } else {
                    log4jIsAvailable = false;
                }
            } catch (Throwable t) {
                log4jIsAvailable = false;
            }

            // Is JDK 1.4 Logging Available?原来同上面的Log4J
            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,通过common-logging.properties配置文件来决定日志实现方式
            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) {//如果log4j可用,默认优先使用Log4JLogger
                        setLogImplementation
                                ("org.apache.commons.logging.impl.Log4JLogger");
                    } else if (jdk14IsAvailable) {//第二优先使用Jdk14Logger
                        setLogImplementation
                                ("org.apache.commons.logging.impl.Jdk14Logger");
                    } else {//最后使用commoms-logging中的自带的实现,但它不进行任何操作
                        setLogImplementation
                                ("org.apache.commons.logging.impl.NoOpLog");
                    }
                } catch (Throwable t) {
                    try {
                        setLogImplementation
                                ("org.apache.commons.logging.impl.NoOpLog");
                    } catch (Throwable u) {
                        ;
                    }
                }
            }

        }
}

org.apache.commons.logging.Log的具体实现有如下:

-org.apache.commons.logging.impl.Jdk14Logger 使用JDK1.4。

-org.apache.commons.logging.impl.Log4JLogger 使用Log4J。

-org.apache.commons.logging.impl.LogKitLogger 使用 avalon-Logkit。

-org.apache.commons.logging.impl.SimpleLog common-logging自带日志实现类。它实现了Log接口,把日志消息都输出到系统错误流System.err 中。 

-org.apache.commons.logging.impl.NoOpLog common-logging自带日志实现类。它实现了Log接口。 其输出日志的方法中不进行任何操作。

  3.使用

  因为项目上使用的就是log4j和commons- logging结合,所以这里只介绍这种方式。

(1)下载log4j和commons- logging的jar包,这里推荐用http://mvnrepository.com/去找jar包

(2)如果需要指定日志器,可以在属性配置文件common-logging.properties中设置,这里以log4j为例,只需要这一句即可。在目前工作的项目,是没有这个配置文件的,因为LogFactory会自动检测到应用程序的classpath。

org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog

(3)org.apache.commons.logging.Log接口中定义的方法,按严重性由高到低的顺序:

log.fatal(Object message);
log.fatal(Object message, Throwable t);
log.error(Object message);
log.error(Object message, Throwable t);
log.warn(Object message);
log.warn(Object message, Throwable t);
log.info(Object message);
log.info(Object message, Throwable t);
log.debug(Object message);
log.debug(Object message, Throwable t);
log.trace(Object message);
log.trace(Object message, Throwable t);

  一般当我们在捕获error级别及以上是,通常使用log.error(Object message, Throwable t)方法,因为log.error(Object message)只能输出错误信息,无法输出堆栈信息,对我们分析日志是非常不利的,下面是我在实际项目中使用commons- logging的格式:

package TEST;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Test {

    private static final Log log = LogFactory.getLog(Test.class);

	public void test(  ) throws Exception {
		log.info("-----------------START-----------------");
		try {


		} catch (Exception e) {
			log.error("代码执行错误", e);
	  }
	}
	

 

Log4j

  1.简介

  Log4j是Apache的一个开源项目,它允许开发者以任意间隔输出日志信息。Log4j主要由三大类组件构成:

  1)Logger-负责输出日志信息,并能够对日志信息进行分类筛选,即决定哪些日志信息应该被输出,哪些该被忽略。Loggers组件输出日志信息时分为5个级别:DEBUG、INFO、WARN、ERROR、FATAL。这五个级别的顺序是:DEBUG<INFO<WARN<ERROR<FATAL。如果设置某个Logger组件的级别是P,则只有级别比P高的日志信息才能输出。Logger是有继承关系的,最上层是rootLogger,定义的其他Logger都会继承rootLogger。

  2)Appender-定义了日志输出目的地,指定日志信息应该被输出到什么地方。输出的目的地可以是控制台、文件或网络设备。

  3)Layout-通过在Appender的后面附加Layout来实现格式化输出。

  一个Logger可以有多个Appender,每个Appender对应一个Layout。

   2.详细配置

  log4j.properties配置如下:

### set log levels ###
log4j.rootLogger = debug , stdout , D , E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
## 输出INFO级别以上的日志
log4j.appender.stdout.Threshold = INFO
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n

### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D:/logs/log.log
log4j.appender.D.Append = true
## 输出DEBUG级别以上的日志
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

### 保存异常信息到单独文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
## 异常日志文件名
log4j.appender.E.File = D:/logs/error.log 
log4j.appender.E.Append = true
 ## 只输出ERROR级别以上的日志!!!
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值