首页 > PHP开发 > Yii1 > Yii框架官方教程增补版45——专题:日志记录
2014
11-07

Yii框架官方教程增补版45——专题:日志记录

Yii 提供了一个灵活可扩展的日志功能。记录的日志 可以通过日志级别和信息分类进行归类。通过使用 级别和分类过滤器,所选的信息还可以进一步路由到 不同的目的地,例如一个文件,Email,浏览器窗口等。

1. 信息记录

信息可以通过 Yii::log 或 Yii::trace 记录。其区别是后者只在当应用程序运行在调试模式(debug mode) 中时才会记录信息。

Yii::log($message, $level, $category);
Yii::trace($message, $category);

当记录信息时,我们需要指定它的分类和级别 分类是一段格式类似于路径别名的字符串。 例如,如果一条信息是在 CController 中记录的,我们可以使用 system.web.CController 作为分类。信息级别应该是下列值中的一种:

  • trace: 这是在 Yii::trace 中使用的级别。它用于在开发中 跟踪程序的执行流程。
  • info: 这个用于记录普通的信息。
  • profile: 这个是性能概述(profile)。下面马上会有更详细的说明。
  • warning: 这个用于警告(warning)信息。
  • error: 这个用于致命错误(fatal error)信息。

2. 信息路由

通过 Yii::log 或 Yii::trace 记录的信息是保存在内存中的。 我们通常需要将它们显示到浏览器窗口中,或者将他们保存到一些 持久存储例如文件、Email中。这个就叫作信息路由,例如, 发送信息到不同的目的地。

在 Yii 中,信息路由是由一个叫做 CLogRouter 的应用组件管理的。 它负责管理一系列称作日志路由的东西。每个日志路由 代表一个单独的日志目的地。通过一个日志路由发送的信息会被他们的级别和分类过滤。

要使用信息路由,我们需要安装并预加载一个 CLogRouter 应用组件。我们也还需要配置它的 routes 属性为我们想要的那些日志路由。 下面的代码演示了一个所需的 应用配置 示例:

array(
    ......
    'preload'=>array('log'),
    'components'=>array(
        ......
        'log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                array(
                    'class'=>'CFileLogRoute',
                    'levels'=>'trace, info',
                    'categories'=>'system.*',
                ),
                array(
                    'class'=>'CEmailLogRoute',
                    'levels'=>'error, warning',
                    'emails'=>'admin@example.com',
                ),
            ),
        ),
    ),
)

在上面的例子中,我们定义了两个日志路由。第一个是 CFileLogRoute ,它会把信息保存在位于应用程序 runtime 目录中的一个文件中。 而且只有级别为 trace 或 info 、分类以 system. 开头的信息才会被保存。 第二个路由是 CEmailLogRoute ,它会将信息发送到指定的 email 地址,且只有级别为 error 或 warning 的才会发送。

在 Yii 中,有下列几种日志路由可用:

  • CDbLogRoute: 将信息保存到数据库的表中。
  • CEmailLogRoute: 发送信息到指定的 Email 地址。
  • CFileLogRoute: 保存信息到应用程序 runtime 目录中的一个文件中。
  • CWebLogRoute: 将 信息显示在当前页面的底部。
  • CProfileLogRoute: 在页面的底部显示概述(profiling)信息。

信息: 信息路由发生在当前请求周期最后的 onEndRequest 事件触发时。 要显式终止当前请求过程,请调用 CApplication::end() 而不是使用 die() 或 exit(),因为 CApplication::end() 将会触发onEndRequest 事件, 这样信息才会被顺利地记录。

3. 信息过滤

正如我们所提到的,信息可以在他们被发送到一个日志路由之前通过它们的级别和分类过滤。 这是通过设置对应日志路由的 levels 和 categories 属性完成的。 多个级别或分类应使用逗号连接。

由于信息分类是类似 xxx.yyy.zzz 格式的,我们可以将其视为一个分类层级。 具体地,我们说 xxx 是 xxx.yyy的父级,而xxx.yyy 又是 xxx.yyy.zzz 的父级。 这样我们就可以使用 xxx.* 表示分类 xxx 及其所有的子级和孙级分类。

4. 记录上下文信息

从版本 1.0.6 起,我们可以设置记录附加的上下文信息, 比如 PHP 的预定义变量(例如 $_GET, $_SERVER),session ID,用户名等。 这是通过指定一个日志路由的 CLogRoute::filter属性为一个合适的日志过滤规则实现的。

框架使用非常方面的可以用于大多数日志过滤的CLogFilter,默认情况下, CLogFilter 将会记录一条包含变量(如通常包含系统上下文变量值的如$_GET,$_SERVER等)的信息。CLogFilter还可以用于配置到每一个日志信息之前,带上session ID,用户名等。当我们要查找日志信息的位置时这将带来极大的便利 。

下面的配置展示了如何开启记录上下文信息。每一个日志路由都有自己的日志过滤器,但是默认情况下, 日志路由并不包含日志过滤器。

array(
    ......
    'preload'=>array('log'),
    'components'=>array(
        ......
        'log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                array(
                    'class'=>'CFileLogRoute',
                    'levels'=>'error',
                    'filter'=>'CLogFilter',
                ),
                ...other log routes...
            ),
        ),
    ),
)

从版本1.0.7开始,Yii支持记录通过调用Yii::trace返回的日志记录信息中的回调栈信息。这一特性默认是取消的,因为这回降低性能。想要使用这一特性,只需在入口脚本中定义一个名为YII_TRACE_LEVEL的大于0的常量 (在包含yii.php之前),然后Yii将会在每一个trace信息之后加上应用代码回调栈的文件名和行号。 YII_TRACE_LEVEL 决定了每一个回调栈的层级将会被记录。这个信息在开发期间很有用,因为这可以帮助我们确定触发trace信息的位置。

5. 性能分析

性能分析是一个特殊的日志记录类型。性能分析可以用于衡量指定代码块的运行时间,并且找出性能瓶颈。

使用性能分析,我们需要指定被分析的代码块。我们通过插入如下代码来标记每一个代码块的开始和结束:

Yii::beginProfile('blockID');
...code block being profiled...
Yii::endProfile('blockID');

其中blockID 指的是代码块的唯一标志符.

注意, 代码块需要被合理嵌套。也就是说,一个代码块不能和另一代码块交叉嵌套:要么是并行的,要么是完全封闭包含在另一个代码块里。

为了显示分析结果, 需要安装 一个包含CProfileLogRoute日志路由的CLogRouter 应用组件。这和我们处理其他的信息路由一样,CProfileLogRoute路由将会在当前页面的底部显示性能分析结果。

profile

6. SQL执行分析

性能分析在处理数据库操作时尤为有用,因为 SQL 执行经常是一个应用主要的性能瓶颈。 我们当然可以在每一次SQL执行的地方插入beginProfile 和 endProfile语句, 从版本1.0.6开始, 但Yii 提供了一个更加系统的方式来解决这个问题。

通过在应用配置中设置 CDbConnection::enableProfiling 为true, 每一个被执行的SQL语句都会被分析. 结果可以通过设置前面提到的CProfileLogRoute来显示, 这样我们就能知晓每一个SQL语句的执行时间。除此之外我们还可以调用CDbConnection::getStats() 来取回SQL语句执行的次数和总的执行时间。

编程技巧