1????????? 概述
一般的系统对程序的调试信息只进行了简单的粗放处理,将这些信息直接用System.out.println()语句输出到控制台中。由于在调度过程中程序员为了能够跟踪程序的运行情况往往将大量信息输出到控制台,而在调度成功后没有相应地将这些信息屏蔽掉,在程序部署运行后,往往一个简单的业务功能调用也会输出大容量的过程调度信息,一方面造成了大量IO的读写,占用硬盘空间,另一方面则因为日志量大,很难查找到运行期有用的日志信息。
程序异常,资源释放操作失败这些信息是发现程序问题,定位出错点的信息依据,得不到这些信息将导致程序错误被屏蔽,要想使问题浮出水面程序必须能够提供详细而简洁的日志信息。
?log4J是为java语言量身定做的一个日志模块,用统一的接口写日志,通过配置文件信息控制日志信息的输出格式、目的及输出级别(指定输出级别后,只有比输出级别更高的日志会被输出)。可以在不更改程序输出日志的情况下方便日志输出的控制,为日志的操作提供了很大的灵活性。
2????????? log4J的基本操作
2.1??????? 写日志的API
???? log4J将日志分为5个级别,从低到高分别是DEBUG,INFO,WARN,ERROR,FATAL,相应地log4J为记录这5个级别提供了5个方法,它们分别是:
? public void debug(Object obj)
? public void info(Object obj)
public void warn(Object obj)
? public void error(Object obj)
public void fatal(Object obj)
同时每个方法还对应一个带Throwable入参的重载函数,用于将异常一并记录到日志中:
? public void debug(Object obj,Throwable ex)
? public void info(Object obj,Throwable ex)
public void warn(Object obj,Throwable ex)
? public void error(Object obj,Throwable ex)
public void fatal(Object obj,Throwable ex)
5个级别记录信息的重要性依次提升,下面就每个记录方法对应的应用场合举例如下:
2.1.1??????? 写日志API的使用示例
? 在程序中如何恰当级别的日志记录API记录日志信息是非常重要的,一般的我们将信息以其重要性调用将其划分为5个级别,分别调用相应的API来记录,我们以一个查询数据库的代码段来说明各级别的划分:
Connection conn = null;
String sqlStr = “select * from table1 where a=’”+a+”’”;
logger.debug(“sqlStr字串为:”+sqlStr);//测试变量是否正确,在调度时查看,以后不会用
...
try
{
?? conn = DBBean.getConnection();
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery(sqlStr);
if(rs.next())
{
? logger.info(“有记录”);//查看程序运行中的信息,反映程序及配置信息的情况
}
else
{
? logger.warn(“因配置要求至少要有一条记录,请核对配置信息。”);
? //假设配置信息要求一条配置记录,当找不到记录时应该警告,以并更改配置
}
}catch(SQLException e)
{
?? logger.error(“数据查询时发生异常”,e);
?? //发生了查询异常,可能是sqlStr语句的语法错误造成的
}
finally
{
? try
{
? if(conn != null)
{
? conn.close();
? conn = null;
}
}
catch(SQLException e)
{
? logger.fatal(“数据连接无法关闭,连接将无法释放”,e);
? //数据连接无法关闭将导致资源泄漏,是非常严重的问题,程序员必须对该信息
? //响应,查询原因,否则系统将因数据连接资源无法释放而崩溃
}
}
?
2.1.2??????? 日志信息构成
?? ??通过配置,日志信息包括两部分,一部分是由日志引擎通过配置生成的信息,如信息来源的包、类、对应源码的行数,日志级别等信息,而另一部分是用户通过接口入参手工设置的对象信息,在写日志前,将调用对象的toString()将其转换成字符串。对于 error和fatal级别的日志,我们约定必须为每个日志指定错误日志的类型,错误的日志的类型和日志信息一起作为入参传入写日志引擎,错误类型用[]括起来。如:
logger.error(“[DB001]关闭数据连接时出错。”)
?
logger.fatal(“[HIB001]关闭Hibernate会话时发生异常。”);
?
logger.error(“[CFG001]审批流程配置信息不正确。”);
?
此外必须为每条日志类型构造说明字典:
错误编号
说明
产生原因
解决方法
DB001
关闭数据连接失败
数据连接打开的光标太多,会话因网络终止
仔细检查程序,查看该连接创建的Statement或PrepareStatemetn在用完后没有及时关闭。检查数据库的配置,或网络连接方面的硬件问题
HIB001
关闭Hibernate会话失败
会话对应的数据连接打开的光标太多,会话因网络终止
仔细检查程序,查看该会话对应的数据连接创建的Statement或PrepareStatemetn在用完后没有及时关闭。检查数据库的配置,或网络连接方面的硬件问题
CFG001
审批流程配置信息不正确
没有正确配置T_FLOW表的信息
每个流程在T_Flow表中都必须配置且只须配置一条配置信息,配置信息必须包括流程名、流程编号的信息,流程编号不能和其他流程编号重复。
…
…
…
…
?
?
3????????? log4J的配置
log4J通过一个配置文件决定输出日志的级别、目的以及格式,文件名为:log4j.properties
可以在web.xml中通过容器上下文参数指定该文件的地址:
…
??
??? logConfFile
??? WEB-INF/log4j.properties
??? 相对于应用程序根目录
?
…
? 必须通过一个类读取该参数以初始化log4J的配置信息,我们在SysInit.java中设置该配置信息:
? public void contextInitialized(ServletContextEvent sce) {???
…
System.out.println("初始化基于log4j的日志引擎...");
??? String prefix =? sce.getServletContext().getRealPath("/");
??? String logFileConf = sce.getServletContext().getInitParameter("logConfFile");
??? PropertyConfigurator.configure(prefix+System.getProperty("file.separator")+logFileConf);
System.out.println("日志引擎就绪,日志配置文件位于"+prefix+System.getProperty("file.separator")+logFileConf+"\n");?
…
? }
因为SysInit是实现容器监听器接口的类,这样在WEB容器初始化时,就会初始化该日志的配置信息.
log4J的配置文件内容如下:
log4j.rootLogger=DEBUG,R
#log4j.appender.A1=org.apache.log4j.ConsoleAppender
#log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#log4j.appender.A1.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=e:/tomcat/webLogs/log4j.log
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d %5p [%t] (%F:%L) - %m%n
?
该配置指定日志写入到e:/tomcat/webLogs/log4j.log文件中,大小为100K,以原文本方式写日志,日志信息中包括类名,方法名,行数等信息.
?
?