diff --git a/extensions/debug/Module.php b/extensions/debug/Module.php index 8a20021..6c1e6e0 100644 --- a/extensions/debug/Module.php +++ b/extensions/debug/Module.php @@ -61,7 +61,8 @@ class Module extends \yii\base\Module Yii::$app->getView()->on(View::EVENT_END_BODY, [$this, 'renderToolbar']); }); - foreach (array_merge($this->corePanels(), $this->panels) as $id => $config) { + $this->panels = array_merge($this->corePanels(), $this->panels); + foreach ($this->panels as $id => $config) { $config['module'] = $this; $config['id'] = $id; $this->panels[$id] = Yii::createObject($config); diff --git a/extensions/debug/Panel.php b/extensions/debug/Panel.php index 055dbba..ebfa8b3 100644 --- a/extensions/debug/Panel.php +++ b/extensions/debug/Panel.php @@ -31,6 +31,12 @@ class Panel extends Component */ public $module; public $data; + /** + * @var array array of actions to add to the debug modules default controller. + * This array will be merged with all other panels actions property. + * See [[yii\base\Controller::actions()]] for the format. + */ + public $actions = []; /** * @return string name of the panel diff --git a/extensions/debug/controllers/DefaultController.php b/extensions/debug/controllers/DefaultController.php index 6694d26..0c8d6e9 100644 --- a/extensions/debug/controllers/DefaultController.php +++ b/extensions/debug/controllers/DefaultController.php @@ -27,6 +27,15 @@ class DefaultController extends Controller */ public $summary; + public function actions() + { + $actions = []; + foreach($this->module->panels as $panel) { + $actions = array_merge($actions, $panel->actions); + } + return $actions; + } + public function actionIndex() { return $this->render('index', ['manifest' => $this->getManifest()]); @@ -82,7 +91,7 @@ class DefaultController extends Controller return $this->_manifest; } - protected function loadData($tag) + public function loadData($tag) { $manifest = $this->getManifest(); if (isset($manifest[$tag])) { diff --git a/extensions/elasticsearch/Command.php b/extensions/elasticsearch/Command.php index 916d597..4b7b0a7 100644 --- a/extensions/elasticsearch/Command.php +++ b/extensions/elasticsearch/Command.php @@ -94,7 +94,7 @@ class Command extends Component */ public function get($index, $type, $id, $options = []) { - return $this->db->get([$index, $type, $id], $options, null, [200, 404]); + return $this->db->get([$index, $type, $id], $options, null); } /** diff --git a/extensions/elasticsearch/Connection.php b/extensions/elasticsearch/Connection.php index 098d6ee..75de7a3 100644 --- a/extensions/elasticsearch/Connection.php +++ b/extensions/elasticsearch/Connection.php @@ -177,10 +177,10 @@ class Connection extends Component return new QueryBuilder($this); } - public function get($url, $options = [], $body = null) + public function get($url, $options = [], $body = null, $raw = false) { $this->open(); - return $this->httpRequest('GET', $this->createUrl($url, $options), $body); + return $this->httpRequest('GET', $this->createUrl($url, $options), $body, $raw); } public function head($url, $options = [], $body = null) @@ -189,37 +189,43 @@ class Connection extends Component return $this->httpRequest('HEAD', $this->createUrl($url, $options), $body); } - public function post($url, $options = [], $body = null) + public function post($url, $options = [], $body = null, $raw = false) { $this->open(); - return $this->httpRequest('POST', $this->createUrl($url, $options), $body); + return $this->httpRequest('POST', $this->createUrl($url, $options), $body, $raw); } - public function put($url, $options = [], $body = null) + public function put($url, $options = [], $body = null, $raw = false) { $this->open(); - return $this->httpRequest('PUT', $this->createUrl($url, $options), $body); + return $this->httpRequest('PUT', $this->createUrl($url, $options), $body, $raw); } - public function delete($url, $options = [], $body = null) + public function delete($url, $options = [], $body = null, $raw = false) { $this->open(); - return $this->httpRequest('DELETE', $this->createUrl($url, $options), $body); + return $this->httpRequest('DELETE', $this->createUrl($url, $options), $body, $raw); } private function createUrl($path, $options = []) { - $url = implode('/', array_map(function($a) { - return urlencode(is_array($a) ? implode(',', $a) : $a); - }, $path)); - - if (!empty($options)) { - $url .= '?' . http_build_query($options); + if (!is_string($path)) { + $url = implode('/', array_map(function($a) { + return urlencode(is_array($a) ? implode(',', $a) : $a); + }, $path)); + if (!empty($options)) { + $url .= '?' . http_build_query($options); + } + } else { + $url = $path; + if (!empty($options)) { + $url .= (strpos($url, '?') === false ? '?' : '&') . http_build_query($options); + } } return [$this->nodes[$this->activeNode]['http_address'], $url]; } - protected function httpRequest($method, $url, $requestBody = null) + protected function httpRequest($method, $url, $requestBody = null, $raw = false) { $method = strtoupper($method); @@ -228,7 +234,7 @@ class Connection extends Component $body = ''; $options = [ - CURLOPT_USERAGENT => 'Yii2 Framework ' . __CLASS__, + CURLOPT_USERAGENT => 'Yii Framework 2 ' . __CLASS__, CURLOPT_RETURNTRANSFER => false, CURLOPT_HEADER => false, // http://www.php.net/manual/en/function.curl-setopt.php#82418 @@ -264,8 +270,11 @@ class Connection extends Component if (is_array($url)) { list($host, $q) = $url; - if (strncmp($host, 'inet[/', 6) == 0) { - $host = substr($host, 6, -1); + if (strncmp($host, 'inet[', 5) == 0) { + $host = substr($host, 5, -1); + if (($pos = strpos($host, '/')) !== false) { + $host = substr($host, $pos + 1); + } } $profile = $method . ' ' . $q . '#' . $requestBody; $url = 'http://' . $host . '/' . $q; @@ -312,7 +321,7 @@ class Connection extends Component ]); } if (isset($headers['content-type']) && !strncmp($headers['content-type'], 'application/json', 16)) { - return Json::decode($body); + return $raw ? $body : Json::decode($body); } throw new Exception('Unsupported data received from elasticsearch: ' . $headers['content-type'], [ 'requestMethod' => $method, diff --git a/extensions/elasticsearch/DebugAction.php b/extensions/elasticsearch/DebugAction.php new file mode 100644 index 0000000..d4ddd41 --- /dev/null +++ b/extensions/elasticsearch/DebugAction.php @@ -0,0 +1,76 @@ + + */ + +namespace yii\elasticsearch; + + +use yii\base\Action; +use yii\base\NotSupportedException; +use yii\debug\Panel; +use yii\helpers\ArrayHelper; +use yii\web\HttpException; +use Yii; +use yii\web\Response; + +class DebugAction extends Action +{ + /** + * @var string the connection id to use + */ + public $db; + /** + * @var Panel + */ + public $panel; + + public function run($logId, $tag) + { + $this->controller->loadData($tag); + + $timings = $this->panel->calculateTimings(); + ArrayHelper::multisort($timings, 3, SORT_DESC); + if (!isset($timings[$logId])) { + throw new HttpException(404, 'Log message not found.'); + } + $message = $timings[$logId][1]; + if (($pos = mb_strpos($message, "#")) !== false) { + $url = mb_substr($message, 0, $pos); + $body = mb_substr($message, $pos + 1); + } else { + $url = $message; + $body = null; + } + $method = mb_substr($url, 0, $pos = mb_strpos($url, ' ')); + $url = mb_substr($url, $pos + 1); + + $options = ['pretty' => true]; + + /** @var Connection $db */ + $db = \Yii::$app->getComponent($this->db); + $time = microtime(true); + switch($method) { + case 'GET': $result = $db->get($url, $options, $body, true); break; + case 'POST': $result = $db->post($url, $options, $body, true); break; + case 'PUT': $result = $db->put($url, $options, $body, true); break; + case 'DELETE': $result = $db->delete($url, $options, $body, true); break; + case 'HEAD': $result = $db->head($url, $options, $body); break; + default: + throw new NotSupportedException("Request method '$method' is not supported by elasticsearch."); + } + $time = microtime(true) - $time; + + if ($result === true) { + $result = 'success'; + } elseif ($result === false) { + $result = 'no success'; + } + + Yii::$app->response->format = Response::FORMAT_JSON; + return [ + 'time' => sprintf('%.1f ms', $time * 1000), + 'result' => $result, + ]; + } +} \ No newline at end of file diff --git a/extensions/elasticsearch/DebugPanel.php b/extensions/elasticsearch/DebugPanel.php index da5a824..1782b8d 100644 --- a/extensions/elasticsearch/DebugPanel.php +++ b/extensions/elasticsearch/DebugPanel.php @@ -8,6 +8,7 @@ namespace yii\elasticsearch; use yii\debug\Panel; +use yii\helpers\ArrayHelper; use yii\log\Logger; use yii\helpers\Html; use yii\web\View; @@ -20,6 +21,17 @@ use yii\web\View; */ class DebugPanel extends Panel { + public $db = 'elasticsearch'; + + public function init() + { + $this->actions['elasticsearch-query'] = [ + 'class' => 'yii\\elasticsearch\\DebugAction', + 'panel' => $this, + 'db' => $this->db, + ]; + } + public function getName() { return 'Elasticsearch'; @@ -47,13 +59,14 @@ EOD; public function getDetail() { + $timings = $this->calculateTimings(); + ArrayHelper::multisort($timings, 3, SORT_DESC); $rows = []; $i = 0; - foreach ($this->data['messages'] as $log) { - list ($message, $level, $category, $time, $traces) = $log; - if ($level == Logger::LEVEL_PROFILE_BEGIN) { - continue; - } + foreach ($timings as $logId => $timing) { + $duration = sprintf('%.1f ms', $timing[3] * 1000); + $message = $timing[1]; + $traces = $timing[4]; if (($pos = mb_strpos($message, "#")) !== false) { $url = mb_substr($message, 0, $pos); $body = mb_substr($message, $pos + 1); @@ -66,48 +79,43 @@ EOD; $traceString .= Html::ul($traces, [ 'class' => 'trace', 'item' => function ($trace) { - return "
  • {$trace['file']}({$trace['line']})
  • "; - }, + return "
  • {$trace['file']}({$trace['line']})
  • "; + }, ]); } - $runLinks = ''; - $c = 0; - \Yii::$app->elasticsearch->open(); - foreach(\Yii::$app->elasticsearch->nodes as $node) { - $pos = mb_strpos($url, ' '); - $type = mb_substr($url, 0, $pos); - if ($type == 'GET' && !empty($body)) { - $type = 'POST'; - } - $host = $node['http_address']; - if (strncmp($host, 'inet[/', 6) == 0) { - $host = substr($host, 6, -1); - } - $nodeUrl = 'http://' . $host . '/' . mb_substr($url, $pos + 1); - $nodeUrl .= (strpos($nodeUrl, '?') === false) ? '?pretty=true' : '&pretty=true'; - $nodeBody = json_encode($body); - \Yii::$app->view->registerJs(<< $logId, 'tag' => $this->tag]); + \Yii::$app->view->registerJs(<<Error: ' + errorThrown + ' - ' + textStatus + '
    ' + jqXHR.responseText); + }, + dataType: "json" }); return false; }); JS , View::POS_READY); - $runLinks .= Html::a(isset($node['name']) ? $node['name'] : $node['http_address'], '#', ['id' => "elastic-link-$i-$c"]) . '
    '; - $c++; - } - $rows[] = "
    $url

    $body

    $traceString
    $runLinks"; + $runLink = Html::a('run query', '#', ['id' => "elastic-link-$i"]) . '
    '; + $rows[] = << + $duration +
    $url

    $body

    $traceString
    + $runLink + + +HTML; $i++; } $rows = implode("\n", $rows); @@ -117,8 +125,9 @@ JS - - + + + @@ -130,7 +139,7 @@ HTML; private $_timings; - protected function calculateTimings() + public function calculateTimings() { if ($this->_timings !== null) { return $this->_timings; diff --git a/extensions/elasticsearch/README-debug.png b/extensions/elasticsearch/README-debug.png new file mode 100644 index 0000000..8877a60 Binary files /dev/null and b/extensions/elasticsearch/README-debug.png differ diff --git a/extensions/elasticsearch/README.md b/extensions/elasticsearch/README.md index 2a07155..ecbf633 100644 --- a/extensions/elasticsearch/README.md +++ b/extensions/elasticsearch/README.md @@ -172,3 +172,5 @@ Add the following to you application config to enable it: ], // ... ``` + +![elasticsearch DebugPanel](README-debug.png) \ No newline at end of file
    Url / QueryRun Query on nodeTimeUrl / QueryRun Query on node