mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-22 19:31:02 +08:00
improved debug module profile panel
This commit is contained in:
@ -22,7 +22,7 @@ class Log extends Base
|
|||||||
public $category;
|
public $category;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var integer ajax attribute input search value
|
* @var integer message attribute input search value
|
||||||
*/
|
*/
|
||||||
public $message;
|
public $message;
|
||||||
|
|
||||||
|
75
extensions/yii/debug/models/search/Profile.php
Normal file
75
extensions/yii/debug/models/search/Profile.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace yii\debug\models\search;
|
||||||
|
|
||||||
|
use yii\data\ArrayDataProvider;
|
||||||
|
use yii\debug\components\search\Filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profile represents the model behind the search form about current request profiling log.
|
||||||
|
*/
|
||||||
|
class Profile extends Base
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string method attribute input search value
|
||||||
|
*/
|
||||||
|
public $category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var integer info attribute input search value
|
||||||
|
*/
|
||||||
|
public $info;
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[['category', 'info'], 'safe'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function attributeLabels()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'category' => 'Category',
|
||||||
|
'info' => 'Info',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns data provider with filled models. Filter applied if needed.
|
||||||
|
* @param array $params
|
||||||
|
* @param array $models
|
||||||
|
* @return \yii\data\ArrayDataProvider
|
||||||
|
*/
|
||||||
|
public function search($params, $models)
|
||||||
|
{
|
||||||
|
$dataProvider = new ArrayDataProvider([
|
||||||
|
'allModels' => $models,
|
||||||
|
'pagination' => [
|
||||||
|
'pageSize' => 10,
|
||||||
|
],
|
||||||
|
'sort' => [
|
||||||
|
'attributes' => ['category','info','duration'],
|
||||||
|
'defaultOrder' => [
|
||||||
|
'duration' => SORT_DESC,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!($this->load($params) && $this->validate())) {
|
||||||
|
return $dataProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
$filter = new Filter();
|
||||||
|
$this->addCondition($filter, 'category', true);
|
||||||
|
$this->addCondition($filter, 'info', true);
|
||||||
|
$dataProvider->allModels = $filter->filter($models);
|
||||||
|
|
||||||
|
return $dataProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -121,7 +121,7 @@ class DbPanel extends Panel
|
|||||||
*/
|
*/
|
||||||
protected function getModels()
|
protected function getModels()
|
||||||
{
|
{
|
||||||
if ($this->_models === null || $refresh) {
|
if ($this->_models === null) {
|
||||||
$this->_models = [];
|
$this->_models = [];
|
||||||
$timings = $this->calculateTimings();
|
$timings = $this->calculateTimings();
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@ namespace yii\debug\panels;
|
|||||||
|
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\debug\Panel;
|
use yii\debug\Panel;
|
||||||
use yii\helpers\Html;
|
|
||||||
use yii\log\Logger;
|
use yii\log\Logger;
|
||||||
|
use yii\debug\models\search\Profile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debugger panel that collects and displays performance profiling info.
|
* Debugger panel that collects and displays performance profiling info.
|
||||||
@ -20,6 +20,17 @@ use yii\log\Logger;
|
|||||||
*/
|
*/
|
||||||
class ProfilingPanel extends Panel
|
class ProfilingPanel extends Panel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array profile messages timings
|
||||||
|
*/
|
||||||
|
private $_timings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array current request profile timings
|
||||||
|
*/
|
||||||
|
private $_models;
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return 'Profiling';
|
return 'Profiling';
|
||||||
@ -27,25 +38,41 @@ class ProfilingPanel extends Panel
|
|||||||
|
|
||||||
public function getSummary()
|
public function getSummary()
|
||||||
{
|
{
|
||||||
$memory = sprintf('%.1f MB', $this->data['memory'] / 1048576);
|
return Yii::$app->view->render('panels/profile/summary',[
|
||||||
$time = number_format($this->data['time'] * 1000) . ' ms';
|
'memory' => sprintf('%.1f MB', $this->data['memory'] / 1048576),
|
||||||
$url = $this->getUrl();
|
'time' => number_format($this->data['time'] * 1000) . ' ms',
|
||||||
|
'panel' => $this
|
||||||
return <<<EOD
|
]);
|
||||||
<div class="yii-debug-toolbar-block">
|
|
||||||
<a href="$url" title="Total request processing time was $time">Time <span class="label">$time</span></a>
|
|
||||||
</div>
|
|
||||||
<div class="yii-debug-toolbar-block">
|
|
||||||
<a href="$url" title="Peak memory consumption">Memory <span class="label">$memory</span></a>
|
|
||||||
</div>
|
|
||||||
EOD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDetail()
|
public function getDetail()
|
||||||
{
|
{
|
||||||
|
$searchModel = new Profile();
|
||||||
|
$dataProvider = $searchModel->search($_GET, $this->getModels());
|
||||||
|
|
||||||
|
return Yii::$app->view->render('panels/profile/detail',[
|
||||||
|
'panel' => $this,
|
||||||
|
'dataProvider' => $dataProvider,
|
||||||
|
'searchModel' => $searchModel,
|
||||||
|
'memory' => sprintf('%.1f MB', $this->data['memory'] / 1048576),
|
||||||
|
'time' => number_format($this->data['time'] * 1000) . ' ms',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates given request profile messages timings.
|
||||||
|
* @return array timings
|
||||||
|
*/
|
||||||
|
protected function calculateTimings()
|
||||||
|
{
|
||||||
|
if ($this->_timings !== null) {
|
||||||
|
return $this->_timings;
|
||||||
|
}
|
||||||
|
|
||||||
$messages = $this->data['messages'];
|
$messages = $this->data['messages'];
|
||||||
$timings = [];
|
$timings = [];
|
||||||
$stack = [];
|
$stack = [];
|
||||||
|
|
||||||
foreach ($messages as $i => $log) {
|
foreach ($messages as $i => $log) {
|
||||||
list($token, $level, $category, $timestamp, $traces) = $log;
|
list($token, $level, $category, $timestamp, $traces) = $log;
|
||||||
if ($level == Logger::LEVEL_PROFILE_BEGIN) {
|
if ($level == Logger::LEVEL_PROFILE_BEGIN) {
|
||||||
@ -62,36 +89,7 @@ EOD;
|
|||||||
$timings[] = [count($stack), $last[0], $last[2], $now - $last[3], $last[4]];
|
$timings[] = [count($stack), $last[0], $last[2], $now - $last[3], $last[4]];
|
||||||
}
|
}
|
||||||
|
|
||||||
$rows = [];
|
return $this->_timings = $timings;
|
||||||
foreach ($timings as $timing) {
|
|
||||||
$time = sprintf('%.1f ms', $timing[3] * 1000);
|
|
||||||
$procedure = str_repeat('<span class="indent">→</span>', $timing[0]) . Html::encode($timing[1]);
|
|
||||||
$category = Html::encode($timing[2]);
|
|
||||||
$rows[] = "<tr><td style=\"width: 80px;\">$time</td><td style=\"width: 220px;\">$category</td><td>$procedure</td>";
|
|
||||||
}
|
|
||||||
$rows = implode("\n", $rows);
|
|
||||||
|
|
||||||
$memory = sprintf('%.1f MB', $this->data['memory'] / 1048576);
|
|
||||||
$time = number_format($this->data['time'] * 1000) . ' ms';
|
|
||||||
|
|
||||||
return <<<EOD
|
|
||||||
<h2>Performance Profiling</h2>
|
|
||||||
|
|
||||||
<p>Total processing time: <b>$time</b>; Peak memory: <b>$memory</b>.</p>
|
|
||||||
|
|
||||||
<table class="table table-condensed table-bordered table-striped table-hover" style="table-layout: fixed;">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style="width: 80px;">Time</th>
|
|
||||||
<th style="width: 220px;">Category</th>
|
|
||||||
<th>Procedure</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
$rows
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
EOD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save()
|
public function save()
|
||||||
@ -104,4 +102,27 @@ EOD;
|
|||||||
'messages' => $messages,
|
'messages' => $messages,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns array of profiling models that can be used in data provider.
|
||||||
|
* @return array models
|
||||||
|
*/
|
||||||
|
protected function getModels()
|
||||||
|
{
|
||||||
|
if ($this->_models === null) {
|
||||||
|
$this->_models = [];
|
||||||
|
$timings = $this->calculateTimings();
|
||||||
|
|
||||||
|
foreach($timings as $profileTiming) {
|
||||||
|
$this->_models[] = [
|
||||||
|
'duration' => $profileTiming[3] * 1000, #in milliseconds
|
||||||
|
'category' => $profileTiming[2],
|
||||||
|
'info' => $profileTiming[1],
|
||||||
|
'level' => $profileTiming[0],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->_models;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php if ($queryCount): ?>
|
<?php if ($queryCount): ?>
|
||||||
<div class="yii-debug-toolbar-block">
|
<div class="yii-debug-toolbar-block">
|
||||||
<a href="$url" title="Executed <?php echo $queryCount; ?> database queries which took <?php echo $queryTime; ?>.">
|
<a href="<?php echo $panel->getUrl();?>" title="Executed <?php echo $queryCount; ?> database queries which took <?php echo $queryTime; ?>.">
|
||||||
DB <span class="label"><?php echo $queryCount; ?></span> <span class="label"><?php echo $queryTime; ?></span>
|
DB <span class="label"><?php echo $queryCount; ?></span> <span class="label"><?php echo $queryTime; ?></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
34
extensions/yii/debug/views/default/panels/profile/detail.php
Normal file
34
extensions/yii/debug/views/default/panels/profile/detail.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
use yii\grid\GridView;
|
||||||
|
?>
|
||||||
|
<h1>Performance Profiling</h1>
|
||||||
|
<p>Total processing time: <b><?php echo $time; ?></b>; Peak memory: <b><?php echo $memory; ?></b>.</p>
|
||||||
|
<?php
|
||||||
|
echo GridView::widget([
|
||||||
|
'dataProvider' => $dataProvider,
|
||||||
|
'id' => 'profile-panel-detailed-grid',
|
||||||
|
'filterModel' => $searchModel,
|
||||||
|
'filterUrl' => $panel->getUrl(),
|
||||||
|
'columns' => [
|
||||||
|
['class' => 'yii\grid\SerialColumn'],
|
||||||
|
[
|
||||||
|
'attribute' => 'duration',
|
||||||
|
'value' => function ($data)
|
||||||
|
{
|
||||||
|
return sprintf('%.1f ms',$data['duration']);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'category',
|
||||||
|
[
|
||||||
|
'attribute' => 'info',
|
||||||
|
'value' => function ($data)
|
||||||
|
{
|
||||||
|
return str_repeat('<span class="indent">→</span>', $data['level']) . $data['info'];
|
||||||
|
},
|
||||||
|
'options' => [
|
||||||
|
'width' => '60%',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
?>
|
@ -0,0 +1,6 @@
|
|||||||
|
<div class="yii-debug-toolbar-block">
|
||||||
|
<a href="<?php echo $panel->getUrl(); ?>" title="Total request processing time was <?php echo $time; ?>">Time <span class="label"><?php echo $time; ?></span></a>
|
||||||
|
</div>
|
||||||
|
<div class="yii-debug-toolbar-block">
|
||||||
|
<a href="<?php echo $panel->getUrl(); ?>" title="Peak memory consumption">Memory <span class="label"><?php echo $memory; ?></span></a>
|
||||||
|
</div>
|
Reference in New Issue
Block a user