From 4b25fc699733ba785f1054e562a6ac5a16aca1fa Mon Sep 17 00:00:00 2001 From: Dave Pifke Date: Thu, 9 Jul 2020 15:46:23 -0700 Subject: [PATCH] Add Prometheus exporter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a /metrics endpoint, to export stats about the size of the database table. (This is currently PDO-only.) Bug: T256039 Change-Id: I5f83c6fe648db6065a46ef51a110fe4278bfaeaf Signed-off-by: Elan Ruusamäe --- README.md | 6 +++++ src/Xhgui/Controller/Metrics.php | 40 ++++++++++++++++++++++++++++++++ src/Xhgui/Searcher/Interface.php | 8 +++++++ src/Xhgui/Searcher/Mongo.php | 12 ++++++++++ src/Xhgui/Searcher/Pdo.php | 26 +++++++++++++++++++++ src/Xhgui/ServiceContainer.php | 4 ++++ src/routes.php | 5 ++++ 7 files changed, 101 insertions(+) create mode 100644 src/Xhgui/Controller/Metrics.php diff --git a/README.md b/README.md index 3af92990d..5936f6233 100644 --- a/README.md +++ b/README.md @@ -235,6 +235,12 @@ Some Notes: - The waterfall display is still very much in alpha. - Feedback and pull requests are welcome :) +# Monitoring + +[Prometheus](https://prometheus.io) metrics suitable for monitoring service +health are exposed on `/metrics`. (This currently only works if using PDO for +storage.) + # Releases / Changelog See the [releases](https://github.com/perftools/xhgui/releases) for changelogs, diff --git a/src/Xhgui/Controller/Metrics.php b/src/Xhgui/Controller/Metrics.php new file mode 100644 index 000000000..ac4f9f8a3 --- /dev/null +++ b/src/Xhgui/Controller/Metrics.php @@ -0,0 +1,40 @@ +searcher = $searcher; + } + + public function metrics() + { + $request = $this->app->request(); + $response = $this->app->response(); + + $stats = $this->searcher->stats(); + + $body = "# HELP xhgui_profiles_total Number of profiles collected.\n"; + $body .= "# TYPE xhgui_profiles_total gauge\n"; + $body .= sprintf("xhgui_profiles_total %0.1F\n\n", $stats['profiles']); + + $body .= "# HELP xhgui_profile_bytes_total Size of profiles collected.\n"; + $body .= "# TYPE xhgui_profile_bytes_total gauge\n"; + $body .= sprintf("xhgui_profile_bytes_total %0.1F\n\n", $stats['bytes']); + + $body .= "# HELP xhgui_latest_profile_seconds UNIX timestamp of most recent profile.\n"; + $body .= "# TYPE xhgui_latest_profile_seconds gauge\n"; + $body .= sprintf("xhgui_latest_profile_seconds %0.1F\n", $stats['latest']); + + $response->body($body); + $response['Content-Type'] = 'text/plain; version=0.0.4'; + } +} diff --git a/src/Xhgui/Searcher/Interface.php b/src/Xhgui/Searcher/Interface.php index f08ee06b9..012555deb 100644 --- a/src/Xhgui/Searcher/Interface.php +++ b/src/Xhgui/Searcher/Interface.php @@ -124,4 +124,12 @@ public function getAllWatches(); * @return void */ public function truncateWatches(); + + /** + * Return statistics about the size of all profiling data. + * + * @return array Array of stats. + */ + public function stats(); + } diff --git a/src/Xhgui/Searcher/Mongo.php b/src/Xhgui/Searcher/Mongo.php index 6a6a3b642..27246fabe 100644 --- a/src/Xhgui/Searcher/Mongo.php +++ b/src/Xhgui/Searcher/Mongo.php @@ -329,4 +329,16 @@ private function _wrap($data) } return $results; } + + /** + * {@inheritdoc} + */ + public function stats() + { + return [ + 'profiles' => 0, + 'latest' => 0, + 'bytes' => 0, + ]; + } } diff --git a/src/Xhgui/Searcher/Pdo.php b/src/Xhgui/Searcher/Pdo.php index f71948bfe..fcf827b9b 100644 --- a/src/Xhgui/Searcher/Pdo.php +++ b/src/Xhgui/Searcher/Pdo.php @@ -271,4 +271,30 @@ public function getAllWatches() public function truncateWatches() { } + + /** + * {@inheritdoc} + */ + public function stats() + { + $stmt = $this->pdo->query(" + SELECT + COUNT(*) AS profiles, + MAX(request_ts) AS latest, + SUM(LENGTH(profile)) AS bytes + FROM {$this->table} + ", PDO::FETCH_ASSOC); + + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if (false === $row) { + $row = [ + 'profiles' => 0, + 'latest' => 0, + 'bytes' => 0, + ]; + } + + return $row; + } } diff --git a/src/Xhgui/ServiceContainer.php b/src/Xhgui/ServiceContainer.php index 99dd629b7..445de3c78 100644 --- a/src/Xhgui/ServiceContainer.php +++ b/src/Xhgui/ServiceContainer.php @@ -154,6 +154,10 @@ protected function _controllers() $this['importController'] = function ($c) { return new Xhgui_Controller_Import($c['app'], $c['saver'], $c['config']['upload.token']); }; + + $this['metricsController'] = function ($c) { + return new Xhgui_Controller_Metrics($c['app'], $c['searcher']); + }; } } diff --git a/src/routes.php b/src/routes.php index 1e47d9cb7..f985a60c4 100644 --- a/src/routes.php +++ b/src/routes.php @@ -124,3 +124,8 @@ $app->get('/waterfall/data', function () use ($di) { $di['waterfallController']->query(); })->name('waterfall.data'); + +// Metrics +$app->get('/metrics', function () use ($di, $app) { + $di['metricsController']->metrics(); +})->name('metrics');