Commit d0556a13 by Qiang Xue

debug toolbar WIP

parent 5892b265
...@@ -16,32 +16,34 @@ use yii\log\Target; ...@@ -16,32 +16,34 @@ use yii\log\Target;
*/ */
class LogTarget extends Target class LogTarget extends Target
{ {
/**
* @var Module
*/
public $module;
public $maxLogFiles = 20; public $maxLogFiles = 20;
public function __construct($module, $config = array())
{
parent::__construct($config);
$this->module = $module;
}
/** /**
* Exports log messages to a specific destination. * Exports log messages to a specific destination.
* Child classes must implement this method. * Child classes must implement this method.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/ */
public function export($messages) public function export()
{ {
$path = Yii::$app->getRuntimePath() . '/debug'; $path = Yii::$app->getRuntimePath() . '/debug';
if (!is_dir($path)) { if (!is_dir($path)) {
mkdir($path); mkdir($path);
} }
$file = $path . '/' . Yii::$app->getLog()->getTag() . '.log'; $tag = Yii::$app->getLog()->getTag();
$data = array( $file = "$path/$tag.log";
'messages' => $messages, $data = array();
'_SERVER' => $_SERVER, foreach ($this->module->panels as $panel) {
'_GET' => $_GET, $data[$panel->id] = $panel->save();
'_POST' => $_POST, }
'_COOKIE' => $_COOKIE,
'_FILES' => empty($_FILES) ? array() : $_FILES,
'_SESSION' => empty($_SESSION) ? array() : $_SESSION,
'memory' => memory_get_peak_usage(),
'time' => microtime(true) - YII_BEGIN_TIME,
);
file_put_contents($file, json_encode($data)); file_put_contents($file, json_encode($data));
} }
......
...@@ -18,19 +18,28 @@ use yii\helpers\Html; ...@@ -18,19 +18,28 @@ use yii\helpers\Html;
class Module extends \yii\base\Module class Module extends \yii\base\Module
{ {
public $controllerNamespace = 'yii\debug\controllers'; public $controllerNamespace = 'yii\debug\controllers';
public $panels; /**
* @var array|Panel[]
*/
public $panels = array();
public function init() public function init()
{ {
parent::init(); parent::init();
Yii::$app->log->targets['debug'] = new LogTarget;
foreach (array_merge($this->corePanels(), $this->panels) as $id => $config) {
$config['id'] = $id;
$this->panels[$id] = Yii::createObject($config);
}
Yii::$app->getLog()->targets['debug'] = new LogTarget($this);
Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar')); Yii::$app->getView()->on(View::EVENT_END_BODY, array($this, 'renderToolbar'));
} }
public function beforeAction($action) public function beforeAction($action)
{ {
Yii::$app->getView()->off(View::EVENT_END_BODY, array($this, 'renderToolbar')); Yii::$app->getView()->off(View::EVENT_END_BODY, array($this, 'renderToolbar'));
unset(Yii::$app->log->targets['debug']); unset(Yii::$app->getLog()->targets['debug']);
return parent::beforeAction($action); return parent::beforeAction($action);
} }
...@@ -49,4 +58,19 @@ class Module extends \yii\base\Module ...@@ -49,4 +58,19 @@ class Module extends \yii\base\Module
'style' => 'display: none', 'style' => 'display: none',
)); ));
} }
protected function corePanels()
{
return array(
'config' => array(
'class' => 'yii\debug\panels\ConfigPanel',
),
'request' => array(
'class' => 'yii\debug\panels\RequestPanel',
),
'log' => array(
'class' => 'yii\debug\panels\LogPanel',
),
);
}
} }
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\debug;
use yii\base\Component;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Panel extends Component
{
public $id;
public $data;
public function getName()
{
return '';
}
public function getSummary()
{
return '';
}
public function getDetail()
{
return '';
}
public function save()
{
return null;
}
public function load($data)
{
$this->data = $data;
}
}
...@@ -9,6 +9,7 @@ namespace yii\debug\controllers; ...@@ -9,6 +9,7 @@ namespace yii\debug\controllers;
use Yii; use Yii;
use yii\web\Controller; use yii\web\Controller;
use yii\web\HttpException;
/** /**
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
...@@ -16,22 +17,48 @@ use yii\web\Controller; ...@@ -16,22 +17,48 @@ use yii\web\Controller;
*/ */
class DefaultController extends Controller class DefaultController extends Controller
{ {
/** @var \yii\debug\Module */
public $module;
public $layout = 'main'; public $layout = 'main';
public function actionIndex($tag) public function actionIndex($tag, $panel = null)
{ {
return $this->render('index'); $this->loadData($tag);
if (isset($this->module->panels[$panel])) {
$activePanel = $this->module->panels[$panel];
} else {
$activePanel = reset($this->module->panels);
}
return $this->render('index', array(
'tag' => $tag,
'panels' => $this->module->panels,
'activePanel' => $activePanel,
));
} }
public function actionToolbar($tag) public function actionToolbar($tag)
{ {
$this->loadData($tag);
return $this->renderPartial('toolbar', array(
'panels' => $this->module->panels,
));
}
protected function loadData($tag)
{
$file = Yii::$app->getRuntimePath() . "/debug/$tag.log"; $file = Yii::$app->getRuntimePath() . "/debug/$tag.log";
if (preg_match('/^[\w\-]+$/', $tag) && is_file($file)) { if (preg_match('/^[\w\-]+$/', $tag) && is_file($file)) {
$data = json_decode(file_get_contents($file), true); $data = json_decode(file_get_contents($file), true);
$data['tag'] = $tag; foreach ($this->module->panels as $id => $panel) {
return $this->renderPartial('toolbar', $data); if (isset($data[$panel->id])) {
$panel->load($data[$panel->id]);
} else {
// remove the panel since it has not received any data
unset($this->module->panels[$id]);
}
}
} else { } else {
return "Unable to find debug data tagged with '$tag'."; throw new HttpException(404, "Unable to find debug data tagged with '$tag'.");
} }
} }
} }
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\debug\panels;
use Yii;
use yii\debug\Panel;
use yii\helpers\Html;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ConfigPanel extends Panel
{
public function getName()
{
return 'Config';
}
public function getSummary()
{
$link = Html::a('more details', array('index', 'tag' => $this->data['tag']));
return <<<EOD
<div class="yii-debug-toolbar-block">
PHP: {$this->data['phpVersion']},
Yii: {$this->data['phpVersion']},
$link
</div>
EOD;
}
public function getDetail()
{
return '<h2>Config</h2>';
}
public function save()
{
return array(
'tag' => Yii::$app->getLog()->getTag(),
'phpVersion' => PHP_VERSION,
'yiiVersion' => Yii::getVersion(),
);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\debug\panels;
use Yii;
use yii\debug\Panel;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class LogPanel extends Panel
{
public function getName()
{
return 'Logs';
}
public function getSummary()
{
$count = count($this->data['messages']);
return <<<EOD
<div class="yii-debug-toolbar-block">
Log messages: $count
</div>
EOD;
}
public function getDetail()
{
return '<h2>Logs</h2>';
}
public function save()
{
return array(
'messages' => Yii::$app->getLog()->targets['debug']->messages,
);
}
}
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\debug\panels;
use yii\debug\Panel;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class RequestPanel extends Panel
{
public function getName()
{
return 'Request';
}
public function getSummary()
{
$memory = sprintf('%.2fMB', $this->data['memory'] / 1048576);
$time = sprintf('%.3fs', $this->data['time']);
return <<<EOD
<div class="yii-debug-toolbar-block">
Peak memory: $memory
</div>
<div class="yii-debug-toolbar-block">
Time spent: $time
</div>
EOD;
}
public function getDetail()
{
return '<h2>Request</h2>';
}
public function save()
{
return array(
'memory' => memory_get_peak_usage(),
'time' => microtime(true) - YII_BEGIN_TIME,
'SERVER' => $_SERVER,
'GET' => $_GET,
'POST' => $_POST,
'COOKIE' => $_COOKIE,
'FILES' => empty($_FILES) ? array() : $_FILES,
'SESSION' => empty($_SESSION) ? array() : $_SESSION,
);
}
}
here we are <?php
use yii\helpers\Html;
/**
* @var \yii\base\View $this
* @var string $tag
* @var \yii\debug\Panel[] $panels
* @var \yii\debug\Panel $activePanel
*/
?>
<?php foreach ($panels as $panel): ?>
<?php echo Html::a(Html::encode($panel->getName()), array('debug/default/index', 'tag' => $tag, 'panel' => $panel->id)); ?><br>
<?php endforeach; ?>
<?php echo $activePanel->getDetail(); ?>
<?php use yii\helpers\Html; <?php
/**
echo Html::style(" * @var \yii\base\View $this
* @var \yii\debug\Panel[] $panels
*/
?>
<style>
#yii-debug-toolbar { #yii-debug-toolbar {
position: fixed; position: fixed;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: #eee; background-color: #eee;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
margin: 0; margin: 0;
padding: 5px 10px; padding: 5px 10px;
z-index: 1000000; z-index: 1000000;
font: 11px Verdana, Arial, sans-serif; font: 11px Verdana, Arial, sans-serif;
text-align: left; text-align: left;
} }
.yii-debug-toolbar-block { .yii-debug-toolbar-block {
float: left; float: left;
margin: 0 10px; margin: 0 10px;
"); }
?> </style>
<div id="yii-debug-toolbar">
<div class="yii-debug-toolbar-block">
<?php echo Html::a('more details', array('index', 'tag' => $tag)); ?>
</div>
<div class="yii-debug-toolbar-block">
Peak memory: <?php echo sprintf('%.2fMB', $memory / 1048576); ?>
</div>
<div class="yii-debug-toolbar-block">
Time spent: <?php echo sprintf('%.3fs', $time); ?>
</div>
<div class="yii-debug-toolbar-block">
</div>
<div class="yii-debug-toolbar-block"> <div id="yii-debug-toolbar">
</div> <?php foreach ($panels as $panel): ?>
<?php echo $panel->getSummary(); ?>
<?php endforeach; ?>
</div> </div>
...@@ -72,16 +72,14 @@ class DbTarget extends Target ...@@ -72,16 +72,14 @@ class DbTarget extends Target
/** /**
* Stores log messages to DB. * Stores log messages to DB.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/ */
public function export($messages) public function export()
{ {
$tableName = $this->db->quoteTableName($this->logTable); $tableName = $this->db->quoteTableName($this->logTable);
$sql = "INSERT INTO $tableName ([[level]], [[category]], [[log_time]], [[message]]) $sql = "INSERT INTO $tableName ([[level]], [[category]], [[log_time]], [[message]])
VALUES (:level, :category, :log_time, :message)"; VALUES (:level, :category, :log_time, :message)";
$command = $this->db->createCommand($sql); $command = $this->db->createCommand($sql);
foreach ($messages as $message) { foreach ($this->messages as $message) {
$command->bindValues(array( $command->bindValues(array(
':level' => $message[1], ':level' => $message[1],
':category' => $message[2], ':category' => $message[2],
......
...@@ -38,13 +38,11 @@ class EmailTarget extends Target ...@@ -38,13 +38,11 @@ class EmailTarget extends Target
/** /**
* Sends log messages to specified email addresses. * Sends log messages to specified email addresses.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/ */
public function export($messages) public function export()
{ {
$body = ''; $body = '';
foreach ($messages as $message) { foreach ($this->messages as $message) {
$body .= $this->formatMessage($message); $body .= $this->formatMessage($message);
} }
$body = wordwrap($body, 70); $body = wordwrap($body, 70);
......
...@@ -65,14 +65,12 @@ class FileTarget extends Target ...@@ -65,14 +65,12 @@ class FileTarget extends Target
/** /**
* Sends log messages to specified email addresses. * Sends log messages to specified email addresses.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
* @throws InvalidConfigException if unable to open the log file for writing * @throws InvalidConfigException if unable to open the log file for writing
*/ */
public function export($messages) public function export()
{ {
$text = ''; $text = '';
foreach ($messages as $message) { foreach ($this->messages as $message) {
$text .= $this->formatMessage($message); $text .= $this->formatMessage($message);
} }
if (($fp = @fopen($this->logFile, 'a')) === false) { if (($fp = @fopen($this->logFile, 'a')) === false) {
......
...@@ -124,7 +124,7 @@ class Logger extends Component ...@@ -124,7 +124,7 @@ class Logger extends Component
*/ */
public $messages = array(); public $messages = array();
/** /**
* @var array the log targets. Each array element represents a single [[Target|log target]] instance * @var array|Target[] the log targets. Each array element represents a single [[Target|log target]] instance
* or the configuration for creating the log target instance. * or the configuration for creating the log target instance.
*/ */
public $targets = array(); public $targets = array();
......
...@@ -68,18 +68,17 @@ abstract class Target extends Component ...@@ -68,18 +68,17 @@ abstract class Target extends Component
public $exportInterval = 1000; public $exportInterval = 1000;
/** /**
* @var array the messages that are retrieved from the logger so far by this log target. * @var array the messages that are retrieved from the logger so far by this log target.
* Please refer to [[Logger::messages]] for the details about the message structure.
*/ */
public $messages = array(); public $messages = array();
private $_levels = 0; private $_levels = 0;
/** /**
* Exports log messages to a specific destination. * Exports log [[messages]] to a specific destination.
* Child classes must implement this method. * Child classes must implement this method.
* @param array $messages the messages to be exported. See [[Logger::messages]] for the structure
* of each message.
*/ */
abstract public function export($messages); abstract public function export();
/** /**
* Processes the given log messages. * Processes the given log messages.
...@@ -97,7 +96,7 @@ abstract class Target extends Component ...@@ -97,7 +96,7 @@ abstract class Target extends Component
if (($context = $this->getContextMessage()) !== '') { if (($context = $this->getContextMessage()) !== '') {
$this->messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME); $this->messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME);
} }
$this->export($this->messages); $this->export();
$this->messages = array(); $this->messages = array();
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment