一、什么是log4php:
?log4j在JAVA中可算是大名鼎鼎的日志开发包了,它为apche组织维护项目,VxR兄使用php来实现了log4j的功能, 目前log4php已经作为log4j的一个子项目存在,详细信息可点击:http://logging.apache.org/log4php/进行查看,另外VxR兄的log4php官方主站为:http://www.vxr.it/log4php/,有兴趣的朋友可直接点上边两个网址查看详细信息。
?下载地址:http://www.vxr.it/log4php/download.html
二、安装:
?本文下载版本为log4php-0.9.tar.gz, 解压后目录中有src目录,将{解压目录}/src/log4php/目录拷贝至你的项目目录,完成安装。因为本文是用来讲解log4php的, 所以不相关目录都不列出来,把它定义为http://localhost, 项目结构图如下:
+app/
?? + log4php
?? + images/
?? + logs/
?? + js/
?? + css/
?? - log4php.properties
?? - index.php
三、开始使用:
?先从最简单的来,先来看看test1.php中的内容:
[php]
<?php
/*1*/ define (LOG4PHP_DIR, "log4php");
/*2*/ require_once(LOG4PHP_DIR . '/LoggerManager.php');
/*3*/ $str = "here is test string!";
/*4*/ echo "这里是PHP的输出, 与log4php无关哟!<br>";
/*5*/ $logger = LoggerManager::getLogger('test');
/*6*/ if ("" != $str) {
???????? $logger->debug("str的值不为空! 它的值为: " . $str . "<br>");
????? }
/*7*/ if (strlen($str) > 4) {
?$logger->debug("str的长度大于4!" . "<br>");
????? }
/*8*/? LoggerManager::shutdown();
?>
[/php]
程序非常简单,来看看各处标记的作用:
1. 定义LOG4PHP_DIR目录名为log4php, 也就是我们目录结构中的log4php目录
2. 包含LoggerManager.php, 它是我们在程序中主要用到的类,通过它的getLogger()静态方法取得一个logger类,在第5处时使用这个类
3. 定义一个字串$str, 用来测试,在第6与第7处使用条件判断来产生logger的debug信息。
4. 这里代表着你的PHP输出,为了区别PHP程序输出与logger输出信息的不同,在这里先输出一条信息。
5. 通过LoggerManager类的getLogger()静态方法取得一个logger类,它的参数一般为类名,这个信息用来区别不同的logger记录,在这里我们只用到了一个测试类,因此这个名称我们可以定义为test, 当然你也可以定义为test1, test2...
6. 如果$str不为空则输出一条调试信息
7. 如果$str的长度超过4输出一条调试信息
OK,现在我们来执行一下http://localhost/test1.php. 不对,只有4处输出的语句而没有调试信息!怎么回事?原因是我们还没有设置log4php的配置文件!好,我这里有一个简单的配置文件,代码如下:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderEcho
log4php.appender.A1.layout=LoggerLayoutSimple
[/php]
先不用管这些代码是什么意思,在app目录中新建立一个log4php.properties文件,然后将以上的代码拷贝至这个文件里,保存。
注意:
?1. 这个文件的文件名必须是log4php.properties,不要写错
?2. 这个文件必需与index.php同级,也就是在app目录下
OK,执行完这一步继续执行http://localhost/test1.php,
这时我们将会看到这样的代码:
[php]
这里是PHP的输出, 与log4php无关哟!
DEBUG - str的值不为空! 它的值为: here is test string!
DEBUG - str的长度大于4!?
[/php]
?看到这里,有人就会说了,为什么上边会有两个注意的地方?我想把文件名改成log4.txt, 同时为了方便我还要把它的位置放在另一个地方,比如我的项目中有一个专门的配置文件目录config/,我想把log4.txt放在config/目录中, OK, 可以, 如果你这样做了,那么在test1.php中还需要在1处后边加一条语句:
[php]
define (LOG4PHP_CONFIGURATION, "/config/log4.txt");
[/php]
这里要说明的一定,因为log4php的属性文件采用的是properties格式,这种格式在JAVA中一般的扩展名为.properties, 因此我们还是将log4.txt的扩展名修改为log4.properties, 这样更符合习惯一些。log4php也支持XML格式定义的配置文件,不过一般说来XML文件的可读性较差,我在这里就统一使用properties格式的配置文件了。
?OK,高级的东西我们放到下边去看,我们来看执行后的页面,好像很简单一样,与echo 没什么两样,好,我们先不用知道为什么,先将log4.properties中的最后一条log4php.appender.A1.layout的值由LoggerLayoutSimple改为LoggerLayoutHtml, 保存后再执行http://localhost/test1.php看看,哈哈,现在是不是感觉舒服一些了?也对得起这自己花这么长时间来看这个东西了。后边所谓的高级使用也就是来详细说明这个配置文件的使用的。通过配置文件,我们可以使用一些更高级的功能,例如将日志写成文件等。
四、高级使用:
?Log4php由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将附加到执行文件尾还是文件中;而输出格式则控制了日志信息的显示内容。
?1. 日志的优先级,日志信息有四种分类(常用),可以通过在在配置文件中设置优先级来将代码中出现的调试信息显示或隐藏,举例来讲,当我把日志等级调整至WARN级时,那么程序中所出现的ERROR信息(通过$log->error("error message here!"))及WARN等级的信息可以记录出来,而程序中所有使用INFO与DEBUG级的信息都将不显示,它由
"log4php.rootLogger=DEBUG, A1"中rootLogger的第一个参数定义,这一句的意思是将调试等级定义为DEBUG级,也就是说程序中所有的ERROR, WARN,INFO, DEBUG信息都可以显示出来, 如果将等级设置为INFO, 那么只能有ERROR, WARN, INFO这三种信息可显示。
以下是常用四种等级的用法:
DEBUG Level指出细粒度信息事件对调试应用程序是非常有帮助的。
INFO level表明 消息在粗粒度级别上突出强调应用程序的运行过程。
WARN level表明会出现潜在错误的情形。
ERROR level指出虽然发生错误事件,但仍然不影响系统的继续运行。
FATAL level指出每个严重的错误事件将会导致应用程序的退出。
?2. 日志信息的输出目的地。在log4php中输出目的地支持12种,分别为:
[php]
1. LoggerAppenderConsole 以php://stdout为输出地
2. LoggerAppenderDailyFile 继承自LoggerAppenderFile, 以文件为输出地,每日输出一个文件
3. LoggerAppenderDb? 以数据库为输出地
4. LoggerAppenderEcho 在执行文件尾输出
5. LoggerAppenderFile 以文件为输出地
6. LoggerAppenderMail 以邮件为输出地
7. LoggerAppenderMailEvent 继承自LoggerAppenderMail, 以邮件为输出地, 为事件触发
8. LoggerAppenderNull: 不输出任何信息
9. LoggerAppenderPhp: 输出至PHP错误信息,将各类日志等级信息转化为php标准信息
10. LoggerAppenderRollingFile: 继承自LoggerAppenderFile,以xxx.log.1, xxx.log.2的形式输出,
11. LoggerAppenderSocket: 以socket方式输出
12. LoggerAppenderSyslog: 以系统日志为目的地输出,使用php中的syslog()函数进行记录
[/php]
在配置文件中表现为"log4php.rootLogger=DEBUG, A1" 从第二个参数起的别名,具体目的地的设置方式由:
[php]
log4php.appender.A1=LoggerAppenderEcho
log4php.appender.A1.layout=LoggerLayoutHtml
[/php]
来实现,每种输出目的地都有不同的设置参数,根据实际需要,输出的目的地可有多项,表现如下:
log4php.rootLogger=DEBUG, A1, A2, A3, ....
其中A1, A2, A3代表不同的输出目的地。
?
?3. 日志文件输出格式。它作为输出目的地的一个属性存在,log4php上包含5种不同的输出方式,分别为:
[php]
1. LoggerLayoutHtml: 以html格式输出调试信息
2. LoggerLayoutSimple: 简单的以 "等级信息 - 日志信息"的格式显示
3. LoggerLayoutTTCC: 以"月/日/年 时间[进程] 等级信息 日志名称 - 调试信息"的格式来显示
4. LoggerPatternLayout: 以模式表达式作为输出格式来显示(这个功能极为强悍,你可以随心所欲的来设置输出格式,在实例部分详细讲解)
5. LoggerXmlLayout: 以xml的模式来输出
[/php]
?这里所谓的高级使用也就是log4php中的配置文件的使用,所有的高级功能都要由配置文件来完成,我每讲一个功能的使用,都有一个示例文件,大家可以边看教程边进行调试, 在这里我将以几种常见的输出目的地为例进行讲解,详细的内容大家可以查看log4php解压目录里的test目录。
?
1. LoggerAppenderEcho:定义方式:
[php]?
log4php.appender.A1=LoggerAppenderEcho
log4php.appender.A1.layout=LoggerLayoutHtml
[/php]
?log4php.appender是固定格式,A1代表输出地的别名,log4php.appender.A1为输出地,这里为直接回显,log4php.appender.A1.layout定义直接回显时的格式,在这里取值可以是5种输出格式, 当前设置表示使用HTML来输出DEBUG信息,当A1的layout配置为LoggerLayoutHtml后,它还有两个附加参数可定义(请记住:这里的参数指的是为LoggerLayoutHmtl设置为不是为LoggerAppenderEcho,是为输出格式设置参数而不是为输出目的地设置参数),分别为:
?1. locationInfo: 输出本地信息,值为boolean
?2. title:输出html的标题名,也就是输出HTML中的<title></title>中的名称, 字符串
完整配置示例如下:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderEcho
log4php.appender.A1.layout=LoggerLayoutHtml
log4php.appender.A1.layout.locationInfo=true
log4php.appender.A1.layout.title=这里是测试实例1
[/php]
?本节实例为log_echo.php.
2. LoggerAppenderFile:
定义格式:
[php]
log4php.appender.A1=LoggerAppenderFile
log4php.appender.A1.layout=LoggerLayoutHtml
[/php]
同样,这里表示输出地为File, 输出的格式为loggerLayoutHtml. 当输出目的地为LoggerAppenderFile时还要进行设置几个参数:
?1. file: 要输出的文件名, 字符串
?2. append:是否每次记录时添加至文件尾部,值为boolean, 为true时不清除原有数据,为false时清除原有记录。
完整的设置模式为:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderFile
log4php.appender.A1.file=logs/log4php_file.log.html
log4php.appender.A1.append=false
log4php.appender.A1.layout=LoggerLayoutHtml
log4php.appender.A1.layout.locationInfo=true
log4php.appender.A1.layout.title=这里是测试实例1
[/php]
很明显示,这里的A1.append应该设置为false, 因为是HTML格式输出,如果为true的话文件里每次都会将整个HTML信息写入。不过有个遗憾就是log4php对中文的支持不是很好,生成的HTML文件title的中文正确,调试信息的中文全部为乱码。这一点注意。
?本节实例为log_file.php.
3. LoggerAppenderDailyFile:
定义格式:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderDailyFile
log4php.appender.A1.layout=LoggerLayoutSimple
[/php]
?通过设置log4php.appender.A1的值使用日志文件按时间输出,同时这里的输出方式选择最简单的LoggerLayoutSimple. 当选择LoggerAppenderDailyFile为输出目的地时需要设置以下几个参数:
?1. file: 输出文件名,采用"文件名_%s.log"这样的形式来输出,尾部的%s表示附带的时间,时间的定义格式为下面的参数
?2. datePattern:时间格式,表示将当前日期格式化为字串型代换文件名的中的%s.
完整设置模式为:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderDailyFile
log4php.appender.A1.datePattern=Ymd
log4php.appender.A1.file=logs/log4php_dailyfile_%s.log
log4php.appender.A1.append=true
log4php.appender.A1.layout=LoggerLayoutSimple
[/php]
?输出格式为LoggerLayoutSimple表示我以简单的“[等级信息] - 调试信息”这样的格式写入.
?本节实例为log_dailyfile.php
4. LoggerAppenderRollingFile:
定义格式:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderRollingFile
log4php.appender.A1.layout=LoggerLayoutSimple
[/php]
?表示按序列号排列文件,当日志文件大小超过最大定义时备份旧日志并重写新日志
来看看它的相关参数:
?1. file: 要输出的文件名 字符串型
?2. maxFileSize: 日志文件最大字节数? 格式为:数值k
?3. maxBackupIndex: 最大序列数 为日志文件.后边的最大数值? 数值型。
完整体的配置文件如下:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderRollingFile
log4php.appender.A1.file=logs/log4php_rollingfile.log
log4php.appender.A1.maxFileSize=5KB
log4php.appender.A1.maxBackupIndex=5
log4php.appender.A1.layout=LoggerLayoutSimple
[/php]
?这里为演示将maxFileSize调整为5KB, 实际使用中请按需设置. 其它可选单位为KB,MB,GB.
? 本节实例为log_rollingfile.php.
5. LoggerPatternLayout输出格式详解:
?这里我们的输出目的地设置为最简单的LoggerAppenderEcho, 来看看如何在layout层使用LoggerPatternLayout:
完整体配置文件:
[php]
log4php.rootLogger=DEBUG, A1
log4php.appender.A1=LoggerAppenderEcho
log4php.appender.A1.layout=LoggerPatternLayout
log4php.appender.A1.layout.conversionPattern=%-5p %d %t %m in %F line %L%n
[/php]
?关于conversionPattern中参数的作用如下:
?* c: 当前logger名称,通过LoggerManager::getLogger($cateName)传入的$cateName值
?* C: 当前的完整体的类名称(产生log信息的类,log4php中类名)
?* d: 当前时间
?* F: 当前文件名
?* l: 产生日志信息的类
?* L: 产生日志信息的行数
?* n: 换行
?* m: 调试信息
?* M: 产生日志信息的方法名
?* p: 日志等级信息
?* r: 执行时间ms数
?* t: 产生日志信息的线程
?* x: NDC (nested diagnostic context)
?* X: MDC (mapped diagnostic context)
???? 这里0.9的版本中有一个bug, %F与%L不能正常显示值,通过只需要修改log4php\spi\LoggerLoggingEvent.php 189和190行:
[php]
?189?????????????????? $className = @$hop['class'];
?190?????????????????? if ( !empty($className) and ($className == 'logger' or get_parent_class($className) == 'logger') )
[/php]
更改为以下:
[php]
189??????????????????? $className = @strtolower($hop['class']);
190??????????????????? if ( !empty($className) and ($className == 'logger' or $className == 'loggercategory' or? get_parent_class($className) == 'logger') or get_parent_class($className) == 'loggercategory')
[/php]
?(摘自:http://ipis007.spaces.live.com/blog/cns!75F0E4FEE274140B!1056.entry, 原作中错误文件为LoggerLocationInfo.php, 实际应为LoggerLoggingEvent.php)
6. 多输出地设置:
?有了上边的知道,多输出地的设置自然也就明白了,来看一个配置文件:
[php]
log4php.rootLogger=DEBUG, A1, A2
log4php.appender.A1=LoggerAppenderEcho
log4php.appender.A1.layout=LoggerPatternLayout
log4php.appender.A1.layout.conversionPattern="%-5p %l %d %c %t %m in %F line %L%n"
log4php.appender.A2=LoggerAppenderFile
log4php.appender.A2.file=logs/log4php_mutil.log
log4php.appender.A2.append=false
log4php.appender.A2.layout=LoggerPatternLayout
log4php.appender.A2.layout.conversionPattern="%-5p %l %d %c %t %m in %F line %L%n"
[/php]
?相信大家能够明白上边的配置文件了,多余的就不说了,这里的输出地别名A1, A2你可以自已定义,你可这样定义File, Echo...
五 log4php在phpsa框架中的应用
?phpsa3.0开始集成log4php进行调试工作, 框架级的调试信息等级为INFO, 用户定义模块中可以使用DEBUG等级进行输出日志信息, 想要了解框架的结构时可将/comm/config/log4php.properties中的log4php.rootLogger的属性设置为DEBUG, 默认为DEBUG级, 需要指明的是它们的优先级从高到低分别是ERROR、WARN、INFO、DEBUG, 如果不想看到系统输出的debug信息可将调试等级设置为INFO, 在模块文件中使用$this->logger->info("xxxx")来输出info信息.
?在phpsa框架中的大多数类都在关键方法中加入deub()日志信息, 用来记录框架的执行顺序. 在Object类中logger进行初始化, 在其继承类中进行调用. 框架使用config::IS_LOG来记录是否使用log4php, 在实际的开发中, 我们可以将这个变量的值设置为true进行日志输出, 发布时要将此值设置为false以获得更好的性能.
?在Object的构造函数中也使用if语句进行类库的加载与初始化工作:
[php]
if ($this->isLog) {
?require_once ($_SERVER['DOCUMENT_ROOT'] . "/comm/config/phpsaLogger.inc.php");
?$this->logger = LoggerManager::getLogger($this->toString());
}
[/php]
?在用户自定义的模块中我们可以这样进行初始化:
?if (Config::IS_LOG) {
??$this->logger = LoggerManager::getLogger($this->toString());
?}
?这样调用:
?if (Config::IS_LOG) {
??$this->logger->info("here is debug info...");
?}