应用程序中使用好日志(Logging)功能能够方便的调试和跟踪应用程序任意时刻的行为和状态。在大规模的应用开发中尤其重要,毫不夸张的说,Logging是不可或缺的重要组成部分。那么我们需要自己开发一套Logging API吗?答案是否定的,我们不用再造轮子了。java自J2SE 1.4版本开始提供一个新的Java Logging API应用程序接口。它能够很方便地控制和输出日志信息到控制台,文件或其它用户定义的地方,如数据库,电子邮件等。当然还有其它的一些 Logging API,如:log4j、JDK、Logkit等等。
那么这么多的Logging工具,我们该选择那个呢?在我们的程序中如何兼容这些个日志组件呢?一个选择是在我们的程序中使用Commons Logging 组件,然后在发布时根据环境来选择不同的底层实现。
Commons项目Logging组件的办法是将记录日志的功能封装为一组标准的API,使其底层实现可以任意修改和变换。开发者利用这个API来执行记录日志信息的命令,由API来决定把这些命令传递给适当的底层实现。因此,对于开发者来说,Logging组件对于任何具体的底层实现都是中立的。
使用Commons的Logging API非常简单。只需导入Logging的两个必须类、创建一个Log的静态实例,下面展示了这部分操作的代码:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CommonLogTest {
private static Log log = LogFactory.getLog(CommonLogTest.class);
// ...
}
有必要详细说明一下调用LogFactory.getLog()时发生的事情。调用该函数会启动一个发现过程,即找出必需的底层日志记录功能的实现,具体的发现过程在下面列出。注意,不管底层的日志工具是怎么找到的,它都必须是一个实现了Log接口的类,且必须在CLASSPATH之中。Commons Logging API直接提供对下列底层日志记录工具的支持:Jdk14Logger,Log4JLogger,LogKitLogger,NoOpLogger (直接丢弃所有日志信息),还有一个SimpleLog。
⑴ Commons的Logging首先在CLASSPATH中查找commons-logging.properties文件。这个属性文件至少定义org.apache.commons.logging.Log属性,它的值应该是上述任意Log接口实现的完整限定名称。如果找到org.apache.commons.logging.Log属相,则使用该属相对应的日志组件。结束发现过程。
⑵ 如果上面的步骤失败(文件不存在或属相不存在),Commons的Logging接着检查系统属性org.apache.commons.logging.Log。 如果找到org.apache.commons.logging.Log系统属性,则使用该系统属性对应的日志组件。结束发现过程。
⑶ 如果找不到org.apache.commons.logging.Log系统属性,Logging接着在CLASSPATH中寻找log4j的类。如果找到了,Logging就假定应用要使用的是log4j。不过这时log4j本身的属性仍要通过log4j.properties文件正确配置。结束发现过程。
⑷ 如果上述查找均不能找到适当的Logging API,但应用程序正运行在JRE 1.4或更高版本上,则默认使用JRE 1.4的日志记录功能。结束发现过程。
⑸ 最后,如果上述操作都失败(JRE 版本也低于1.4),则应用将使用内建的SimpleLog。SimpleLog把所有日志信息直接输出到System.err。结束发现过程。
获得适当的底层日志工具之后,接下来就可以开始记录日志信息。作为一种标准的API,Commons Logging API主要的好处是在底层日志机制的基础上建立了一个抽象层,通过抽象层把调用转换成与具体实现有关的日志记录命令。 本文提供的示例程序会输出一个提示信息,告诉你当前正在使用哪一种底层的日志工具。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CommonLogTest {
private static Log log = LogFactory.getLog(CommonLogTest.class);
public static void main(String[] args) {
log.error("ERROR");
log.debug("DEBUG");
log.warn("WARN");
log.info("INFO");
log.trace("TRACE");
System.out.println(log.getClass());
}
}
请试着在不同的环境配置下运行这个程序。例如,
1. 在不指定任何属性的情况下运行这个程序,这时默认将使用Jdk14Logger;
2. 然后指定系统属性 -Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog再运行程序,这时日志记录工具将是SimpleLog;
3. 把Log4J的类放入CLASSPATH,默认情况下log4j会在类路径上寻找log4j.properties,如果找到就加载,否则查找系统属性log4j.properties,若还是没有找到,则报告错误。因此只要正确设置了log4j的log4j.properties配置文件并放在合适位置,就可以得到Log4JLogger输出的信息。
如果没有设置log4j.properties配置文件,则会输出以下提示:
class org.apache.commons.logging.impl.Log4JLogger
log4j:WARN No appenders could be found for logger (CommonLogTest).
log4j:WARN Please initialize the log4j system properly.
1.logger.debug("Debug ...")或logger.info("Info ...")或
logger.warn("Warn ...")或logger.error("Error ...") 都只输出对应的信息,即logger.debug只输出debug的信息,info只输出info的信息。
而log4j.properties中配置“log4j.rootLogger=dubug, console, logfile”的作用是控制显示出来的信息。作用:当同时有logger.debug("Debug ...")和logger.error("Error ...")时,log4j.properties配置成“log4j.rootLogger=error, console, logfile”,这样显示台之显示error的信息,而不显示Debug的信息。
2.级别顺序(低到高): DEBUG < INFO < WARN < ERROR < FATAL
显示台显示的内容是:大于等于log4j.properties中配置的信息。
全文如下:
先写一个例子
package usual;
import org.apache.log4j.*;
import org.apache.log4j.SimpleLayout;
public class testlog {
static Logger logger = Logger.getLogger(testlog.class.getName());
public static void main(String[] args) {
PropertyConfigurator pc = new PropertyConfigurator();
pc.configure("config/log4j.properties");// (其中config是你保存log4j.properties的目录)
logger.debug("Debug ...");
logger.info("Info ...");
logger.warn("Warn ...");
logger.error("Error ...");
}
}
static Logger logger = Logger.getLogger(testlog.class.getName());就是创建一个属於testlog类的Logger对象,创建时要告知Logger你当前的Class是什么,
logger.debug就是输出debug的信息
logger.info就是输出提示信息
logger.warn就是显示警告信息
logger.error就是显示错误信息
log4j可以让你把要写的东西分成4级 (其实有更多级,你可以自己定义,比如叫: 三级++),这些级别叫优先权 (Priority),这里四个优先权就是debug, info, warn, 和error,优先权从低到高,log4j能让你控制显示哪些优先权的信息。log4j也让你要写哪就哪,可以是屏幕,可以是一个文件,甚至是一个Email,一个XML,一个Socket,等等。这些控制都在一个小文件里,叫log4j.properties (其实你可以用其它名字,这里是默认名)。这个文件在工程目录下。以下是log4j.properties的内容:
#### Use one appender to log to console
log4j.rootCategory=DEBUG, stdout
#### Appender writes to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p(%F:%L) - %m%n
就是说我要显示所有优先权等於和高于Debug的信息,所以上面那个Class会显示Debug ...,Info ...,Warn ...,Error ...所有信息。
下面的三行说,这个stdout输出端其实是标准输出Console,也就是屏幕。输出的格式是Pattern。转换方式是%5p(%F:%L) - %m%n,即前五格用来显示优先权,再显示当前的文件名,加当前的行数。最后是logger.debug()或logger.info()或logger.warn()或logger.error()里的信息。%n表示回车空行。
运行程序,最后输出的是:
DEBUG(LogTest.java:9) - Debug ...
INFO(LogTest.java:10) - Info ...
WARN(LogTest.java:11) - Warn ...
ERROR(LogTest.java:12) - Error ...
log4j的参数配置说明 |
Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打印到控制台还是文件中;而输出格式则控制了日志信息的显示内容。
一、定义配置文件 其实您也可以完全不使用配置文件,而是在代码中配置Log4j环境。但是,使用配置文件将使您的应用程序更加灵活。Log4j支持两种配置文件格式,一种是XML格式的文件,一种是Java特性文件(键=值)。下面我们介绍使用Java特性文件做为配置文件的方法: 1.配置根Logger,其语法为: log4j.rootLogger = [ level ] , appenderName, appenderName, … 其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。 appenderName就是指B日志信息输出到哪个地方。您可以同时指定多个输出目的地。 2.配置日志信息输出目的地Appender,其语法为: log4j.appender.appenderName = fully.qualified.name.of.appender.class 其中,Log4j提供的appender有以下几种: 3.配置日志信息的格式(布局),其语法为: log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class 其中,Log4j提供的layout有以e几种: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: %m 输出代码中指定的消息 %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL 二、在代码中使用Log4j 1.得到记录器 使用Log4j,第一步就是获取日志记录器,这个记录器将负责控制日志信息。其语法为: public static Logger getLogger( String name) 通过指定的名字获得记录器,如果必要的话,则为这个名字创建一个新的记录器。Name一般取本类的名字,比如: static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) 2.读取配置文件 当获得了日志记录器之后,第二步将配置Log4j环境,其语法为: BasicConfigurator.configure (): 自动快速地使用缺省Log4j环境。 3.插入记录信息(格式化日志信息) 当上两个必要步骤执行完毕,您就可以轻松地使用不同优先级别的日志记录语句插入到您想记录日志的任何地方,其语法如下: Logger.debug ( Object message ) ; |
ISO8601
#NULL
,
RELATIVE
,
ABSOLUTE
,
DATE
or
ISO8601
.
GMT-8:00
false
##
默认为true 打印类别名
false
##
默认为true 打印上下文信息
false
##
默认为true 打印线程名
#
打印信息如下:
2007-09-13 14:45:39,765 [http-8080-1] ERROR com.poxool.test.test - error
成功关闭链接
!-----------------------------------------------------------------------------!
! PATTERN FORMATS GLOSSARY !
!-----------------------------------------------------------------------------!
! %n – 新的一行 !
! %m – 打印错误信息 !
! %p – 打印优先级信息 (FATAL, ERROR, WARN, INFO, DEBUG or custom) !
! %r – 打印程序开始后过去的毫秒数 !
! %% - 打印输出的百分比 !
! !
!-----------------------SOME MORE CLUTTER IN YOUR LOG-------------------------!
! %c - name of your category (logger), %c{2} will outputs last two components !
! %t – 打印产生该日志信息的线程名称 !
! %x – 打印嵌套的上下文信息 !
! !
!-------------------------SLOW PERFORMANCE FORMATS----------------------------!
! %d – 打印时间和日期, 比如 %d{ISO8601}, %d{DATE}, %d{ABSOLUTE}, !
! %d{HH:mm:ss,SSS}, %d{dd MMM yyyy HH:mm:ss,SSS} 等等 !
! %l - Shortcut for %F%L%C%M !
! %F - Java 代码文件名称 !
! %L - Java 代码错误的行数 !
! %C - Java 类的名称, %C{1} 将输出以“.”分割的后面一个 !
! %M - Java 方法的名称 !
! !
!------------------------------FORMAT MODIFIERS-------------------------------!
! %-any_letter_above - Left-justify in min. width (default is right-justify) !
! %20any_letter_above - 20 char. min. width (pad with spaces if reqd.) !
! %.30any_letter_above - 30 char. max. width (truncate beginning if reqd.) !
! %-10.10r - Example. Left-justify time elapsed within 10-wide field. !
! Truncate from beginning if wider than 10 characters. !
!-----------------------------------------------------------------------------!