DebugPanel.php 4.53 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\elasticsearch;

use yii\debug\Panel;
11
use yii\helpers\ArrayHelper;
12 13 14 15 16 17 18 19 20 21 22 23
use yii\log\Logger;
use yii\helpers\Html;
use yii\web\View;

/**
 * Debugger panel that collects and displays elasticsearch queries performed.
 *
 * @author Carsten Brandt <mail@cebe.cc>
 * @since 2.0
 */
class DebugPanel extends Panel
{
24 25 26 27 28 29 30 31 32 33 34
	public $db = 'elasticsearch';

	public function init()
	{
		$this->actions['elasticsearch-query'] = [
			'class' => 'yii\\elasticsearch\\DebugAction',
			'panel' => $this,
			'db' => $this->db,
		];
	}

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
	public function getName()
	{
		return 'Elasticsearch';
	}

	public function getSummary()
	{
		$timings = $this->calculateTimings();
		$queryCount = count($timings);
		$queryTime = 0;
		foreach ($timings as $timing) {
			$queryTime += $timing[3];
		}
		$queryTime = number_format($queryTime * 1000) . ' ms';
		$url = $this->getUrl();
		$output = <<<EOD
<div class="yii-debug-toolbar-block">
	<a href="$url" title="Executed $queryCount elasticsearch queries which took $queryTime.">
		ES <span class="label">$queryCount</span> <span class="label">$queryTime</span>
	</a>
</div>
EOD;
		return $queryCount > 0 ? $output : '';
	}

	public function getDetail()
	{
62 63
		$timings = $this->calculateTimings();
		ArrayHelper::multisort($timings, 3, SORT_DESC);
64 65
		$rows = [];
		$i = 0;
66 67 68 69
		foreach ($timings as $logId => $timing) {
			$duration = sprintf('%.1f ms', $timing[3] * 1000);
			$message = $timing[1];
			$traces = $timing[4];
70 71 72 73 74 75 76 77 78 79 80 81
			if (($pos = mb_strpos($message, "#")) !== false) {
				$url = mb_substr($message, 0, $pos);
				$body = mb_substr($message, $pos + 1);
			} else {
				$url = $message;
				$body = null;
			}
			$traceString = '';
			if (!empty($traces)) {
				$traceString .= Html::ul($traces, [
					'class' => 'trace',
					'item' => function ($trace) {
82 83
						return "<li>{$trace['file']}({$trace['line']})</li>";
					},
84 85
				]);
			}
86 87 88 89 90 91
			$ajaxUrl = Html::url(['elasticsearch-query', 'logId' => $logId, 'tag' => $this->tag]);
			\Yii::$app->view->registerJs(<<<JS
$('#elastic-link-$i').on('click', function() {
	var result = $('#elastic-result-$i');
	result.html('Sending request...');
	result.parent('tr').show();
92
	$.ajax({
93 94
		type: "POST",
		url: "$ajaxUrl",
95
		success: function( data ) {
96 97
			$('#elastic-time-$i').html(data.time);
			$('#elastic-result-$i').html(data.result);
98
		},
99 100 101 102 103
		error: function(jqXHR, textStatus, errorThrown) {
			$('#elastic-time-$i').html('');
			$('#elastic-result-$i').html('<span style="color: #c00;">Error: ' + errorThrown + ' - ' + textStatus + '</span><br />' + jqXHR.responseText);
		},
		dataType: "json"
104 105 106 107 108 109
	});

	return false;
});
JS
, View::POS_READY);
110 111 112 113 114 115 116 117 118
			$runLink = Html::a('run query', '#', ['id' => "elastic-link-$i"]) . '<br/>';
			$rows[] = <<<HTML
<tr>
	<td style="width: 10%;">$duration</td>
	<td style="width: 75%;"><div><b>$url</b><br/><p>$body</p>$traceString</div></td>
	<td style="width: 15%;">$runLink</td>
</tr>
<tr style="display: none;"><td id="elastic-time-$i"></td><td colspan="3" id="elastic-result-$i"></td></tr>
HTML;
119 120 121 122 123 124 125 126 127
			$i++;
		}
		$rows = implode("\n", $rows);
		return <<<HTML
<h1>Elasticsearch Queries</h1>

<table class="table table-condensed table-bordered table-striped table-hover" style="table-layout: fixed;">
<thead>
<tr>
128 129 130
	<th style="width: 10%;">Time</th>
	<th style="width: 75%;">Url / Query</th>
	<th style="width: 15%;">Run Query on node</th>
131 132 133 134 135 136 137 138 139 140 141
</tr>
</thead>
<tbody>
$rows
</tbody>
</table>
HTML;
	}

	private $_timings;

142
	public function calculateTimings()
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	{
		if ($this->_timings !== null) {
			return $this->_timings;
		}
		$messages = $this->data['messages'];
		$timings = [];
		$stack = [];
		foreach ($messages as $i => $log) {
			list($token, $level, $category, $timestamp) = $log;
			$log[5] = $i;
			if ($level == Logger::LEVEL_PROFILE_BEGIN) {
				$stack[] = $log;
			} elseif ($level == Logger::LEVEL_PROFILE_END) {
				if (($last = array_pop($stack)) !== null && $last[0] === $token) {
					$timings[$last[5]] = [count($stack), $token, $last[3], $timestamp - $last[3], $last[4]];
				}
			}
		}

		$now = microtime(true);
		while (($last = array_pop($stack)) !== null) {
			$delta = $now - $last[3];
			$timings[$last[5]] = [count($stack), $last[0], $last[2], $delta, $last[4]];
		}
		ksort($timings);
		return $this->_timings = $timings;
	}

	public function save()
	{
		$target = $this->module->logTarget;
		$messages = $target->filterMessages($target->messages, Logger::LEVEL_PROFILE, ['yii\elasticsearch\Connection::httpRequest']);
		return ['messages' => $messages];
	}
}