日志?/font> (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)摘至http://www.aygfsteel.com/rendong/
在应用程序中输出日志有有三个目的Q?/span>
Q?Q监视代码中变量的变化情况,把数据周期性地记录到文件中供其他应用进行统计分析工作?/span>
Q?Q跟t代码运行进轨迹Q作为日后审计的依据?/span>
Q?Q担当集成开发环境中的调试器Q向文g或控制台打印代码的调试信息?/span>
Apache能用日志包(Commons Logging PackageQ是Apache的一个开放源代码目Q它提供?jin)一l通用的日志接口, 用户可以自由地选择实现日志接口的第三方软g。通用日志包目前支持以下日志实玎ͼ(x)
通用日志包把消息分ؓ(f)6个别:(x)FATAL、ERROR、WARN、INFO、DEBUG和TRACE。其中FATALU别最高,
TRACEU别最低?Log接口提供输出不同U别消息的方法:(x)
off---------------------------------最高等U的Q用于关闭所有日志记?/span>
fatal(Object message)-------输出FATALU别的消息?/span>
error(Object message)-------输出ERRORU别的消息?/span>
warn(Object message)-------输出WARNU别的消息?/span>
info(Object message)-------输出INFOU别的消息?/span>
debug(Object message)-------输出DEBUGU别的消息?/span>
trace(Object message)-------输出TRACEU别的消息?/span>
all----------------------------------最低等U的Q用于打开所有日志记?/span>
注:(x)只有当输出日志的U别大于或等于ؓ(f)日志配置器配|的日志U别Ӟq个Ҏ(gu)才会(x)执行?/span>
如何指定日志器的日志U别Q不同的日志器实C(x)有不同的实现Ҏ(gu)?/span>
LogFactory接口提供?jin)获得日志器实例的两个?rn)态方法:(x)
public static Log getLog(String name) throws LogConfigurationException;
public static Log getLog(Class class) throws LogConfigurationException;
注:(x)name参数作ؓ(f)日志器的名字Qclass参数指定cd作ؓ(f)日志器名字?/span>
log4j?/font>
几乎每个大的应用E序都有它自q日志和跟t程序的API。顺应这一规则QE.U. (tng)SEMPER目l决?br />~写它自qE序跟踪APIQtracing (tng)APIQ。这开始于1996q早期。经q无数的工作Q更改和性能加强Q这
个APIl于成ؓ(f)一个十分受Ƣ迎的Java日志软g包,那就是log4j。这个Y件包的发行遵守open (tng)source动议?br />证的Apache (tng)Software (tng)License。最新的log4j版本包括全部的源代码Q类文g和文档资料,
可以在?/font>http://logging.apache.org/log4j/扑ֈ它们。另外,log4j已经被{换成 (tng)C, (tng)C++, (tng)C#, (tng)Perl, (tng)Python, (tng)
Ruby, (tng)和?tng)Eiffel (tng)语言?br />
Log4j是Apache的一个开放源代码目Q通过使用Log4jQ我们可以控制日志信息输送的目的地是控制台?br />文g、GUIlg、甚x(chng)套接口服?器、NT的事件记录器、UNIX Syslog守护q程{;我们也可以控制每一?br />日志的输出格式;通过定义每一条日志信息的U别Q我们能够更加细致地控制日志的生成过E。最令h感兴?br />的就 是,q些可以通过一个配|文件来灉|地进行配|,而不需要修改应用的代码?br />
log4j三个lg
(tng) (tng) (tng) (tng) (tng) (tng) 通常Q我们都提供一个名?log4j.properties的文Ӟ在第一ơ调用到Log4JӞLog4J?x)在c\?br />Q?./web-inf/class/当然也可以放到其它Q何目录,只要该目录被包含到类路径中即可)(j)中定位这个文Ӟq读?br />q个文g完成的配|。这个配|文件告 诉Log4J以什么样的格式、把什么样的信息、输出到什么地斏V?br /> Log4j有三个主要的lgQLoggers(记录?QAppenders(输出?和Layouts(布局)Q这里可单理解ؓ(f)日志
cdQ日志要输出的地方和日志以何UŞ式输出。综合用这三个lg可以L的记录信息的cd和别,q可
以在q行时控制日志输出的样式和位|。下面对三个lg分别q行说明Q?br />
1?Loggers
Loggerslg在此pȝ中被分ؓ(f)五个U别QDEBUG、INFO、WARN、ERROR和FATAL。这五个U别是有序
的,DEBUG < INFO < WARN < ERROR < FATALQ分别用来指定这条日志信息的重要E度,明白q一点很重要Q?br />q里Log4j有一个规则:(x)假设LoggersU别为PQ如果在Loggers中发生了(jin)一个别Q比P高,则可以启动,否则屏蔽掉?br />假设你定义的U别是infoQ那么error和warn的日志可以显C比他低的debug信息׃昄?jin)?br /> (tng)
JavaE序举例来说Q?br />
//建立Logger的一个实例,命名为“com.foo?br /> Logger logger = Logger.getLogger("com.foo"); //"com.foo"是实例进行命名,也可以Q?br /> //讄logger的别。通常不在E序中设|logger的别。一般在配置文g中设|?br /> logger.setLevel(Level.INFO);
Logger barlogger = Logger.getLogger("com.foo.Bar");
//下面q个h可用Q因为WARN >= INFO
logger.warn("Low fuel level.");
//下面q个h不可用,因ؓ(f)DEBUG < INFO
logger.debug("Starting search for nearest gas station.");
//命名为“com.foo.bar”的实例barlogger?x)承实例“com.foo”的U别。因此,下面q个h可用Q因为INFO >= INFO
barlogger.info("Located nearest gas station.");
//下面q个h不可用,因ؓ(f)DEBUG < INFO
barlogger.debug("Exiting gas station search");
q里“是否可用”的意思是能否输出Logger信息?br /> 在对Logger实例q行命名Ӟ没有限制Q可以取L自己感兴的名字。一般情况下以类的所在位|来
命名Logger实例Q这是目前来讲比较有效的Logger命名方式。这样可以得每个类建立自己的日志信息,便于理?br />比如Q?br />
static Logger logger = Logger.getLogger(ClientWithLog4j.class.getName());
2、Appenders
用与用日志请求只是Log4j其中的一个小的地方QLog4j日志pȝ允许把日志输出到不同的地方,
如控制台QConsoleQ、文ӞF(tun)ilesQ、根据天数或者文件大生新的文件、以的形式发送到其它地方{等?br />
其语法表CZؓ(f)Q?br />
org.apache.log4j.ConsoleAppenderQ控制台Q?br /> org.apache.log4j.FileAppenderQ文Ӟ(j)
org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ(j)
(tng) (tng) (tng) (tng) (tng) (tng)org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文Ӟ(j)
org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)(j)
配置时用方式ؓ(f)Q?br /> log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
?br /> (tng) (tng) (tng) (tng) (tng) (tng) log4j.appender.appenderName.option = valueN
q样׃ؓ(f)日志的输出提供了(jin)相当大的便利?br />
3、Layouts
有时用户希望Ҏ(gu)自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完?br /> (tng) (tng) (tng) (tng) (tng) (tng)q个功能。Layouts提供?四种日志输出样式Q如Ҏ(gu)HTML样式、自由指定样式、包含日志别与信息的样?br /> (tng) (tng) (tng) (tng) (tng) (tng)和包含日志时间、线E、类别等信息的样式等{?br />
其语法表CZؓ(f)Q?br />
org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)(j)
配置时用方式ؓ(f)Q?br />
log4j.appender.appenderName.layout =fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
?br /> log4j.appender.appenderName.layout.option = valueN
(tng)
log4j基本~程Ҏ(gu)
以上是从原理斚w说明Log4j的用方法,在具体Java~程使用Log4j可以参照以下CZQ?br />
1?建立Logger实例Q?br /> 语法表示Qpublic static Logger getLogger( String name)
实际使用Qstatic Logger logger = Logger.getLogger(ServerWithLog4j.class.getName ()) ;
2?d配置文gQ?br /> 获得?jin)Logger的实例之后,接下来将配置Log4j使用环境Q?br /> 语法表示Q?br /> BasicConfigurator.configure()Q自动快速地使用~省Log4j环境?br /> PropertyConfigurator.configure(String configFilename)Q读取用Java的特性文件编写的配置文g?br /> DOMConfigurator.configure(String filename)Q读取XML形式的配|文件?br /> 实际使用Q?br /> (tng) (tng) (tng) PropertyConfigurator.configure("ServerWithLog4j.properties");
3?插入日志信息
完成?jin)以上连个步骤以后,下面可以按日志的不同别插入到你要记录日志的Q何地方了(jin)?br /> 语法表示Q?br /> Logger.debug(Object message);//调试信息
Logger.info(Object message);//一般信?br /> Logger.warn(Object message);//警告信息
Logger.error(Object message);//错误信息
Logger.fatal(Object message);//致命错误信息
实际使用Qlogger.info("ServerSocket before accept: " + server);
log4j配置文g
在实际编E时Q要使Log4j真正在系l中q行事先q要寚w|文件进行定义。定义步骤就是对Logger?br />Appender?qing)Layout的分别用?br /> (tng) (tng) (tng) Log4j支持两种配置文g格式Q一U是XML格式的文Ӟ一U是java propertiesQkey=valueQ?br />【JavaҎ(gu)文Ӟ?|(j)】。下面我们介l用JavaҎ(gu)文件做为配|文件的Ҏ(gu)
(tng) (tng) 具体如下Q?br />
1、配|根LoggerQ?/strong>其语法ؓ(f)Q?br /> log4j.rootLogger = [ level ] , appenderName1, appenderName2, ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) level : 是日志记录的优先U,分ؓ(f)OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者?zhn)定义的别?br />Log4j只用四个别,优先U从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的U别Q?br />(zhn)可以控制到应用E序中相应别的日志信息的开兟뀂比如在q里?义了(jin)INFOU别Q则应用E序中所有DEBUGU?br />别的日志信息不被打印出来?br /> (tng) (tng) (tng) (tng) appenderName:是指定日志信息输出到哪个地斏V?zhn)可以同时指定多个输出目的地?br /> (tng) (tng) 例如Qlog4j.rootLoggerQinfo,A1,B2,C3
2、配|日志信息输出目的地Q其语法为:(x)
log4j.appender.appenderName = fully.qualified.name.of.appender.class (tng) //
(tng) "fully.qualified.name.of.appender.class" 可以指定下面五个目的C的一个:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)1.org.apache.log4j.ConsoleAppenderQ控制台Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)2.org.apache.log4j.FileAppenderQ文Ӟ(j)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3.org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ(j)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 4.org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文Ӟ(j)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 5.org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)(j)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1.ConsoleAppender选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Threshold=WARN:指定日志消息的输出最低层ơ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ImmediateFlush=true:默认值是true,意谓着所有的消息都会(x)被立卌出?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Target=System.errQ默认情况下是:(x)System.out,指定输出控制?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)2.FileAppender 选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Threshold=WARN:指定日志消息的输出最低层ơ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ImmediateFlush=true:默认值是true,意谓着所有的消息都会(x)被立卌出?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) File=mylog.txt:指定消息输出到mylog.txt文g?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3.DailyRollingFileAppender 选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Threshold=WARN:指定日志消息的输出最低层ơ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ImmediateFlush=true:默认值是true,意谓着所有的消息都会(x)被立卌出?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)File=mylog.txt:指定消息输出到mylog.txt文g?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) DatePattern='.'yyyy-ww:每周滚动一ơ文Ӟx(chng)周生一个新的文件。当然也可以指定按月、周?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)天、时和分。即对应的格式如下:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1)'.'yyyy-MM: 每月
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2)'.'yyyy-ww: 每周 (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3)'.'yyyy-MM-dd: 每天
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 4)'.'yyyy-MM-dd-a: 每天两次
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 5)'.'yyyy-MM-dd-HH: 每小?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 6)'.'yyyy-MM-dd-HH-mm: 每分?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 4.RollingFileAppender 选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)Threshold=WARN:指定日志消息的输出最低层ơ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)I(yng)mmediateFlush=true:默认值是true,意谓着所有的消息都会(x)被立卌出?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) File=mylog.txt:指定消息输出到mylog.txt文g?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小Ӟ会(x)自动滚动Q即原?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)的内容移到mylog.log.1文g?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) MaxBackupIndex=2:指定可以产生的滚动文件的最大数?/span>
实际应用Q?br /> log4j.appender.A1=org.apache.log4j.ConsoleAppender //q里指定?jin)日志输出的W一个位|A1是控制台ConsoleAppender
?========================================?br /> (tng) (tng) (tng) 青山不改 l水长流http://blog.csdn.net/wangyihust
(tng) (tng) (tng) (tng) (tng) Ƣ迎各位转脓(chung)Q但需声明版权Q尊重技术原创?:)
(tng) (tng) (tng) (tng) (tng) (tng) E-mail:wangyihust@163.com (tng) (tng) (tng) OICQ:76406573 (tng) (tng) (tng)
?========================================?br />
3、配|日志信息的格式Q其语法为:(x)
1).log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)"fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1.org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
(tng) (tng) (tng) (tng) (tng) (tng) 2.org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
(tng) (tng) (tng) (tng) (tng) (tng) 3.org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
(tng) (tng) (tng) (tng) (tng) (tng) 4.org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)(j)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1.HTMLLayout 选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) LocationInfo=true:默认值是false,输出java文g名称和行?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) Title=my app file: 默认值是 Log4J Log Messages.
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)2.PatternLayout 选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ConversionPattern=%m%n :指定怎样格式化指定的消息?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3.XMLLayout (tng) 选项
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) LocationInfo=true:默认值是false,输出java文g和行?br /> (tng) (tng) 实际应用Q?br /> (tng) (tng) log4j.appender.A1.layout=org.apache.log4j.PatternLayout
(tng) (tng) (tng) (tng) (tng) (tng) 2). log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) q里需要说明的是日志信息格式中几个符h代表的含义:(x)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) QX? X信息输出时左寚wQ?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %p: 输出日志信息优先U,即DEBUGQINFOQW(xu)ARNQERRORQFATAL,
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %d: 输出日志旉点的日期或时_(d)默认格式为ISO8601Q也可以在其后指定格式,
比如Q?d{yyy MMM dd HH:mm:ss,SSS}Q输出类|(x)2002q?0?8?22Q?0Q?8Q?21
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %r: 输出自应用启动到输出该log信息耗费的毫U数
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %c: 输出日志信息所属的cȝQ通常是所在类的全?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %t: 输出产生该日志事件的U程?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %l: 输出日志事g的发生位|,相当?C.%M(%F:%L)的组?包括cȝ名、发生的U程Q以?qing)在代?br />中的行数。D例:(x)Testlog4.main(TestLog4.java:10)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %x: 输出和当前线E相兌的NDC(嵌套诊断环境),其用到像java servletsq样的多客户多线E的应用中?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %%: 输出一?%"字符
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %F: 输出日志消息产生时所在的文g名称
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)%L: 输出代码中的行号
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %m: 输出代码中指定的消息,产生的日志具体信?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) %n: 输出一个回车换行符QW(xu)indowsq_?\r\n"QUnixq_?\n"输出日志信息换行
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 可以?与模式字W之间加上修饰符来控制其最宽度、最大宽度、和文本的对齐方式。如Q?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 1)%20cQ指定输出category的名Uͼ最的宽度?0Q如果category的名U小?0的话Q默认的情况下右寚w?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 2)%-20c:指定输出category的名Uͼ最的宽度?0Q如果category的名U小?0的话Q?-"h定左寚w?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 3)%.30c:指定输出category的名Uͼ最大的宽度?0Q如果category的名U大?0的话Q就?x)将左?br />多出的字W截掉,但小?0的话也不?x)有I格?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 4)%20.30c:如果category的名U小?0pI格Qƈ且右寚wQ如果其名称长于30字符Q?br />׃左边交远销出的字符截掉?/span>
q里上面三个步骤是对前面Log4jlg说明的一个简化;下面l出一个具体配|例子,在程序中可以参照执行Q?br /> log4j.rootLogger=INFO,A1QB2
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
(tng) Ҏ(gu)上面的日志格式,某一个程序的输出l果如下Q?br /> 0 INFO 2003-06-13 13:23:46968 ClientWithLog4j Client socket:
Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 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
(tng)
(tng) (tng) (tng) (tng) (tng) 4. 当输Z息于回滚文g?/strong>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender (tng) (tng) //指定以文件的方式输出日志
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.Threshold=ERROR (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.File=rolling.log (tng) //文g位置,也可以用变量、rolling.log
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.Append=true (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.MaxFileSize=10KB (tng) //文g最大尺?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.MaxBackupIndex=1 (tng) //备䆾?br /> (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n (tng)
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 5.Log4J对应用性能的媄(jing)?/font>
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) 如果在程序运行中输出大量日志Q显然会(x)对应用的性能造成一定的影响。Log4JҎ(gu)能的媄(jing)响取决于以下因素Q?/font>
log4j全能配置文g(转自gmmgood)
(tng)使用XML配置文g
首先Q看看下面的XML配置文gCZQ?/span>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
(tng) (tng) (tng) (tng) (tng) (tng) (tng)
(tng) <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
(tng) (tng) (tng) <layout class="org.apache.log4j.SimpleLayout"/>
(tng) </appender>
(tng) <root>
(tng) (tng) (tng) <priority value ="debug" />
(tng) (tng) (tng) <appender-ref ref="ConsoleAppender"/>
(tng) </root>
</log4j:configuration>
(tng) (tng) (tng)
(tng)
文g以标准的XML声明作ؓ(f)开始,后面跟着指出DTDQ文档类型定义)(j)的DOCTYPE声明Q它定义?jin)XML文g的结构,
例如Q什么元素可以嵌入在其他元素中等{。上面文件在log4j发行版的src/java/org/apache/log4j/xml目录中?
接着看看装所有元素的 log4j:configuration 元素Q它在DOCTYPE声明中被指定为根元素。嵌入在根元素中有两个结构:(x)
(tng) <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
(tng) (tng) (tng) <layout class="org.apache.log4j.SimpleLayout"/>
(tng) </appender> (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng)
(tng)
q里创徏一个名?ConsoleAppender"?AppenderQ注意,你可以选择M名字Q该CZ之所以选择"ConsoleAppender"Q?br />完全是ؓ(f)?jin)示例的设计。接着q个appendercM全名形式l出Q经常用规范Qfully qualifiedQ类名?Appender必须h
一个指定的 name和class。嵌入在 Appender之内的是 layout元素Q这里它被指定ؓ(f)SimpleLayout?Layout 必须?br />有一?class属性?
(tng) <root>
(tng) (tng) (tng) <priority value ="debug" />
(tng) (tng) (tng) <appender-ref ref="ConsoleAppender"/>
(tng) </root> (tng) (tng) (tng) (tng) (tng) (tng)
(tng) (tng) (tng)
root元素必须存在且不能被子类化。示例中的优先被设|ؓ(f)"debug"Q设|a(chn)ppender饱含一个appender-ref元素?br />q有更多的属性或元素可以指定。查看log4j发行版中的src/java/org/apache/log4j/xml/log4j.dtd以了(jin)解关于XML配置
文gl构的更多信息。可以用下面q种Ҏ(gu)把配|信息文件读入到JavaE序?
DOMConfigurator.configure("configurationfile.xml"); (tng) (tng) (tng)
DOMConfigurator 用一DOM?wi)来初始化log4j环境。这里是CZ中的XML配置文gQconfigurationfile.xml。这里是
执行该配|文件的javaE序:
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
public class externalxmltest {
(tng) (tng) static Logger logger = Logger.getLogger(filetest.class);
(tng) (tng) public static void main(String args[]) {
(tng) (tng) (tng) (tng) (tng) DOMConfigurator.configure("xmllog4jconfig.xml");
(tng) (tng) (tng) (tng) (tng) logger.debug("Here is some DEBUG");
(tng) (tng) (tng) (tng) (tng) logger.info("Here is some INFO");
(tng) (tng) (tng) (tng) (tng) logger.warn("Here is some WARN");
(tng) (tng) (tng) (tng) (tng) logger.error("Here is some ERROR");
(tng) (tng) (tng) (tng) (tng) logger.fatal("Here is some FATAL");
(tng) (tng) }
}
(tng) (tng) (tng)
对于带有PatternLayout的FileAppender的日志记录器Logger的XML配置文g:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
(tng) (tng) (tng) (tng) (tng) (tng) (tng)
(tng) <appender name="appender" class="org.apache.log4j.FileAppender">
(tng) (tng) (tng) <param name="File" value="Indentify-Log.txt"/>
(tng) (tng) (tng) <param name="Append" value="true"/>
(tng) (tng) (tng) <layout class="org.apache.log4j.PatternLayout">
(tng) (tng) (tng) (tng) (tng) <param name="ConversionPattern" value="%d [%t] %p - %m%n"/>
(tng) (tng) (tng) </layout>
(tng) </appender>
(tng) <root>
(tng) (tng) (tng) <priority value ="info"/>
(tng) (tng) (tng) <appender-ref ref="appender"/>
(tng) </root>
</log4j:configuration>
(tng) (tng) (tng)
(tng)log4j日志写入数据?/strong>
首先创徏一数据库表:
字段 | 描述 |
GUID | 水?IDENTITY (1, 1) |
DATE | 旉 |
THREAD | 当前U程 |
LEVEL | 当前U别 |
CLASS | 当前cȝjavaE序/Ҏ(gu) |
MESSAGES | 当前输出信息 |
EXCEPTION | 异常信息 |
log4j.properties如下配置:
log4j.rootLogger=DEBUG,CONSOLE,DATABASE
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{
(tng) public static void main(String[] args){
(tng) (tng) (tng) static Logger logger = Logger.getLogger
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) ( write2database.class.getName () ) ;
(tng) (tng) (tng) PropertyConfigurator.configure ( "log4j2database.properties" ) ;
(tng) (tng) (tng) logger.info ( "test" ) ;
(tng) }
}
q行hQ你׃(x)看到有这L(fng)sql语句被执行了(jin)Q?
(tng) (tng) (tng) (tng) (tng) (tng) INSERT INTO jws_log (tng) VALUES ('2006-01-18 17:50:22', 'main', 'INFO',
'Wite2Database.main(Write2Database.java:18)', 'test', '')
注意 Q?u>在赛q论坛上有一个笔者按照上q类似的Ҏ(gu)没有q行成功Q现他所出现的问题和解决Ҏ(gu)转蝲?/u>
上述Ҏ(gu)是利用传l的数据库连接方法,对于数据库的理和效率严重不I在现在这个连接池横行的时?
Z么我们不能给lLog4j配上q接池,让Log4j利用数据q接池的q接和数据库q行通讯?br />现查看Log4j的Api,发现JDBCAppenderq个cL以下几段话:(x)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:
getConnection()
to pass any connection you want. Typically this is used to enablecloseConnection(Connection con)
-- if you override getConnection make sure to closeConnection
to handle the connection you generated. Typically this wouldgetLogStatement(LoggingEvent event)
to produce specialized or dynamic statements.
原来log4j我们把其提供的JDBCAppender作ؓ(f)基类来用,然后Override三个父类的方法:(x)getConnection(),
closeConnection(Connection con)和getLogStatement(LoggingEvent event)?/font>
原来如此Q那写一个子cJDBCPoolAppender来替代这个JDBCAppender
JDBCPoolAppender代码和其相关代码如下Q?br />
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的属?br />
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 此函数来利用q接池返回一个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数据库连接池的配|如下:(x)
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配置如下Q?br />
?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>
(tng) (tng) q行成功Q对于JDBCPoolAppender的属性(比如sqlname属性)(j)我们可以利用Log4j的反机
刉便添加,只要在配|文件给光上值即可应用,而原来的父类里面的一些属性(username
什么的)和其get,setҎ(gu)׃在连接池中不需要,所以删除。而在JDBCPoolAppendercMQ我?br />只是getConnection Ҏ(gu)Override Q在q个Ҏ(gu)中我们可以根据需要生成我们的Connection
对象Q另外两个方法大家可以根据需求来军_怎样Override?/font>
(tng)Log4Net (tng) for .net framework
(tng) (tng) (tng) (tng) {待研究 (tng)
(tng) (tng) (tng) (tng) (tng) (tng) 用户可以?a >http://logging.apache.org/log4net/下蝲log4net的源代码。解压Y件包后,在解压的src目录
下将log4net.sln载入Visual Studio .NETQ编译后可以得到l(f)og4net.dll。用戯在自qE序里加入日志功能,
只需log4net.dll引入工程卛_。?tng)?