Skip to content

Commit

Permalink
Feature/monitor manager (#30)
Browse files Browse the repository at this point in the history
Added monitor manager

Added getMetrics function to retrieve Prometheus metrics from the database

Performance: Sped up JSON decoding for responses smaller than 1MB (configurable)
  • Loading branch information
LaravelFreelancerNL authored Oct 5, 2024
1 parent 7376175 commit 5ddafca
Show file tree
Hide file tree
Showing 31 changed files with 2,087 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ jobs:

- name: Test coverage
run: |
vendor/bin/phpunit --coverage-clover clover.xml --whitelist src
composer test:coverage
echo "Upload results to Scrutinizer-ci"
vendor/bin/ocular code-coverage:upload --format=php-clover clover.xml
2 changes: 1 addition & 1 deletion .github/workflows/fix-code-style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
- name: Fix style
if: ${{ always() }}
run: |
"${GITHUB_WORKSPACE}/vendor/bin/pint"
composer style
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/quality-assurance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,4 @@ jobs:
- name: Run all QA tests
if: ${{ always() }}
run: |
chmod +x "${GITHUB_WORKSPACE}/bin/qa.sh"
"${GITHUB_WORKSPACE}/bin/qa.sh"
composer analyse
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest]
arangodb: ["3.10", 3.11]
arangodb: ["3.10", 3.11, 3.12]
php: [8.1, 8.2, 8.3]
stability: [prefer-stable]

Expand Down
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
.env
.env.backup
.idea
.php_cs
.php_cs.cache
.phpunit.result.cache
.vscode
.env
.env.backup
clover.xml
composer.lock
ray.php
/build
/coverage
/vendor
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ The admin manager manages administrative functions and information retrieval for
$client->admin()->version();
```

### Monitor manager
The monitor manager manages monitoring functions the server/cluster.
```
$client->monitor()->getMetrics();
```

### Schema manager
The schema manager manages all schema related operations.
```
Expand All @@ -86,15 +92,16 @@ $client->transactions()->begin(['write' => ['users', 'teams']]);
1) [ArangoDB PHP client](docs/arangodb-client.md)
2) [AQL query statements](docs/statements.md)
3) [Admin manager](docs/admin-manager.md)
4) Schema manager
4) [Monitor manager](docs/monitor-manager.md)
5Schema manager
1) [Database schema](docs/schema-databases.md)
2) [User schema](docs/schema-users.md)
3) [Collection schema](docs/schema-collections.md)
4) [Index schema](docs/schema-indexes.md)
5) [Graph schema](docs/schema-graphs.md)
6) [View schema](docs/schema-views.md)
7) [Analyzer schema](docs/schema-analyzers.md)
5) [Transaction manager](docs/transaction-manager.md)
6[Transaction manager](docs/transaction-manager.md)

## Related packages
* [AQL query builder](https://github.com/LaravelFreelancerNL/fluentaql)
Expand Down
7 changes: 0 additions & 7 deletions bin/qa.sh

This file was deleted.

5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"ext-json": "*",
"guzzlehttp/guzzle": "^7.3",
"halaxa/json-machine": "^1.0",
"spatie/data-transfer-object": "^3.9"
"spatie/data-transfer-object": "^3.9",
"spatie/ray": "^1.41"
},
"require-dev": {
"laravel/pint": "^1.2.1",
Expand All @@ -45,7 +46,7 @@
"scripts": {
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/phpunit",
"test-coverage": "vendor/bin/phpunit --coverage",
"test:coverage": "vendor/bin/phpunit --coverage-clover clover.xml --whitelist src",
"style": "vendor/bin/pint"
},
"config": {
Expand Down
10 changes: 10 additions & 0 deletions docs/arangodb-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Upon creation, you can alter the default configuration of the client. The follow
* username = null
* password = null
* database = '_system'
* responseSizeDecoderSwitch = 1 * 1024 * 1024

```
$config = [
Expand All @@ -25,6 +26,15 @@ $config = [
$arangoClient = new ArangoClient($config);
```

### Speed vs response size
JSON response decoding is normally done by the default json_decode method. This method
is optimized for speed and can take a large amount of memory; up to ~ 20x of the JSON size.

Therefor we use halaxa/json-machine to stream decode for responses larger than 1MB.
You can alter this cutoff by setting the `responseSizeDecoderSwitch` to a different size in **Bytes**.

This removed any memory issues at the cost of speed.

### Support Guzzle configuration
In addition to the above mentioned options you can use the following Guzzle 7 specific options:
* [version](https://docs.guzzlephp.org/en/stable/request-options.html#version)
Expand Down
13 changes: 13 additions & 0 deletions docs/monitor-manager.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Monitor manager

Manages monitoring functions for the server/cluster.

## Functions
The monitor manager supports the following functions:

### getMetrics(): Metrics
Get Prometheus metrics of the server

```
$arangoClient->monitor()->getMetrics();
```
2 changes: 2 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ parameters:
level: 8
paths:
- src
universalObjectCratesClasses:
- ArangoClient\Prometheus\Metrics
2 changes: 1 addition & 1 deletion src/Admin/AdminManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function getVersion(bool $details = false): stdClass
'query' => [
'details' => $details,
],
]
],
);
}

Expand Down
42 changes: 29 additions & 13 deletions src/ArangoClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/
class ArangoClient
{
use HandlesResponses;
use HandlesJson;
use HasManagers;
use SupportsTransactions;
Expand Down Expand Up @@ -88,7 +89,11 @@ public function request(string $method, string $uri, array|HttpRequestOptions $o
$this->handleGuzzleException($e);
}

return $this->cleanupResponse($response);
if ($response !== null) {
return $this->cleanupResponse($response);
}

return new stdClass();
}

/**
Expand Down Expand Up @@ -116,7 +121,7 @@ public function debugRequest(
string $method,
string $uri,
array $options = [],
?string $database = null
?string $database = null,
): ResponseInterface {
$uri = $this->prependDatabaseToUri($uri, $database);
$options['debug'] = true;
Expand All @@ -142,23 +147,31 @@ protected function handleGuzzleException(Throwable $e): void
$code = $e->getCode();

if ($e instanceof RequestException && $e->hasResponse()) {
$decodedResponse = $this->decodeResponse($e->getResponse());
$message = (string) $decodedResponse->errorMessage;
$code = (int) $decodedResponse->code;
$response = $e->getResponse();
if ($response !== null) {
$decodedResponse = $this->decodeResponse($response);
}
if (isset($decodedResponse->errorMessage)) {
$message = (string) $decodedResponse->errorMessage;
}

if (isset($decodedResponse->code)) {
$code = (int) $decodedResponse->code;
}
}

throw(
new ArangoException(
$code . ' - ' . $message,
$code
)
new ArangoException(
$code . ' - ' . $message,
$code,
)
);
}

/**
* @SuppressWarnings(PHPMD.StaticAccess)
*/
protected function cleanupResponse(?ResponseInterface $response): stdClass
protected function cleanupResponse(ResponseInterface $response): stdClass
{
$response = $this->decodeResponse($response);
unset($response->error);
Expand All @@ -175,16 +188,19 @@ protected function cleanupResponse(?ResponseInterface $response): stdClass
public function prepare(
string $query,
array $bindVars = [],
array $options = []
array $options = [],
): Traversable {
return new Statement($this, $query, $bindVars, $options);
}

/**
* @return array<array-key, mixed>
* @return mixed
*/
public function getConfig(): array
public function getConfig(string $value = null): mixed
{
if ($value) {
return $this->config->$value;
}
return $this->config->toArray();
}

Expand Down
13 changes: 8 additions & 5 deletions src/HandlesJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,18 @@ public function jsonEncode(mixed $data): string
/**
* @SuppressWarnings(PHPMD.StaticAccess)
*/
protected function decodeResponse(?ResponseInterface $response): stdClass
protected function decodeJsonResponse(ResponseInterface $response): stdClass
{
$decodedResponse = new stdClass();
if (!isset($response)) {
return $decodedResponse;
$contentLength = $response->getHeaderLine('Content-Length');
$sizeSwitch = $this->getConfig('responseSizeDecoderSwitch');
if ($contentLength < $sizeSwitch) {
return json_decode($response->getBody()->getContents(), false, 512, JSON_THROW_ON_ERROR);
}

$decodedResponse = new stdClass();

$phpStream = StreamWrapper::getResource($response->getBody());
$decoder = new ExtJsonDecoder(false);
$decoder = new ExtJsonDecoder(true);
$decodedStream = Items::fromStream($phpStream, ['decoder' => $decoder]);

foreach ($decodedStream as $key => $value) {
Expand Down
41 changes: 41 additions & 0 deletions src/HandlesResponses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace ArangoClient;

use ArangoClient\Prometheus\Prometheus;
use Psr\Http\Message\ResponseInterface;
use stdClass;

trait HandlesResponses
{
use HandlesJson;

/**
* @SuppressWarnings(PHPMD.StaticAccess)
*/
protected function decodeResponse(ResponseInterface $response): stdClass
{
$contentType = null;
$rawContentType = $response->getHeader('Content-type');
if (is_array($rawContentType) && sizeOf($rawContentType) > 0) {
$contentType = $rawContentType[0];
}

return match ($contentType) {
"application/json; charset=utf-8" => $this->decodeJsonResponse($response),
"text/plain; charset=utf-8" => $this->decodeTextResponse($response),
default => (object) $response->getBody()->getContents(),
};
}

/**
* @SuppressWarnings(PHPMD.StaticAccess)
*/
protected function decodeTextResponse(ResponseInterface $response): stdClass
{
$prometheus = new Prometheus();
return $prometheus->parseStream($response);
}
}
12 changes: 12 additions & 0 deletions src/HasManagers.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
namespace ArangoClient;

use ArangoClient\Admin\AdminManager;
use ArangoClient\Monitor\MonitorManager;
use ArangoClient\Schema\SchemaManager;

trait HasManagers
{
protected ?AdminManager $adminManager = null;

protected ?MonitorManager $monitorManager = null;

protected ?SchemaManager $schemaManager = null;

public function admin(): AdminManager
Expand All @@ -22,6 +25,15 @@ public function admin(): AdminManager
return $this->adminManager;
}

public function monitor(): MonitorManager
{
if (!(property_exists($this, 'monitorManager') && $this->monitorManager !== null)) {
$this->monitorManager = new MonitorManager($this);
}

return $this->monitorManager;
}

public function schema(): SchemaManager
{
if (!(property_exists($this, 'schemaManager') && $this->schemaManager !== null)) {
Expand Down
9 changes: 9 additions & 0 deletions src/Http/HttpClientConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ class HttpClientConfig extends DataTransferObject

public string $database = '_system';

/**
* Small responses are decoded with json_decode. This is fast but memory intensive.
* Large responses are decoded with Halaxa/json-machine stream decoder.
* $responseSizeDecoderSwitch is the response length cutoff in bytes which determines which decoder is used.
*
* @var int
*/
public int $responseSizeDecoderSwitch = 1 * 1024 * 1024; // Default 1 MB

/**
* @return array<array<mixed>|string|numeric|bool|null>
*/
Expand Down
20 changes: 20 additions & 0 deletions src/Monitor/MonitorManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace ArangoClient\Monitor;

use ArangoClient\ArangoClient;
use ArangoClient\Manager;

class MonitorManager extends Manager
{
public function __construct(protected ArangoClient $arangoClient) {}

public function getMetrics(): \stdClass
{
$uri = '/_admin/metrics/v2';

return $this->arangoClient->request('get', $uri);
}
}
Loading

0 comments on commit 5ddafca

Please sign in to comment.