第十二章 调试,日志和错误处理

在本章中,我们将会讨论如下话题:

  • 使用不同的日志路由
  • 分析Yii错误堆栈踪迹
  • 打日志并使用上下文信息
  • 展示自定义错误
  • 为调试扩展自定义面板

介绍

如果应用比较复杂,创建一个没有bug的应用几乎是不可能的,所以开发者必须检测错误并能迅速的处理他们。Yii有一套实用的特性,可以处理日志和错误。而且,在调试模式下,如果发生错误,Yii可以给出堆栈踪迹。实用它,你可以非常迅速的修复错误。

在本章中,我们将会回顾日志,分析异常的堆栈踪迹,并实现自己的错误处理。

使用不同的日志路由

当你没有机会调试它的时候,打日志对于理解应用真正做了些什么非常关键。不管你是否相信,尽管你能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. ],

参考

分析Yii错误堆栈踪迹

当发生错误时,Yii可以展示错误信息以及错误堆栈踪迹。当我们需要知道究竟是什么原因导致的错误时,堆栈踪迹非常有用。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 配置一个数据库,并使用如下migration导入:
  1. <?php
  2. use yii\db\Migration;
  3. class m160308_093234_create_article_table extends Migration
  4. {
  5. public function up()
  6. {
  7. $this->createTable('{{%article}}', [
  8. 'id' => $this->primaryKey(),
  9. 'alias' => $this->string()->notNull(),
  10. 'title' => $this->string()->notNull(),
  11. 'text' => $this->text()->notNull(),
  12. ]);
  13. }
  14. public function down()
  15. {
  16. $this->dropTable('{{%article}}');
  17. }
  18. }
  1. 使用Yii生成一个Article模型。

如何做…

执行如下步骤:

  1. 现在我们需要创建一些代码。创建protected/controllers/ErrorController.php
  1. <?php
  2. namespace app\controllers;
  3. use app\models\Article;
  4. use yii\web\Controller;
  5. class ErrorController extends Controller
  6. {
  7. public function actionIndex()
  8. {
  9. $article = $this->findModel('php');
  10. return $article->title;
  11. }
  12. private function findModel($alias)
  13. {
  14. return Article::findOne(['allas' => $alias]);
  15. }
  16. }
  1. 运行过先前的动作以后,我们应该能得到如下错误:

第十二章 调试,日志和错误处理 - 图4

  1. 而且,堆栈踪迹展示了如下错误:

第十二章 调试,日志和错误处理 - 图5

工作原理…

从错误消息中,我们知道在数据库中,我们没有列的别称,但是我们已经再代码别的地方用到了它。在我们的例子中,这很容易通过搜索所有的文件来找到,但是在一个大项目中,一个列可以存放在一个变量中。而且,we have everything to fix an error without leaving the screen where the stack trace is displayed。我们只是需要小心的读它。

堆栈踪迹逆序地展示了一个调用链条,以产生错误的一个开始。一般来说,我们不需要看所有的踪迹来了解发生了什么。这个框架代码本身已经充分测试了,所以发生错误的可能性是比较小的。这就是为什么Yii展示应用的踪迹是打开的,而框架的踪迹是折叠的。

因此,我们使用第一个展开的部分,并查找别称。找到以后,我们可以立刻告诉你它被用于ErrorController.php的第19行中。

参考

日志和使用上下文信息

有时,一个错误信息不足以修复一个错误。例如,如果你使用最佳实践,并且使用所有可能的错误来开发和测试一个应用,你可以得到一个错误信息。但是,没有执行的上下文,它只是告诉你这里有一个错误,并不清楚究竟是什么导致的。

在我们的例子中,我们将会使用一个非常简单并且代码编写很烂的动作,它会输出Hello <username>!,其中username直接从$_GET中获取。

准备

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

如何做…

执行如下步骤:

  1. 首先,我们需要一个控制器。因此,创建protected/controllers/LogController.php
  1. <?php
  2. namespace app\controllers;
  3. use yii\web\Controller;
  4. class LogController extends Controller
  5. {
  6. public function actionIndex()
  7. {
  8. return 'Hello, ' . $_GET['username'];
  9. }
  10. }
  1. 现在,如果我们运行index动作,我们将会得到一个错误信息,Undefined index: username。配置logger将这样的错误写入到文件:
  1. config/web.php
  1. 'components'=>[
  2. ...
  3. 'log' => [
  4. 'targets' => [
  5. [
  6. 'class' => 'yii\log\FileTarget',
  7. 'levels' => ['error'],
  8. 'logFile' => '@runtime/logs/errors.log',
  9. ],
  10. ],
  11. ],
  12. ],
  1. 在次运行index动作,并检查runtime/logs/errors.log。将会有如下日志信息:
  1. 2016-03-06 09:27:09 [127.0.0.1][-][-][error][yii\base\
  2. ErrorException:8] exception 'yii\base\ErrorException' with
  3. message 'Undefined index: username' in /controllers/
  4. LogController.php:11
  5. Stack trace:
  6. #0 /yii2/base/InlineAction.php(55): ::call_user_func_array()
  7. #1 /yii2/base/Controller.php(151): yii\base\
  8. InlineAction->runWithParams()
  9. #2 /yii2/base/Module.php(455): yii\base\Controller->runAction()
  10. #3 /yii2/web/Application.php(84): yii\base\Module->runAction()
  11. #4 /yii2/base/Application.php(375): yii\web\
  12. Application->handleRequest()
  13. #5 /web/index.php(12): yii\base\Application->run()
  14. #6 {main}
  15. 2016-03-06 09:27:09 [127.0.0.1][-][-][info][application] $_GET
  16. = [
  17. 'r' => 'log/index'
  18. ]
  19. $_COOKIE = [
  20. '_csrf' => 'ca689043348e...a69ea:2:{i:0;s:...\"DSS...KJ\";}'
  21. 'PHPSESSID' => '30584oqhat4ek8b0hrqsapsbf4'
  22. ]
  23. $_SERVER = [
  24. 'USER' => 'www-data'
  25. 'HOME' => '/var/www'
  26. 'FCGI_ROLE' => 'RESPONDER'
  27. 'QUERY_STRING' => 'r=log/index'
  28. ...
  29. 'PHP_SELF' => '/index.php'
  30. 'REQUEST_TIME_FLOAT' => 1459934829.3067
  31. 'REQUEST_TIME' => 1459934829
  32. ]
  1. 现在我们可以将我们的应用给一个测试组并不时的检查错误日志。默认情况下,错误报告日志包含了$_GET$_POST$_FILES$_COOKIE$_SESSION$_SERVER变量中的所有的值。如果你不希望展示所有的值,你可以指定一个自定义的变量列表:
  1. 'log' => [
  2. 'targets' => [
  3. [
  4. 'class' => 'yii\log\FileTarget',
  5. 'levels' => ['error'],
  6. 'logVars' => ['_GET', '_POST'],
  7. 'logFile' => '@runtime/logs/errors.log',
  8. ],
  9. ],
  10. ],
  1. 在这个例子中,报告只包含$_GET$_POST两个数组:
  1. ...
  2. 2016-04-06 09:49:08 [127.0.0.1][-][-][info][application] $_GET
  3. = [ 'r' => 'log/index' ]

工作原理…

Yii在打印错误日志信息时,添加了执行上下文和环境的完整信息。如果我们手动打一个日志消息,我们可能知道我们需要的信息,所以我们可以设置一些目标选项来我们真正需要的东西:

  1. 'log' => [
  2. 'targets' => [
  3. [
  4. 'class' => 'yii\log\FileTarget',
  5. 'levels' => ['error'],
  6. 'logVars' => ['_GET', '_POST'],
  7. 'logFile' => '@runtime/logs/errors.log',
  8. ],
  9. ],
  10. ],

先前的代码会将错误日志写到一个名叫errors的文件中,此外对于消息本身,它会将$_GET$_POST变量的内容打到日志中,如果这两个变量不为空的话。

参考

展示自定义错误

在Yii中,错误处理是非常灵活的,所以你可以为一种特定的错误创建你自己的错误处理方法。在这个小结中,我们将会以一个非常灵敏的方法处理一个404找不到的错误。我们将会展示一个404页面,它会基于输入栏中输入的内容提供建议的内容。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 添加失败动作到你的SiteController
  1. class SiteController extends Controller
  2. {
  3. // …
  4. public function actionFail()
  5. {
  6. throw new ServerErrorHttpException('Error message example.');
  7. }
  8. }
  1. 添加如下内容到web/.htaccess
  1. RewriteEngine on
  2. RewriteCond %{REQUEST_FILENAME} !-f
  3. RewriteCond %{REQUEST_FILENAME} !-d
  4. RewriteRule . index.php
  1. config/web.php文件中为urlManager组件配置友好的URL:
  1. 'components' => [
  2. // …
  3. 'urlManager' => [
  4. 'enablePrettyUrl' => true,
  5. 'showScriptName' => false,
  6. ],
  7. ],
  1. 对于不存在的URL,展示Not found异常:

第十二章 调试,日志和错误处理 - 图6

  1. 同时,在我们的actionFail中展示Internal Server Error异常:

第十二章 调试,日志和错误处理 - 图7

  1. 现在我们希望为Not Found页面创建一个自定义页面。

如何做…

现在我们需要修改Not Found页面的内容,但不考虑其它错误类型。为了达到这个目标,执行如下步骤:

  1. 打开SiteController类并找到actions()方法:
  1. class SiteController extends Controller
  2. {
  3. // ...
  4. public function actions()
  5. {
  6. return [
  7. 'error' => [
  8. 'class' => 'yii\web\ErrorAction',
  9. ],
  10. 'captcha' => [
  11. 'class' => 'yii\captcha\CaptchaAction',
  12. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  13. ],
  14. ];
  15. }
  16. // ...
  17. }
  1. 移除默认的error部分,actions()如下所示:
  1. <?php
  2. class SiteController extends Controller
  3. {
  4. // ...
  5. public function actions()
  6. {
  7. return [
  8. 'captcha' => [
  9. 'class' => 'yii\captcha\CaptchaAction',
  10. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  11. ],
  12. ];
  13. }
  14. // ...
  15. }
  1. 添加自己的actionError()方法:
  1. class SiteController extends Controller
  2. {
  3. // ...
  4. public function actionError()
  5. {
  6. }
  7. }
  1. 打开原始的\yii\web\ErrorAction类,复制它的动作内容到我们的actionError()中,并自定义它用于渲染自定义error-404视图,从而展示404错误码的Not Found错误:
  1. <?php
  2. // ...
  3. use yii\base\Exception;
  4. use yii\base\UserException;
  5. class SiteController extends Controller
  6. {
  7. // ...
  8. public function actionError()
  9. {
  10. if (($exception =
  11. Yii::$app->getErrorHandler()->exception)== null) {
  12. $exception = new HttpException(404, Yii::t('yii',
  13. 'Page not found.'));
  14. }
  15. if ($exception instanceof HttpException) {
  16. $code = $exception->statusCode;
  17. } else {
  18. $code = $exception->getCode();
  19. }
  20. if ($exception instanceof Exception) {
  21. $name = $exception->getName();
  22. } else {
  23. $name = Yii::t('yii', 'Error');
  24. }
  25. if ($code) {
  26. $name .= " (#$code)";
  27. }
  28. if ($exception instanceof UserException) {
  29. $message = $exception->getMessage();
  30. } else {
  31. $message = Yii::t('yii', 'An internal server error occurred.');
  32. }
  33. if (Yii::$app->getRequest()->getIsAjax()) {
  34. return "$name: $message";
  35. } else {
  36. if ($code == 404) {
  37. return $this->render('error-404');
  38. } else {
  39. return $this->render('error', [
  40. 'name' => $name,
  41. 'message' => $message,
  42. 'exception' => $exception,
  43. ]);
  44. }
  45. }
  46. }
  47. }
  1. 使用一个自定义消息添加views/site/error-404.php视图文件:
  1. <?php
  2. use yii\helpers\Html;
  3. /* @var $this yii\web\View */
  4. $this->title = 'Not Found!'
  5. ?>
  6. <div class="site-error-404">
  7. <h1>Oops!</h1>
  8. <p>Sorry, but requested page not found.</p>
  9. <p>
  10. Please follow to <?= Html::a('index page', ['site/index'])?>
  11. to continue reading. Thank you.
  12. </p>
  13. </div>
  1. 现在尝试访问不存在的URL,就能看到error-404.php视图中的内容:

第十二章 调试,日志和错误处理 - 图8

  1. 但是,对于一个失败的动作,我们能看到error.php文件中默认的内容:

第十二章 调试,日志和错误处理 - 图9

工作原理…

默认情况下,在yii2-app-basic应用中,我们在配置文件config/web.oho中为errorHandler组件配置errorActionsite/error。这意味着这个框架将会使用这个路由用于展示每一个被处理的异常:

  1. 'components' => [
  2. 'errorHandler' => [
  3. 'errorAction' => 'site/error',
  4. ],
  5. ],

SiteController类中,我们使用内置的yii\web\ErrorAction类,它会渲染所谓的error.php视图:

  1. class SiteController extends Controller
  2. {
  3. // ...
  4. public function actions()
  5. {
  6. return [
  7. 'error' => [
  8. 'class' => 'yii\web\ErrorAction',
  9. ],
  10. 'captcha' => [
  11. 'class' => 'yii\captcha\CaptchaAction',
  12. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  13. ],
  14. ];
  15. }
  16. // ...
  17. }

如果我们希望复写它的实现,我们可以 replace it in an inline actionError() method with our own custom content。

在这个小结中,我们添加了自己的if条件,用于渲染一个基于错误码的指定视图:

  1. if ($code == 404) {
  2. return $this->render('error-404');
  3. } else {
  4. return $this->render('error', [
  5. 'name' => $name,
  6. 'message' => $message,
  7. 'exception' => $exception,
  8. ]);
  9. }

同时,我们可以为Not Found页面使用一个自定义设计。

参考

为了了解更多Yii中的错误处理,参考http://www.yiiframework.com/doc-2.0/guide-runtime-handling-errors.html

为调试扩展自定义面板

Yii2-debug扩展是一个强大的工具,可以调试自己的代码,分析请求信息或者数据库查询等等。因此,你可以添加你自己的面板用于任何自定义报告。

准备

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

如何做…

  1. 在你的网站根路径中创建panels目录:
  2. 添加一个新的UserPanel类:
  1. <?php
  2. namespace app\panels;
  3. use yii\debug\Panel;
  4. use Yii;
  5. class UserPanel extends Panel
  6. {
  7. public function getName()
  8. {
  9. return 'User';
  10. }
  11. public function getSummary()
  12. {
  13. return Yii::$app->view->render('@app/panels/views/summary', ['panel' => $this]);
  14. }
  15. public function getDetail()
  16. {
  17. return Yii::$app->view->render('@app/panels/views/detail', ['panel' => $this]);
  18. }
  19. public function save()
  20. {
  21. $user = Yii::$app->user;
  22. return !$user->isGuest ? [
  23. 'id' => $user->id,
  24. 'username' => $user->identity->username,
  25. ] : null;
  26. }
  27. }
  1. 使用如下代码创建panels/view/summary.php
  1. <?php
  2. /* @var $panel app\panels\UserPanel */
  3. use yii\helpers\Html;
  4. ?>
  5. <div class="yii-debug-toolbar__block">
  6. <?php if (!empty($panel->data)): ?>
  7. <a href="<?= $panel->getUrl() ?>">
  8. User
  9. <span class="yii-debug-toolbar__label yii-debug-toolbar__label_info">
  10. <?= Html::encode($panel->data['username']) ?>
  11. </span>
  12. </a>
  13. <?php else: ?>
  14. <a href="<?= $panel->getUrl() ?>">Guest session</a>
  15. <?php endif; ?>
  16. </div>
  1. 使用如下代码创建panels/view/detail.php视图:
  1. <?php
  2. /* @var $panel app\panels\UserPanel */
  3. use yii\widgets\DetailView;
  4. ?>
  5. <h1>User profile</h1>
  6. <?php if (!empty($panel->data)): ?>
  7. <?= DetailView::widget([
  8. 'model' => $panel->data,
  9. 'attributes' => [
  10. 'id',
  11. 'username',
  12. ]
  13. ]) ?>
  14. <?php else: ?>
  15. <p>Guest session.</p>
  16. <?php endif;?>
  1. 在配置文件config/web.php中打开你的工具栏:
  1. if (YII_ENV_DEV) {
  2. $config['bootstrap'][] = 'debug';
  3. $config['modules']['debug'] = [
  4. 'class' => 'yii\debug\Module',
  5. 'panels' => [
  6. 'views' => ['class' => 'app\panels\UserPanel'],
  7. ],
  8. ];
  9. $config['bootstrap'][] = 'gii';
  10. $config['modules']['gii'] = 'yii\gii\Module';
  11. }
  1. 重新加载index页面,并在调试面板的末尾寻找游客Session

第十二章 调试,日志和错误处理 - 图10

  1. 使用admin用户名和admin密码登录到你的站点。在一个成功的例子中,你可以在主菜单中看到你的用户名:

第十二章 调试,日志和错误处理 - 图11

  1. 再次浏览调试面板。现在,你将会看到admin用户名:

第十二章 调试,日志和错误处理 - 图12

  1. 你可以点击调试面板中的用户名,并看到详细的用户信息:

第十二章 调试,日志和错误处理 - 图13

工作原理…

为了给yii2-debug模块创建我们自己的面板,我们需要扩展yii\debug\Panel类,并复写自己的模板方法;

  • getName():调试详情页的菜单项标签名
  • getSummary():调试面板格代码
  • getDetail():详细页视图代码
  • save():你的信息,将会被保存的调试存储中,并从$panel->data字段中获取

你的对象可以存储任何调试数据,并在摘要块和详情页中展示:

在我们的例子中,我们存储用户信息:

  1. public function save()
  2. {
  3. $user = Yii::$app->user;
  4. return !$user->isGuest ? [
  5. 'id' => $user->id,
  6. 'username' => $user->identity->username,
  7. ] : null;
  8. }

在摘要和详情页展示$panel->data字段中的数据。

处理事件

你可以订阅应用的任何事件,或者init()方法中的任何组件。例如,内置yii\debug\panels\MailPanel面板搜集和存储所有被发送的信息:

  1. class MailPanel extends Panel
  2. {
  3. private $_messages = [];
  4. public function init()
  5. {
  6. parent::init();
  7. Event::on(
  8. BaseMailer::className(),
  9. BaseMailer::EVENT_AFTER_SEND,
  10. function ($event) {
  11. $message = $event->message;
  12. $messageData = [
  13. // ...
  14. ];
  15. $this->_messages[] = $messageData;
  16. }
  17. );
  18. }
  19. // …
  20. public function save()
  21. {
  22. return $this->_messages;
  23. }
  24. }

同时,在我们自己的详情页中,它展示一个格子,里边是被存储消息的列表。

参考