使用不同的日志路由

当你没有机会调试它的时候,打日志对于理解应用真正做了些什么非常关键。不管你是否相信,尽管你能100%确信你的应用将会按照你期望的执行,在生产环境中,它可以做很多你意识不到的事情。这没关系,因为没有人可以注意到任何事情。因此,如果我们期望不寻常的行为,我们需要立刻知道并有足够的信息来重现它。这就是日志派上用场的原因。

Yii允许一个开发者不止可以输出日志消息,也能根据消息的级别和种类进行不同的处理。例如,你可以将一条消息写入到数据库,发送一个电子邮件或者将它展示到浏览器中。

在本小节中,我们将会以更明智的方法处理日志消息:最重要的信息通过邮件发送,不太重要的信息会被保存到的文件A和B中,profiling将会被路由到Firebug中。此外,在开发模式下,所有的消息和profiling信息将会展示在屏幕上。

准备

按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。

如何做…

执行如下步骤:

  1. 使用config/web.php配置日志:
  1. 'components' => [
  2. 'log' => [
  3. 'traceLevel' => 0,
  4. 'targets' => [
  5. [
  6. 'class' => 'yii\log\EmailTarget',
  7. 'categories' => ['example'],
  8. 'levels' => ['error'],
  9. 'message' => [
  10. 'from' => ['log@example.com'],
  11. 'to' => ['developer1@example.com',
  12. 'developer2@example.com'],
  13. 'subject' => 'Log message',
  14. ],
  15. ],
  16. [
  17. 'class' => 'yii\log\FileTarget',
  18. 'levels' => ['error'],
  19. 'logFile' => '@runtime/logs/error.log',
  20. ],
  21. [
  22. 'class' => 'yii\log\FileTarget',
  23. 'levels' => ['warning'],
  24. 'logFile' => '@runtime/logs/warning.log',
  25. ],
  26. [
  27. 'class' => 'yii\log\FileTarget',
  28. 'levels' => ['info'],
  29. 'logFile' => '@runtime/logs/info.log',
  30. ],
  31. ],
  32. ],
  33. 'db' => require(__DIR__ . '/db.php'),
  34. ],
  1. 现在,我们会在protected/controllers/LogController.php中生成一些消息:
  1. <?php
  2. namespace app\controllers;
  3. use yii\web\Controller;
  4. use Yii;
  5. class LogController extends Controller
  6. {
  7. public function actionIndex()
  8. {
  9. Yii::trace('example trace message', 'example');
  10. Yii::info('info', 'example');
  11. Yii::error('error', 'example');
  12. Yii::trace('trace', 'example');
  13. Yii::warning('warning','example');
  14. Yii::beginProfile('preg_replace', 'example');
  15. for($i=0;$i<10000;$i++){
  16. preg_replace('~^[ a-z]+~', '', 'test it');
  17. }
  18. Yii::endProfile('preg_replace', 'example');
  19. return $this->render('index');
  20. }
  21. }

以及视图views/log/index.php

  1. <div class="log-index">
  2. <h1>Log</h1>
  3. </div>
  1. 现在多次运行先前的动作。在屏幕上,你应该看到Log头和一个有日志消息数字的调试面板:

使用不同的日志路由 - 图1

  1. 如果你点击17,你将会看到一个web日志,如下图所示:

使用不同的日志路由 - 图2

  1. 一条日志包含我们打的所有信息,堆栈踪迹、时间戳、级别和分类。
  2. 现在打开Profiling页面。你应该能看到profiling消息,如下截图所示:

使用不同的日志路由 - 图3

profiling信息展示了我们代码块的所有执行时长。

  1. 因为我们刚刚修改了日志文件的名称,而不是路径,你应该能在runtime/logs中找到日志文件error.logwarning.loginfo.log
  2. 打开文件你将会看到如下消息:
  1. 2016-03-06 07:28:35 [127.0.0.1][-][-][error][example] error
  2. ...
  3. 2016-03-06 07:28:35 [127.0.0.1][-][-][warning][example] warning
  4. ...
  5. 2016-03-06 07:28:35 [127.0.0.1][-][-][info][example] info

工作原理…

当使用Yii::erorrYii::warningYii::info或者Yii::trace打日志时,Yii将它传递给了日志路由。

依赖于如何配置,它会将消息发送给一个或多个目标,例如,通过电子邮件发送错误信息、将调试信息写入到文件A中、将警告信息写入到文件B中。

yii\log\Dispatcher类的对象通常被附加在一个名叫log的应用组件上。因此,为了配置它,我们应该在配置文件组件部分设置它的属性。这里唯一可配的属性是targets,它包含了一组日志路由和他们的配置。

我们已经定义了四个日志路由。这里回顾一下:

  1. [
  2. 'class' => 'yii\log\EmailTarget',
  3. 'categories' => ['example'],
  4. 'levels' => ['error'],
  5. // 'mailer' => 'mailer',
  6. 'message' => [
  7. 'from' => ['log@example.com'],
  8. 'to' => ['developer1@example.com', 'developer2@example.com'],
  9. 'subject' => 'Log error',
  10. ],
  11. ],

EmailTarget默认通过Yii::$app->mailer组件发送一封电子邮件来发送日志消息。我们将类别限制为example,并将级别限制为error。电子邮件将会从log@example.com发送给两个开发者,且主题是Log error

  1. [
  2. 'class' => 'yii\log\FileTarget',
  3. 'levels' => [warning],
  4. 'logFile' => '@runtime/logs/warning.log',
  5. ],

FileTarget将错误消息发送到一个指定的文件。我们将消息级别限制为warning,并使用一个名叫warning.log的文件。同样我们将info级别的消息存放在Info.log文件中。

此外,我们可以使用yii\log\SyslogTarget将消息写到Unix /var/log/syslog系统文件中,或者使用yii\log\DbTarget将消息写入到数据库中。对于第二种情况,你必须应用他们的migration:

  1. ./yii migrate --migrationPath=@yii/log/migrations/

更多…

关于Yii打日志有很多有趣的东西,在接下来的部分中进行讨论。

Yii::trace和Yii::getLogger()->log

Yii::trace是对Yii::log的封装:

  1. public static function trace($message, $category = 'application')
  2. {
  3. if (YII_DEBUG) {
  4. static::getLogger()->log($message, Logger::LEVEL_TRACE, $category);
  5. }
  6. }

因此,如果Yii在debug模式下,Yii::trace使用trace级别来打日志。

Yii::beginProfile和Yii::endProfile

这些方法被用于测量应用中部分代码的执行时间。在我们的LogController中,我们测量了preg_replace执行10000次所用的时间:

  1. Yii::beginProfile('preg_replace', 'example');
  2. for($i=0;$i<10000;$i++){
  3. preg_replace('~^[ a-z]+~', '', 'test it');
  4. }
  5. Yii::endProfile('preg_replace', 'example');

Yii::beginProfile标记用于profiling的代码块开头。我们必须为每一个代码块设置一个唯一的token,以及指定一个可选的分类:

  1. public static function beginProfile($token, $category = 'application') { }

Yii::endProfile可以匹配到先前调用有相同的分类名的beginProfile

  1. public static function endProfile($token, $category = 'application') { }

begin-end-调用也必须被正确的嵌套。

立即打日志消息

默认情况下,Yii会将所有的日志消息存放在内存中,知道应用终止。这是为了性能考虑,并且一般都能运行良好。

但是,如果一个控制台应用需要长时间运行,日志消息将不会被立刻写出。为了确保你的消息能在任何时候都被打印出来,你可以使用Yii::$app->getLogger()>flush(true)显式刷新,或者为你的控制台应用配置修改flushIntervalexportInterval

  1. 'components' => [
  2. 'log' => [
  3. 'flushInterval' => 1,
  4. 'targets' =>[
  5. [
  6. 'class' => 'yii\log\FileTarget',
  7. 'exportInterval' => 1,
  8. ],
  9. ],
  10. ],
  11. ],

参考