分享
 
 
 

日志操作之JAVA-Apache

王朝java/jsp·作者佚名  2006-01-30
窄屏简体版  字體: |||超大  

日志操作之JAVA-Apache

-根据开发文档,网络资料, 使用心得稍做整理

日志论

在应用程序中输出日志有有三个目的:

(1)监视代码中变量的变化情况,把数据周期性地记录到文件中供其他应用进行统计分析工作。

(2)跟踪代码运行进轨迹,作为日后审计的依据。

(3)担当集成开发环境中的调试器,向文件或控制台打印代码的调试信息。

Apache能用日志包(Commons Logging Package)是Apache的一个开放源代码项目,它提供了一组通用的日志接口,用户可以自由地选择实现日志接口的第三方软件。通用日志包目前支持以下日志实现:

Log4J日志器(http://jakarta.apache.org/log4j

JDK1.4 Logging日志器(JDK1.4自带)

SimpleLog日志器(把日志消息输出到标准系统错误流System.err)

NoOpLog(不输出任何日志信息)

通用日志包中的两个常用接口:LogFactory和Log,分别介绍如下:

Log接口

通用日志包把消息分为6个级别:FATAL、ERROR、WARN、INFO、DEBUG和TRACE。其中FATAL级别最高,TRACE级别最低。Log接口提供输出不同级别消息的方法:

off---------------------------------最高等级的,用于关闭所有日志记录

fatal(Object message)-------输出FATAL级别的消息。

error(Object message)-------输出ERROR级别的消息。

warn(Object message)-------输出WARN级别的消息。

info(Object message)-------输出INFO级别的消息。

debug(Object message)-------输出DEBUG级别的消息。

trace(Object message)-------输出TRACE级别的消息。

all----------------------------------最低等级的,用于打开所有日志记录

注:只有当输出日志的级别大于或等于为日志配置器配置的日志级别时,这个方法才会执行。

如何指定日志器的日志级别,不同的日志器实现会有不同的实现方案。

LogFactory接口

LogFactory接口提供了获得日志器实例的两个静态方法:

public static Log getLog(String name) throws LogConfigurationException;

public static Log getLog(Class class) throws LogConfigurationException;

注:name参数作为日志器的名字;class参数指定类名作为日志器名字。

log4j简介

几乎每个大的应用程序都有它自己的日志和跟踪程序的API。顺应这一规则,E.U. SEMPER项目组决定编写它自己的程序跟踪API(tracing API)。这开始于1996年早期。经过无数的工作,更改和性能加强,这个API终于成为一个十分受欢迎的Java日志软件包,那就是log4j。这个软件包的发行遵守open source动议认证的Apache Software License。最新的log4j版本包括全部的源代码,类文件和文档资料,可以在 http://logging.apache.org/log4j/找到它们。另外,log4j已经被转换成 C, C++, C#, Perl, Python, Ruby, 和 Eiffel 语言。

Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就 是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

log4j三个组件

通常,我们都提供一个名为 log4j.properties的文件,在第一次调用到Log4J时,Log4J会在类路径(../web-inf/class/当然也可以放到其它任何目录,只要该目录被包含到类路径中即可)中定位这个文件,并读入这个文件完成的配置。这个配置文件告 诉Log4J以什么样的格式、把什么样的信息、输出到什么地方。

Log4j有三个主要的组件:Loggers(记录器),Appenders(输出源)和Layouts(布局),这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松的记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。下面对三个组件分别进行说明:

1、 Loggers

Loggers组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重要程度,明白这一点很重要,这里Log4j有一个规则:假设Loggers级别为P,如果在Loggers中发生了一个级别Q比P高,则可以启动,否则屏蔽掉。

假设你定义的级别是info,那么error和warn的日志可以显示而比他低的debug信息就不显示了。

Java程序举例来说:

//建立Logger的一个实例,命名为“com.foo”

Loggerlogger = Logger.getLogger("com.foo"); //"com.foo"是实例进行命名,也可以任意

//设置logger的级别。通常不在程序中设置logger的级别。一般在配置文件中设置。

logger.setLevel(Level.INFO);

Logger barlogger = Logger.getLogger("com.foo.Bar");

//下面这个请求可用,因为WARN >= INFO

logger.warn("Low fuel level.");

//下面这个请求不可用,因为DEBUG < INFO

logger.debug("Starting search for nearest gas station.");

//命名为“com.foo.bar”的实例barlogger会继承实例“com.foo”的级别。因此,下面这个请求可用,因为INFO >= INFO

barlogger.info("Located nearest gas station.");

//下面这个请求不可用,因为DEBUG < INFO

barlogger.debug("Exiting gas station search");

这里“是否可用”的意思是能否输出Logger信息。

在对Logger实例进行命名时,没有限制,可以取任意自己感兴趣的名字。一般情况下建议以类的所在位置来命名Logger实例,这是目前来讲比较有效的Logger命名方式。这样可以使得每个类建立自己的日志信息,便于管理。比如:

static Logger logger = Logger.getLogger(ClientWithLog4j.class.getName());

2、Appenders

禁用与使用日志请求只是Log4j其中的一个小小的地方,Log4j日志系统允许把日志输出到不同的地方,如控制台(Console)、文件(Files)、根据天数或者文件大小产生新的文件、以流的形式发送到其它地方等等。

其语法表示为:

org.apache.log4j.ConsoleAppender(控制台)

org.apache.log4j.FileAppender(文件)

org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

配置时使用方式为:

log4j.appender.appenderName = fully.qualified.name.of.appender.class

log4j.appender.appenderName.option1 = value1

log4j.appender.appenderName.option = valueN

这样就为日志的输出提供了相当大的便利。

3、Layouts

有时用户希望根据自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供了 四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式等等。

其语法表示为:

org.apache.log4j.HTMLLayout(以HTML表格形式布局),

org.apache.log4j.PatternLayout(可以灵活地指定布局模式),

org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),

org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

配置时使用方式为:

log4j.appender.appenderName.layout =fully.qualified.name.of.layout.class

log4j.appender.appenderName.layout.option1 = value1

log4j.appender.appenderName.layout.option = valueN

log4j基本编程方法

以上是从原理方面说明Log4j的使用方法,在具体Java编程使用Log4j可以参照以下示例:

1、 建立Logger实例:

语法表示:public static Logger getLogger( String name)

实际使用:static Logger logger = Logger.getLogger(ServerWithLog4j.class.getName ()) ;

2、 读取配置文件:

获得了Logger的实例之后,接下来将配置Log4j使用环境:

语法表示:

BasicConfigurator.configure():自动快速地使用缺省Log4j环境。

PropertyConfigurator.configure(String configFilename):读取使用Java的特性文件编写的配置文件。

DOMConfigurator.configure(String filename):读取XML形式的配置文件。

实际使用:

PropertyConfigurator.configure("ServerWithLog4j.properties");

3、 插入日志信息

完成了以上连个步骤以后,下面就可以按日志的不同级别插入到你要记录日志的任何地方了。

语法表示:

Logger.debug(Object message);//调试信息

Logger.info(Object message);//一般信息

Logger.warn(Object message);//警告信息

Logger.error(Object message);//错误信息

Logger.fatal(Object message);//致命错误信息

实际使用:logger.info("ServerSocket before accept: " + server);

log4j配置文件

在实际编程时,要使Log4j真正在系统中运行事先还要对配置文件进行定义。定义步骤就是对Logger、Appender及Layout的分别使用。

Log4j支持两种配置文件格式,一种是XML格式的文件,一种是java properties(key=value)【Java特性文件(键=值)】。下面我们介绍使用Java特性文件做为配置文件的方法

具体如下:

1、配置根Logger,其语法为:

log4j.rootLogger = [ level ] , appenderName1, appenderName2, …

level : 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

appenderName:就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。

例如:log4j.rootLogger=info,A1,B2,C3

2、配置日志信息输出目的地,其语法为:

log4j.appender.appenderName = fully.qualified.name.of.appender.class //

"fully.qualified.name.of.appender.class" 可以指定下面五个目的地中的一个:

1.org.apache.log4j.ConsoleAppender(控制台)

2.org.apache.log4j.FileAppender(文件)

3.org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

4.org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

5.org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

1.ConsoleAppender选项

Threshold=WARN:指定日志消息的输出最低层次。

ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。

Target=System.err:默认情况下是:System.out,指定输出控制台

2.FileAppender 选项

Threshold=WARN:指定日志消息的输出最低层次。

ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。

File=mylog.txt:指定消息输出到mylog.txt文件。

Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。

3.DailyRollingFileAppender 选项

Threshold=WARN:指定日志消息的输出最低层次。

ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。

File=mylog.txt:指定消息输出到mylog.txt文件。

Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。

DatePattern='.'yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下:

1)'.'yyyy-MM: 每月

2)'.'yyyy-ww: 每周

3)'.'yyyy-MM-dd: 每天

4)'.'yyyy-MM-dd-a: 每天两次

5)'.'yyyy-MM-dd-HH: 每小时

6)'.'yyyy-MM-dd-HH-mm: 每分钟

4.RollingFileAppender 选项

Threshold=WARN:指定日志消息的输出最低层次。

ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。

File=mylog.txt:指定消息输出到mylog.txt文件。

Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。

MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。

MaxBackupIndex=2:指定可以产生的滚动文件的最大数。

实际应用:

log4j.appender.A1=org.apache.log4j.ConsoleAppender //这里指定了日志输出的第一个位置A1是控制台ConsoleAppender

╭=========================================╮

青山不改 绿水长流http://blog.csdn.net/wangyihust

欢迎各位转贴,但需声明版权,尊重技术原创性 :)

E-mail:wangyihust@163.com OICQ:76406573

╰=========================================╯

3、配置日志信息的格式,其语法为:

1). log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class

"fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个:

1.org.apache.log4j.HTMLLayout(以HTML表格形式布局),

2.org.apache.log4j.PatternLayout(可以灵活地指定布局模式),

3.org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),

4.org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

1.HTMLLayout 选项

LocationInfo=true:默认值是false,输出java文件名称和行号

Title=my app file: 默认值是 Log4J Log Messages.

2.PatternLayout 选项

ConversionPattern=%m%n :指定怎样格式化指定的消息。

3.XMLLayout 选项

LocationInfo=true:默认值是false,输出java文件和行号

实际应用:

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

2). log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n

这里需要说明的就是日志信息格式中几个符号所代表的含义:

-X号: X信息输出时左对齐;

%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,

%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921

%r: 输出自应用启动到输出该log信息耗费的毫秒数

%c: 输出日志信息所属的类目,通常就是所在类的全名

%t: 输出产生该日志事件的线程名

%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)

%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。

%%: 输出一个"%"字符

%F: 输出日志消息产生时所在的文件名称

%L: 输出代码中的行号

%m: 输出代码中指定的消息,产生的日志具体信息

%n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行

可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:

1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。

2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。

3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。

4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。

这里上面三个步骤是对前面Log4j组件说明的一个简化;下面给出一个具体配置例子,在程序中可以参照执行:

log4j.rootLogger=INFO,A1,B2

log4j.appender.A1=org.apache.log4j.ConsoleAppender

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n

根据上面的日志格式,某一个程序的输出结果如下:

0INFO2003-06-13 13:23:46968 ClientWithLog4j Client socket: Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]

16 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server says: 'Java server with log4j, Fri Jun 13 13:23:46 CST 2003'

16 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j GOOD

16 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Command 'HELLO' not understood.'

16 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j HELP

16 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Vocabulary: HELP QUIT'

16 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j QUIT

4. 当输出信息于回滚文件时

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender //指定以文件的方式输出日志

log4j.appender.ROLLING_FILE.Threshold=ERROR

log4j.appender.ROLLING_FILE.File=rolling.log //文件位置,也可以用变量${java.home}、rolling.log

log4j.appender.ROLLING_FILE.Append=true

log4j.appender.ROLLING_FILE.MaxFileSize=10KB //文件最大尺寸

log4j.appender.ROLLING_FILE.MaxBackupIndex=1 //备份数

log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

5.Log4J对应用性能的影响

如果在程序运行中输出大量日志,显然会对应用的性能造成一定的影响。Log4J对性能的影响取决于以下因素:

日志输出目的地:输出到控制台的速度和输出到文件系统的速度是不一样的。

日志输出格式:格式简单,速度也更快。

日志级别:日志级别设置的越低,输出的日志内容越多,对性能的影响也越大。

log4j全能配置文件(转自gmmgood)

[/url][url=http://www.cybercorlin.net/images/icons/best.gif] 下面给出得Log4J配置文件实现了输出到控制台,文件,回滚文件,发送日志邮件,输出到数据库日志表,自定义标签等全套功能。

log4j.rootLogger=DEBUG,CONSOLE,A1,im

#DEBUG,CONSOLE,FILE,ROLLING_FILE,MAIL,DATABASE

log4j.addivity.org.apache=true

###################

# Console Appender

###################

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender

log4j.appender.Threshold=DEBUG

log4j.appender.CONSOLE.Target=System.out

log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout

log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n

#####################

# File Appender

#####################

log4j.appender.FILE=org.apache.log4j.FileAppender

log4j.appender.FILE.File=file.log

log4j.appender.FILE.Append=false

log4j.appender.FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

# Use this layout for LogFactor 5 analysis

########################

# Rolling File

########################

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender

log4j.appender.ROLLING_FILE.Threshold=ERROR

log4j.appender.ROLLING_FILE.File=rolling.log

log4j.appender.ROLLING_FILE.Append=true

log4j.appender.ROLLING_FILE.MaxFileSize=10KB

log4j.appender.ROLLING_FILE.MaxBackupIndex=1

log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

####################

# Socket Appender

####################

log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender

log4j.appender.SOCKET.RemoteHost=localhost

log4j.appender.SOCKET.Port=5001

log4j.appender.SOCKET.LocationInfo=true

# Set up for Log Facter 5

log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout

log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n

########################

# Log Factor 5 Appender

########################

log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender

log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

########################

# SMTP Appender

#######################

log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender

log4j.appender.MAIL.Threshold=FATAL

log4j.appender.MAIL.BufferSize=10

log4j.appender.MAIL.From=chenyl@hollycrm.com

log4j.appender.MAIL.SMTPHost=mail.hollycrm.com

log4j.appender.MAIL.Subject=Log4J Message

log4j.appender.MAIL.To=chenyl@hollycrm.com

log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout

log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

########################

# JDBC Appender

#######################

log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender

log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test

log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver

log4j.appender.DATABASE.user=root

log4j.appender.DATABASE.password=

log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')

log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout

log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender

log4j.appender.A1.File=SampleMessages.log4j

log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'

log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout

###################

#自定义Appender

###################

log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender

log4j.appender.im.host = mail.cybercorlin.net

log4j.appender.im.username = username

log4j.appender.im.password = password

log4j.appender.im.recipient = corlin@cybercorlin.net

log4j.appender.im.layout=org.apache.log4j.PatternLayout

log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

使用XML配置文件

首先,看看下面的XML配置文件示例:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">

<layout class="org.apache.log4j.SimpleLayout"/>

</appender>

<root>

<priority value ="debug" />

<appender-ref ref="ConsoleAppender"/>

</root>

</log4j:configuration>

文件以标准的XML声明作为开始,后面跟着指出DTD(文档类型定义)的DOCTYPE声明,它定义了XML文件的结构,例如,什么元素可以嵌入在其他元素中等等。上面文件在log4j发行版的src/java/org/apache/log4j/xml目录中。 接着看看封装所有元素的 log4j:configuration 元素,它在DOCTYPE声明中被指定为根元素。嵌入在根元素中有两个结构:

<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">

<layout class="org.apache.log4j.SimpleLayout"/>

</appender>

这里创建一个名叫"ConsoleAppender"的 Appender,注意,你可以选择任何名字,该示例之所以选择"ConsoleAppender",完全是为了示例的设计。接着这个appender类以全名形式给出,经常用规范(fully qualified)类名。 Appender必须具有一个指定的 name和class。嵌入在 Appender之内的是 layout元素,这里它被指定为SimpleLayout。 Layout 必须具有一个 class属性。

<root>

<priority value ="debug" />

<appender-ref ref="ConsoleAppender"/>

</root>

root元素必须存在且不能被子类化。示例中的优先级被设置为"debug",设置appender饱含一个appender-ref元素。还有更多的属性或元素可以指定。查看log4j发行版中的src/java/org/apache/log4j/xml/log4j.dtd以了解关于XML配置文件结构的更多信息。可以用下面这种方法把配置信息文件读入到Java程序中:

DOMConfigurator.configure("configurationfile.xml");

DOMConfigurator 用一棵DOM树来初始化log4j环境。这里是示例中的XML配置文件:configurationfile.xml。这里是执行该配置文件的java程序:

import org.apache.log4j.Logger;

import org.apache.log4j.xml.DOMConfigurator;

public class externalxmltest {

static Logger logger = Logger.getLogger(filetest.class);

public static void main(String args[]) {

DOMConfigurator.configure("xmllog4jconfig.xml");

logger.debug("Here is some DEBUG");

logger.info("Here is some INFO");

logger.warn("Here is some WARN");

logger.error("Here is some ERROR");

logger.fatal("Here is some FATAL");

}

}

对于带有PatternLayout的FileAppender的日志记录器Logger的XML配置文件:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

<appender name="appender" class="org.apache.log4j.FileAppender">

<param name="File" value="Indentify-Log.txt"/>

<param name="Append" value="true"/>

<layout class="org.apache.log4j.PatternLayout">

<param name="ConversionPattern" value="%d [%t] %p - %m%n"/>

</layout>

</appender>

<root>

<priority value ="info"/>

<appender-ref ref="appender"/>

</root>

</log4j:configuration>

log4j日志写入数据库

首先创建一数据库表:

字段

描述

GUID

流水号 IDENTITY (1, 1)

DATE

时间

THREAD

当前线程

LEVEL

当前级别

CLASS

当前类的java程序/方法

MESSAGES

当前输出信息

EXCEPTION

异常信息

log4j.properties如下配置:

log4j.rootLogger=DEBUG,CONSOLE,DATABASE

log4j.addivity.org.apache=true

########################

# JDBC Appender

#######################

log4j.appender.DATABASE.Threshold=INFO

log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender

#log4j.appender.DATABASE.BufferSize=10

log4j.appender.DATABASE.URL=you jdbcurl

log4j.appender.DATABASE.driver=you jdbc driver

log4j.appender.DATABASE.user=

log4j.appender.DATABASE.password=

log4j.appender.DATABASE.sql=INSERT INTO YOU_LOG_TABLE VALUES ('%d{yyyy-MM-dd HH:mm:ss}', '%t', '%p', '%l', '%m', '')

log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout

下面我们对“%d %t %p %l %m %n”一一讲解:

l %d输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy-MM-dd HH:mm:ss},输出类似:2006-01-18 17:50:22',刚好适合插入SQLServer;

l %t 产生该日志事件的线程名;

l %p 日志的log_level,如DEBUG、WARN或者INFO;

l %c 输出所属的类目,通常就是所在类的全名,如“com.eking.TestLog”;

l %m 日志的内容;

l %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。如Wite2Database.main(Wite2Database.java:18);

l %n 输出一个回车换行符,Windows平台为“ ”,Unix平台为“ ”

程序代码:

import sun.jdbc.odbc.*;

import java.sql.*;

import org.apache.log4j.Category;

import org.apache.log4j.Level;

import org.apache.log4j.Logger;

import org.apache.log4j.PropertyConfigurator;

import org.apache.log4j.jdbc.*;

public class Write2Database{

public static void main(String[] args){

static Logger logger = Logger.getLogger

( write2database.class.getName () ) ;

PropertyConfigurator.configure ( "log4j2database.properties" ) ;

logger.info ( "test" ) ;

}

}

运行起来,你就会看到有这样的sql语句被执行了:

INSERT INTO jws_log VALUES ('2006-01-18 17:50:22', 'main', 'INFO', 'Wite2Database.main(Write2Database.java:18)', 'test', '')

注意:在赛迪论坛上有一个笔者按照上述类似的方法没有运行成功,现将他所出现的问题和解决方法转载。

上述方法是利用传统的数据库连接方法,对于数据库的管理和效率严重不足,在现在这个连接池横行的时代,为什么我们不能给给Log4j配上连接池,让Log4j利用数据连接池的连接和数据库进行通讯。现查看Log4j的Api,发现JDBCAppender这个类有以下几段话:WARNING: This version of JDBCAppender is very likely to be completely replaced in the future. Moreoever, it does not log exceptions. The JDBCAppender provides for sending log events to a database.

For use as a base class:

Override getConnection() to pass any connection you want. Typically this is used to enable application wide connection pooling.

Override closeConnection(Connection con) -- if you override getConnection make sure to implement closeConnection to handle the connection you generated. Typically this would return the connection to the pool it came from.

Override getLogStatement(LoggingEvent event) to produce specialized or dynamic statements. The default uses the sql option value.

原来log4j建议我们把其提供的JDBCAppender作为基类来使用,然后Override三个父类的方法:getConnection(),closeConnection(Connection con)和getLogStatement(LoggingEvent event)。

原来如此,那就写一个子类JDBCPoolAppender来替代这个JDBCAppender

JDBCPoolAppender代码和其相关代码如下:

JDBCPoolAppender.java:

package common.log;

import java.sql.Connection;

import org.apache.log4j.spi.LoggingEvent;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.Iterator;

import org.apache.log4j.spi.ErrorCode;

import org.apache.log4j.PatternLayout;

import common.sql.MyDB;

import common.sql.GeneralDb;

public class JDBCPoolAppender extends org.apache.log4j.jdbc.JDBCAppender {

private MyDB mydb = null;

protected String sqlname=""; //增加一个数据库jndiName的属性

protected Connection connection = null;

protected String sqlStatement = "";

/**

* size of LoggingEvent buffer before writting to the database.

* Default is 1.

*/

protected int bufferSize = 1;

public JDBCPoolAppender() {

super();

}

/**

* ArrayList holding the buffer of Logging Events.

*/

public void append(LoggingEvent event) {

buffer.add(event);

if (buffer.size() >= bufferSize)

flushBuffer();

}

/**

* By default getLogStatement sends the event to the required Layout object.

* The layout will format the given pattern into a workable SQL string.

*

* Overriding this provides direct access to the LoggingEvent

* when constructing the logging statement.

*

*/

protected String getLogStatement(LoggingEvent event) {

return getLayout().format(event);

}

/**

*

* Override this to provide an alertnate method of getting

* connections (such as caching).One method to fix this is to open

* connections at the start of flushBuffer() and close them at the

* end.I use a connection pool outside of JDBCAppender which is

* accessed in an override of this method.

* */

protected void execute(String sql) throws SQLException {

Connection con = null;

Statement stmt = null;

try {

con = getConnection();

stmt = con.createStatement();

stmt.executeUpdate(sql);

} catch (SQLException e) {

if (stmt != null)

stmt.close();

throw e;

}

stmt.close();

closeConnection(con);

//System.out.println("Execute: " + sql);

}

/**

* Override this to return the connection to a pool, or to clean up the

* resource.

*

* The default behavior holds a single connection open until the appender

* is closed (typically when garbage collected).

*/

protected void closeConnection(Connection con) {

mydb=null;

try {

if (connection != null && !connection.isClosed())

connection.close();

} catch (SQLException e) {

errorHandler.error("Error closing connection", e,

ErrorCode.GENERIC_FAILURE);

}

}

/**

* Override 此函数来利用连接池返回一个Connetion对象

*

*/

protected Connection getConnection() throws SQLException {

try {

mydb = GeneralDb.getInstance(sqlname);

connection = mydb.getConnection();

} catch (Exception e) {

errorHandler.error("Error opening connection", e, ErrorCode.GENERIC_FAILURE);

}

return connection;

}

/**

* Closes the appender, flushing the buffer first then closing the default

* connection if it is open.

*/

public void close() {

flushBuffer();

try {

if (connection != null && !connection.isClosed())

connection.close();

} catch (SQLException e) {

errorHandler.error("Error closing connection", e,

ErrorCode.GENERIC_FAILURE);

}

this.closed = true;

}

/**

* loops through the buffer of LoggingEvents, gets a

* sql string from getLogStatement() and sends it to execute().

* Errors are sent to the errorHandler.

*

* If a statement fails the LoggingEvent stays in the buffer!

*/

public void flushBuffer() {

//Do the actual logging

removes.ensureCapacity(buffer.size());

for (Iterator i = buffer.iterator(); i.hasNext(); ) {

try {

LoggingEvent logEvent = (LoggingEvent) i.next();

String sql = getLogStatement(logEvent);

execute(sql);

removes.add(logEvent);

} catch (SQLException e) {

errorHandler.error("Failed to excute sql", e,

ErrorCode.FLUSH_FAILURE);

}

}

// remove from the buffer any events that were reported

buffer.removeAll(removes);

// clear the buffer of reported events

removes.clear();

}

/** closes the appender before disposal */

public void finalize() {

close();

}

/**

* JDBCAppender requires a layout.

* */

public boolean requiresLayout() {

return true;

}

/**

*

*/

public void setSql(String s) {

sqlStatement = s;

if (getLayout() == null) {

this.setLayout(new PatternLayout(s));

} else {

((PatternLayout) getLayout()).setConversionPattern(s);

}

}

/**

* Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")

*/

public String getSql() {

return sqlStatement;

}

public void setSqlname(String sqlname){

sqlname=sqlname;

}

public String getSqlname(){

return sqlname;

}

public void setBufferSize(int newBufferSize) {

bufferSize = newBufferSize;

buffer.ensureCapacity(bufferSize);

removes.ensureCapacity(bufferSize);

}

public int getBufferSize() {

return bufferSize;

}

}

MyDB.java:

package common.sql;

import java.sql.*;

import com.codestudio.sql.*;//引入开源项目Poolman数据库连接池的包

public class MyDB {

public static final String module = MyDB.class.getName();

private String dbName = "";

private PoolMan plmn = null;

public MyDB(String dbName) {

try {

if (plmn == null) {

plmn = (PoolMan) Class.forName("com.codestudio.sql.PoolMan").

newInstance();

}

} catch (Exception ec) {

System.out.println(ec.toString()+module);

}

this.dbName = dbName;

}

private Connection getNewConnection() {

Connection conn = null;

try {

conn = plmn.connect("jdbc:poolman://" + dbName);

conn.setAutoCommit(true);

} catch (Exception ec) {

System.out.println(ec.toString()+"First:Connect sqlsever failed"+module);

try {

Thread.sleep(1000);

conn = plmn.connect("jdbc:poolman://" + dbName);

conn.setAutoCommit(true);

} catch (Exception ecs) {

System.out.println(ecs.toString()+"Again:Connect sqlsever faile"+module);

}

}

return conn;

}

public Connection getConnection() {

return getNewConnection();

}

}

GeneralDb.java:

package common.sql;

package common.sql;

import java.util.*;

public class GeneralDb {

private static Hashtable dbPool;

public static MyDB getInstance(String dbname) {

if (dbPool == null) {

dbPool = new Hashtable();

}

MyDB db = (MyDB) dbPool.get(dbname);

if (db == null) {

db = new MyDB(dbname);

dbPool.put(dbname, db);

}

return db;

}

}

Log4j数据库连接池的配置如下:

log4j.appender.JDBC=common.log.JDBCPoolAppender

log4j.appender.JDBC.sqlname=log

log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout

log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level,

location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')

poolman.xml配置如下:

〈?xml version="1.0" encoding="UTF-8"?>

〈poolman>

〈management-mode>local〈/management-mode>

〈datasource>

〈dbname>log〈/dbname>

〈jndiName>log〈/jndiName>

〈driver>com.mysql.jdbc.Driver〈/driver>

〈url>jdbc:mysql://localhost:3306/test〈/url>

〈username>use〈/username>

〈password>password〈/password>

〈minimumSize>0〈/minimumSize>

〈maximumSize>10〈/maximumSize>

〈logFile>logs/mysql.log〈/logFile>

〈/datasource>

〈/poolman>

运行成功!对于JDBCPoolAppender的属性(比如sqlname属性)我们可以利用Log4j的反射机制随便添加,只要在配置文件给其附上值即可应用,而原来的父类里面的一些属性(username什么的)和其get,set方法由于在连接池中不需要,所以删除。而在JDBCPoolAppender类中,我也只是将getConnection 方法Override ,在这个方法中我们可以根据需要生成我们的Connection对象,另外两个方法大家可以根据需求来决定怎样Override。

Log4Net for .net framework

等待研究

用户可以从http://logging.apache.org/log4net/下载log4net的源代码。解压软件包后,在解压的src目录下将log4net.sln载入Visual Studio .NET,编译后可以得到log4net.dll。用户要在自己的程序里加入日志功能,只需将log4net.dll引入工程即可。

╭=========================================╮

青山不改 绿水长流http://blog.csdn.net/wangyihust

欢迎各位转贴,但需声明版权,尊重技术原创性 :)

E-mail:wangyihust@163.com OICQ:76406573

╰=========================================╯

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有