diff --git a/panels/arangodb/ArangoDbPanel.php b/panels/arangodb/ArangoDbPanel.php new file mode 100644 index 0000000..52954ea --- /dev/null +++ b/panels/arangodb/ArangoDbPanel.php @@ -0,0 +1,138 @@ +module->logTarget; + + return $target->filterMessages( + $target->messages, + Logger::LEVEL_PROFILE, + [ + 'devgroup\arangodb\Query::query', + 'devgroup\arangodb\Query::execute', + ] + ); + } + + /** + * Calculates given request profile timings. + * + * @return array timings [token, category, timestamp, traces, nesting level, elapsed time] + */ + protected function calculateTimings() + { + if ($this->_timings === null) { + $this->_timings = Yii::getLogger()->calculateTimings($this->data['arango-messages']); + } + + return $this->_timings; + } + + /** + * Returns total query time. + * + * @param array $timings + * @return integer total time + */ + protected function getTotalQueryTime($timings) + { + $queryTime = 0; + + foreach ($timings as $timing) { + $queryTime += $timing['duration']; + } + + return $queryTime; + } + + public function getName() + { + return 'Arango'; + } + + public function getSummary() + { + $timings = $this->calculateTimings(); + $queryCount = count($timings); + $queryTime = number_format($this->getTotalQueryTime($timings) * 1000) . ' ms'; + + return \Yii::$app->view->render( + '@devgroup/arangodb/panels/arangodb/views/summary', + [ + 'timings' => $this->calculateTimings(), + 'queryCount' => $queryCount, + 'queryTime' => $queryTime, + 'panel' => $this, + ] + ); + } + + /** + * @inheritdoc + */ + public function getDetail() + { + $searchModel = new ArangoDb(); + $dataProvider = $searchModel->search(Yii::$app->request->getQueryParams(), $this->getModels()); + + return Yii::$app->view->render('@devgroup/arangodb/panels/arangodb/views/detail', [ + 'panel' => $this, + 'dataProvider' => $dataProvider, + 'searchModel' => $searchModel, + ]); + } + + /** + * Returns an array of models that represents logs of the current request. + * Can be used with data providers such as \yii\data\ArrayDataProvider. + * @return array models + */ + protected function getModels() + { + if ($this->_models === null) { + $this->_models = []; + $timings = $this->calculateTimings(); + + foreach ($timings as $seq => $dbTiming) { + $this->_models[] = [ + 'query' => $dbTiming['info'], + 'duration' => ($dbTiming['duration'] * 1000), // in milliseconds + 'trace' => $dbTiming['trace'], + 'timestamp' => ($dbTiming['timestamp'] * 1000), // in milliseconds + 'seq' => $seq, + ]; + } + } + + return $this->_models; + } + + public function save() + { + return ['arango-messages' => $this->getProfileLogs()]; + } +} \ No newline at end of file diff --git a/panels/arangodb/models/ArangoDb.php b/panels/arangodb/models/ArangoDb.php new file mode 100644 index 0000000..e7747f8 --- /dev/null +++ b/panels/arangodb/models/ArangoDb.php @@ -0,0 +1,67 @@ + 'Query', + ]; + } + + /** + * Returns data provider with filled models. Filter applied if needed. + * + * @param array $params an array of parameter values indexed by parameter names + * @param array $models data to return provider for + * @return \yii\data\ArrayDataProvider + */ + public function search($params, $models) + { + $dataProvider = new ArrayDataProvider([ + 'allModels' => $models, + 'pagination' => false, + 'sort' => [ + 'attributes' => ['duration', 'seq', 'query'], + 'defaultOrder' => [ + 'duration' => SORT_DESC, + ], + ], + ]); + + if (!($this->load($params) && $this->validate())) { + return $dataProvider; + } + + $filter = new Filter(); + $this->addCondition($filter, 'query', true); + $dataProvider->allModels = $filter->filter($models); + + return $dataProvider; + } +} diff --git a/panels/arangodb/views/detail.php b/panels/arangodb/views/detail.php new file mode 100644 index 0000000..c70a83b --- /dev/null +++ b/panels/arangodb/views/detail.php @@ -0,0 +1,69 @@ + +

Arango Database Queries

+ + $dataProvider, + 'id' => 'arango-db-panel-detailed-grid', + 'options' => ['class' => 'detail-grid-view'], + 'filterModel' => $searchModel, + 'filterUrl' => $panel->getUrl(), + 'columns' => [ + ['class' => 'yii\grid\SerialColumn'], + [ + 'attribute' => 'seq', + 'label' => 'Time', + 'value' => function ($data) { + $timeInSeconds = $data['timestamp'] / 1000; + $millisecondsDiff = (int) (($timeInSeconds - (int) $timeInSeconds) * 1000); + + return date('H:i:s.', $timeInSeconds) . sprintf('%03d', $millisecondsDiff); + }, + 'headerOptions' => [ + 'class' => 'sort-numerical' + ] + ], + [ + 'attribute' => 'duration', + 'value' => function ($data) { + return sprintf('%.1f ms', $data['duration']); + }, + 'options' => [ + 'width' => '10%', + ], + 'headerOptions' => [ + 'class' => 'sort-numerical' + ] + ], + [ + 'attribute' => 'query', + 'value' => function ($data) { + $query = Html::encode($data['query']); + + if (!empty($data['trace'])) { + $query .= Html::ul($data['trace'], [ + 'class' => 'trace', + 'item' => function ($trace) { + return "
  • {$trace['file']} ({$trace['line']})
  • "; + }, + ]); + } + + return $query; + }, + 'format' => 'html', + 'options' => [ + 'width' => '60%', + ], + ] + ], +]); diff --git a/panels/arangodb/views/summary.php b/panels/arangodb/views/summary.php new file mode 100644 index 0000000..1738dc1 --- /dev/null +++ b/panels/arangodb/views/summary.php @@ -0,0 +1,12 @@ + + +
    + + Ar. DB + +
    + \ No newline at end of file