Skip to content

Commit

Permalink
Merge pull request #462 from perftools/0.20.x-merge-up-into-0.21.x_8D…
Browse files Browse the repository at this point in the history
…JVRORb

Merge release 0.20.1 into 0.21.x
  • Loading branch information
glensc authored Feb 1, 2022
2 parents 2beaeed + 22f031c commit 448c6d7
Show file tree
Hide file tree
Showing 16 changed files with 128 additions and 48 deletions.
42 changes: 40 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@

A graphical interface for XHProf profiling data that can store the results in MongoDB or PDO database.

Application is [profiled](#profiling-a-web-request-or-cli-script) and the
Application is profiled and the
profiling data is transferred to XHGui, which takes that information, saves it
in MongoDB (or PDO database), and provides a convenient GUI for working with
it.

This project is the GUI for showing profiling results,
to profile your application, use specific minimal library:
- [perftools/php-profiler]

[perftools/php-profiler]: #profiling-a-web-request-or-cli-script

[![Build Status](https://travis-ci.org/perftools/xhgui.svg?branch=master)](https://travis-ci.org/perftools/xhgui)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/perftools/xhgui/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/perftools/xhgui/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/perftools/xhgui/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/perftools/xhgui/?branch=master)
Expand All @@ -15,13 +21,17 @@ it.

XHGui has the following requirements:

- Known to work: PHP >= 7.2, 8.0.
- Known to work: PHP >= 7.2, 8.0, 8.1
- If using MongoDB storage, see [MongoDB](#MongoDB) requirements
- If using PDO storage, see [PDO](#PDO) requirements
- To profile an application, one of the profiling PHP extensions is required.
See [Profiling a Web Request or CLI script](#profiling-a-web-request-or-cli-script).
The extension is not needed to run XHGui itself.

If you need to decide which backend to use, you can check the [compatibility
matrix](#compatibility-matrix) what features are implemented or missing per
backend.

## MongoDB

The default installation uses MongoDB database. Most of the documentation speaks about MongoDB.
Expand Down Expand Up @@ -92,6 +102,7 @@ NOTE: PDO may not support all the features of XHGui, see [#320].
> db.results.ensureIndex( { 'profile.main().cpu' : -1 } )
> db.results.ensureIndex( { 'meta.url' : 1 } )
> db.results.ensureIndex( { 'meta.simple_url' : 1 } )
> db.results.ensureIndex( { 'meta.SERVER.SERVER_NAME' : 1 } )
```

7. Install dependencies with composer
Expand Down Expand Up @@ -242,6 +253,33 @@ Some Notes:
health are exposed on `/metrics`. (This currently only works if using PDO for
storage.)

# Compatibility matrix

| Feature | MongoDB | PDO |
|---------------------------------|----------|----------|
| Prometheus exporter ||[#305] |
| Searcher::latest() |||
| Searcher::query() ||[#384] |
| Searcher::get() |||
| Searcher::getForUrl() ||[#436] |
| Searcher::getPercentileForUrl() ||[#436] |
| Searcher::getAvgsForUrl() ||[#384] |
| Searcher::getAll(sort) ||[#436] |
| Searcher::getAll(direction) ||[#436] |
| Searcher::delete() |||
| Searcher::truncate() |||
| Searcher::saveWatch() ||[#435] |
| Searcher::getAllWatches() ||[#435] |
| Searcher::truncateWatches() ||[#435] |
| Searcher::stats() |[#305] ||
| Searcher::getAllServerNames() |[#460] ||

[#305]: https://github.com/perftools/xhgui/pull/305
[#384]: https://github.com/perftools/xhgui/pull/384
[#435]: https://github.com/perftools/xhgui/pull/435
[#436]: https://github.com/perftools/xhgui/pull/436
[#460]: https://github.com/perftools/xhgui/pull/460

# Releases / Changelog

See the [releases](https://github.com/perftools/xhgui/releases) for changelogs,
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"platform-check": "php-only"
},
"require": {
"php": "^7.2 || ^8.0",
"php": "^7.2 || ~8.0 || ~8.1",
"ext-json": "*",
"alcaeus/mongo-php-adapter": "^1.1",
"pimple/pimple": "^3.0",
Expand Down
4 changes: 2 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions mongo.init.d/xhgui.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ db.results.ensureIndex( { 'profile.main().wt' : -1 } );
db.results.ensureIndex( { 'profile.main().mu' : -1 } );
db.results.ensureIndex( { 'profile.main().cpu' : -1 } );
db.results.ensureIndex( { 'meta.url' : 1 } );
db.results.ensureIndex( { 'meta.SERVER.SERVER_NAME' : 1 } );
4 changes: 2 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit colors="true" bootstrap="./vendor/autoload.php">
<php>
<server name="SYMFONY_PHPUNIT_VERSION" value="6.5" />
<server name="SYMFONY_PHPUNIT_VERSION" value="8.5" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[self]=0"/>
</php>
<testsuites>
<testsuite>
<testsuite name="Tests">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
Expand Down
3 changes: 3 additions & 0 deletions src/Controller/RunController.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public function index(Request $request): void
'projection' => true,
]));

$serverNames = $this->searcher->getAllServerNames();

$title = 'Recent runs';
$titleMap = [
'wt' => 'Longest wall time',
Expand All @@ -71,6 +73,7 @@ public function index(Request $request): void
'search' => $search,
'has_search' => implode('', $search) !== '',
'title' => $title,
'server_names' => $serverNames,
]);
}

Expand Down
8 changes: 8 additions & 0 deletions src/Searcher/MongoSearcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,12 @@ public function stats(): array
'bytes' => 0,
];
}

/**
* {@inheritdoc}
*/
public function getAllServerNames(): ?array
{
return $this->_collection->distinct('meta.SERVER.SERVER_NAME');
}
}
8 changes: 8 additions & 0 deletions src/Searcher/PdoSearcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ public function stats()
return $row;
}

/**
* {@inheritdoc}
*/
public function getAllServerNames(): ?array
{
return null;
}

/**
* {@inheritdoc}
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Searcher/SearcherInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,11 @@ public function truncateWatches();
* @return array array of stats
*/
public function stats();

/**
* Get all the known server names.
*
* @return array|null array of server names or null if not supported
*/
public function getAllServerNames(): ?array;
}
19 changes: 1 addition & 18 deletions src/ServiceProvider/RouteProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,8 @@ public function register(Container $di): void

private function registerRoutes(Container $di, App $app): void
{
/*
$app->error(static function (Exception $e) use ($di, $app): void {
// @var Twig $view
$view = $di['view'];
$view->parserOptions['cache'] = false;
$view->parserExtensions = [
new TwigExtension($app),
];
$app->view($view);
$app->render('error/view.twig', [
'message' => $e->getMessage(),
'stack_trace' => $e->getTraceAsString(),
]);
});
*/

/**
* Wrap Request/Response with RequestProxuy/RequestWrapper
* Wrap Request/Response with RequestProxy/RequestWrapper
*/
$wrap = static function ($handler) use ($di, $app) {
return function () use ($handler, $di, $app) {
Expand Down
19 changes: 0 additions & 19 deletions templates/error/view.twig

This file was deleted.

11 changes: 10 additions & 1 deletion templates/runs/list.twig
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,16 @@
<div class="control-group span4">
<label class="control-label" for="server-name">Server Name</label>
<div class="controls">
<input type="text" id="server-name" name="server_name" value="{{ search.server_name }}">
{% if server_names is iterable %}
<select id="server-name" name="server_name">
{% for server_name in server_names %}
<option></option>
<option value="{{ server_name }}"{% if server_name == search.server_name %} selected{% endif %}>{{ server_name }}</option>
{% endfor %}
</select>
{% else %}
<input type="text" id="server-name" name="server_name" value="{{ search.server_name }}">
{% endif %}
</div>
<label class="control-label" for="url">URL</label>
<div class="controls">
Expand Down
2 changes: 1 addition & 1 deletion tests/Controller/RunTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public function testCallgraphData(): void
]);

$result = $this->runs->callgraphData($this->request);
$this->assertInternalType('array', $result);
$this->assertIsArray($result);
$this->assertArrayHasKey('metric', $result);
$this->assertArrayHasKey('total', $result);
$this->assertArrayHasKey('nodes', $result);
Expand Down
18 changes: 16 additions & 2 deletions tests/Saver/MongoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,23 @@ public function testSave(): void
$collection = $this->getMockBuilder(MongoCollection::class)
->disableOriginalConstructor()
->getMock();
$collection->expects($this->exactly(count($data)))

$collection
->expects($this->exactly(count($data)))
->method('insert')
->withConsecutive($this->equalTo($data));
->withConsecutive(...array_map(function () {
return [
$this->callback(function ($data) {
$this->assertIsArray($data);
$this->assertArrayHasKey('_id', $data);
$this->assertArrayHasKey('meta', $data);
$this->assertArrayHasKey('profile', $data);

return true;
}),
$this->equalTo(['w' => 0]),
];
}, $data));

$saver = new MongoSaver($collection);

Expand Down
8 changes: 8 additions & 0 deletions tests/Searcher/MongoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,12 @@ public function testTruncateWatchesPreserveIndexes(): void
$this->assertEquals($options['name'], $name);
}
}

public function testGetAllServerNames(): void
{
$result = $this->mongo->getAllServerNames();
$this->assertCount(2, $result);
$this->assertContains('localhost', $result);
$this->assertContains('foo', $result);
}
}
20 changes: 20 additions & 0 deletions tests/fixtures/normalized.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,5 +279,25 @@
"pmu": 0
}
}
},
{
"_id": "aaaaaaaaaaaaaaaaaaaaaab2",
"meta": {
"url": "/bar",
"simple_url": "/bar",
"get": [],
"env": [],
"SERVER": {"REQUEST_TIME": 1358614812, "SERVER_NAME": "foo", "REQUEST_METHOD": "GET"},
"request_ts_micro": {"sec": 1358614812, "usec": 123456}
},
"profile": {
"main()": {
"ct": 1,
"wt": 10,
"cpu": 12,
"mu": 3000,
"pmu": 3001
}
}
}
]

0 comments on commit 448c6d7

Please sign in to comment.