davit-vardanyan / netdata-php
PHP SDK for the Netdata API v3 — query metrics, nodes, alerts, contexts, and more
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.0
- psr/log: ^3.0
- psr/simple-cache: ^3.0
Requires (Dev)
- mockery/mockery: ^1.6
- php-cs-fixer/shim: ^3.0
- phpstan/phpstan: ^1.0||^2.0
- phpunit/phpunit: ^11.0
Suggests
- davit-vardanyan/netdata-laravel: Laravel wrapper package for seamless framework integration
README
A production-ready PHP SDK for the Netdata API v3. Covers 22 endpoints across 13 resources with rich DTOs, an immutable query builder, automatic retries, and a testing fake. Zero framework dependencies — works in any PHP 8.2+ project.
Features
- 13 resource classes covering 22
/api/v3/*endpoints - Rich DTOs (
Node,MetricData,Alert,Context,AgentInfo) with automatic v3 response parsing MetricDatawithdimension(),latest(),average(),max(),min(),sum(),toTimeSeries()- Immutable fluent query builders (
DataQueryRequest,WeightsRequest) - Automatic retry with exponential backoff and jitter on 429/5xx errors
- Full exception hierarchy mapped to HTTP status codes
NetdataFakefor easy testing with call assertions- Swappable HTTP client via
HttpClientInterface - Optional PSR-3 logger support
- PHPStan level 9 and PSR-12 compliant
Installation
composer require davit-vardanyan/netdata-php
Quick Start
use DavitVardanyan\Netdata\NetdataClient; // Connect to Netdata Cloud $netdata = NetdataClient::make('your-bearer-token'); // Get CPU metrics from the last 10 minutes $cpu = $netdata->data()->cpu(); echo "Current CPU: " . $cpu->latest('user') . "%\n"; echo "Average CPU: " . round($cpu->average('user'), 2) . "%\n"; // List all monitored nodes $nodes = $netdata->nodes()->list(); foreach ($nodes as $node) { echo "{$node->name} ({$node->os})\n"; }
Configuration
use DavitVardanyan\Netdata\NetdataClient; use DavitVardanyan\Netdata\Support\Config; $netdata = new NetdataClient( config: new Config( token: 'your-bearer-token', // Required baseUrl: 'https://app.netdata.cloud', // Default connectTimeout: 30, // Seconds readTimeout: 60, // Seconds maxRetries: 3, // Retry on 429/5xx retryBaseDelayMs: 1000, // Exponential backoff base ), );
| Option | Type | Default | Description |
|---|---|---|---|
token |
string | required | Netdata API bearer token |
baseUrl |
string | https://app.netdata.cloud |
API base URL |
connectTimeout |
int | 30 |
Connection timeout in seconds |
readTimeout |
int | 60 |
Read timeout in seconds |
maxRetries |
int | 3 |
Max retry attempts on 429/5xx errors |
retryBaseDelayMs |
int | 1000 |
Base delay for exponential backoff (ms) |
Available Resources
| Accessor | Endpoints | Description |
|---|---|---|
data() |
/api/v3/data |
Query metric data with convenience shortcuts |
weights() |
/api/v3/weights |
Metric weight/correlation analysis |
contexts() |
/api/v3/contexts, /api/v3/context |
Browse and inspect metric contexts |
nodes() |
/api/v3/nodes, /api/v3/node_instances |
List nodes and node instances |
alerts() |
/api/v3/alerts, /api/v3/alert_transitions, /api/v3/alert_config |
Alert summaries, transitions, and configuration |
functions() |
/api/v3/functions, /api/v3/function |
List and execute agent functions |
info() |
/api/v3/info, /api/v3/versions, /api/v3/me, /api/v3/settings |
Agent and version information |
search() |
/api/v3/q |
Search across metrics, nodes, and contexts |
badges() |
/api/v3/badge.svg |
Generate badge SVGs |
allMetrics() |
/api/v3/allmetrics |
Export all metrics (Prometheus, JSON, Shell) |
config() |
/api/v3/config, /api/v3/variable |
Agent configuration and variables |
streamPath() |
/api/v3/stream_path |
Streaming path information |
claim() |
/api/v3/claim |
Agent claiming |
Usage
Querying Metrics
Convenience Shortcuts
// CPU metrics (last 10 minutes by default) $cpu = $netdata->data()->cpu(); $cpu = $netdata->data()->cpu(afterSeconds: -3600); // last hour // Memory metrics $memory = $netdata->data()->memory(); // Disk metrics $disk = $netdata->data()->disk(); // Network metrics $network = $netdata->data()->network();
Full Query Builder
use DavitVardanyan\Netdata\Requests\DataQueryRequest; use DavitVardanyan\Netdata\Enums\GroupMethod; $request = DataQueryRequest::make() ->contexts('system.cpu') // required — pipe-separated if multiple ->nodes('my-node-id') // scope to specific nodes ->dimensions(['user', 'system']) // filter dimensions ->labels(['env:production']) // filter by labels ->after(-3600) // 1 hour ago ->before(0) // now ->points(60) // 60 data points ->group(GroupMethod::Average) ->groupBy('dimension') ->aggregation('avg'); $data = $netdata->data()->query($request);
The builder also supports scopeInstances(), filterContexts(), filterNodes(), filterInstances(), filterAlerts(), format(), options(), tier(), and timeoutMs().
Working with MetricData
$cpu = $netdata->data()->cpu(); // Get values for a single dimension $userValues = $cpu->dimension('user'); // [12.5, 15.8, ...] // Get the latest value $current = $cpu->latest('user'); // 18.3 // Statistical methods $cpu->average('user'); // 16.38 $cpu->max('user'); // 25.1 $cpu->min('user'); // 10.2 $cpu->sum('user'); // 81.9 // Convert to charting format $timeSeries = $cpu->toTimeSeries(); // [['timestamp' => 1709550000, 'user' => 12.5, 'system' => 3.2, ...], ...] // Metadata $cpu->labels; // ['guest_nice', 'guest', 'steal', 'softirq', 'irq', 'user', ...] $cpu->timestamps; // [1709550000, 1709550020, ...] $cpu->points; // 60 $cpu->after; // 1709549400 $cpu->before; // 1709550000 $cpu->isEmpty(); // false
Listing Nodes
$nodes = $netdata->nodes()->list(); foreach ($nodes as $node) { echo "{$node->name} (OS: {$node->os})\n"; echo " Version: {$node->version}\n"; echo " Arch: {$node->architecture}, CPUs: {$node->cpus}\n"; } // With scoping $nodes = $netdata->nodes()->list(scopeNodes: 'node-1|node-2'); // Node instances $instances = $netdata->nodes()->instances();
The Node DTO provides: id, name, os, osName, osVersion, kernelName, kernelVersion, architecture, cpus, memory, diskSpace, version, machineGuid, services.
Browsing Contexts
$contexts = $netdata->contexts()->list(); foreach ($contexts as $context) { echo "{$context->id} ({$context->family}) - {$context->units}\n"; } // Get a single context $ctx = $netdata->contexts()->get('system.cpu'); echo "Priority: {$ctx->priority}, Units: {$ctx->units}\n";
The Context DTO provides: id, name, family, chartType, units, priority, firstEntry, lastEntry.
Alerts
$alerts = $netdata->alerts()->list(); foreach ($alerts as $alert) { echo "{$alert->name}: {$alert->status->value} ({$alert->chart})\n"; } // Filter by status $critical = $netdata->alerts()->list(status: 'CRITICAL'); // Alert transitions (history) $transitions = $netdata->alerts()->transitions(after: -86400); // Alert configuration by hash ID $config = $netdata->alerts()->config();
The Alert DTO provides: name, chart, status (enum: critical, warning, clear, undefined, uninitialized), value, units, info, lastStatusChange.
Weights Analysis
use DavitVardanyan\Netdata\Requests\WeightsRequest; use DavitVardanyan\Netdata\Enums\WeightsMethod; $request = WeightsRequest::make() ->contexts('system.cpu') ->after(-600) ->before(0) ->method(WeightsMethod::Ks2) ->baseline(-1200, -600); $weights = $netdata->weights()->query($request);
Agent Info
$info = $netdata->info()->get(); echo "Agent {$info->version} on {$info->hostname}\n"; echo "OS: {$info->os}, Arch: {$info->architecture}, CPUs: {$info->cpus}\n"; // Other info endpoints $versions = $netdata->info()->versions(); $me = $netdata->info()->me(); $settings = $netdata->info()->settings();
Functions
// List available functions $functions = $netdata->functions()->list(); // Execute a function $result = $netdata->functions()->execute('processes');
Search
$results = $netdata->search()->query('cpu'); // Returns raw array with keys: nodes, contexts, searches, etc.
Badges
$svg = $netdata->badges()->svg('system.cpu', dimension: 'user'); // Returns raw SVG string
All Metrics Export
use DavitVardanyan\Netdata\Enums\AllMetricsFormat; // Prometheus format $metrics = $netdata->allMetrics()->get(AllMetricsFormat::Prometheus); // JSON format $metrics = $netdata->allMetrics()->get(AllMetricsFormat::Json);
Configuration
// Get full config tree $tree = $netdata->config()->tree(); // Get specific config $item = $netdata->config()->get('some-config-id'); // Update config $result = $netdata->config()->update(['key' => 'value']); // Get variables $vars = $netdata->config()->variable(chart: 'system.cpu');
Stream Path & Claiming
// Stream path info $paths = $netdata->streamPath()->get(); // Claim info $claim = $netdata->claim()->info();
Custom HTTP Client
Implement HttpClientInterface to use your own HTTP client:
use DavitVardanyan\Netdata\Contracts\HttpClientInterface; class MyHttpClient implements HttpClientInterface { public function get(string $uri, array $query = [], array $headers = []): array { // Must return ['status' => int, 'headers' => array, 'body' => array] } public function post(string $uri, array $data = [], array $headers = []): array { // Must return ['status' => int, 'headers' => array, 'body' => array] } public function getRaw(string $uri, array $query = [], array $headers = []): string { // Must return raw response body as string } } $netdata = new NetdataClient( config: new Config(token: 'your-token'), httpClient: new MyHttpClient(), );
Logging
Pass any PSR-3 compatible logger:
use Monolog\Logger; use Monolog\Handler\StreamHandler; $logger = new Logger('netdata'); $logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG)); $netdata = new NetdataClient( config: new Config(token: 'your-token'), logger: $logger, );
Requests and responses are logged at debug level. Retry attempts are logged at warning level.
Error Handling
All exceptions extend NetdataException:
use DavitVardanyan\Netdata\Exceptions\AuthenticationException; use DavitVardanyan\Netdata\Exceptions\NotFoundException; use DavitVardanyan\Netdata\Exceptions\RateLimitException; use DavitVardanyan\Netdata\Exceptions\ValidationException; use DavitVardanyan\Netdata\Exceptions\ApiException; use DavitVardanyan\Netdata\Exceptions\NetdataException; try { $nodes = $netdata->nodes()->list(); } catch (AuthenticationException $e) { // 401 - Invalid or expired token } catch (NotFoundException $e) { // 404 - Resource not found } catch (RateLimitException $e) { // 429 - Rate limited (auto-retried by default) $retryAfter = $e->retryAfter; // seconds until retry is safe } catch (ValidationException $e) { // 422 - Invalid request parameters } catch (ApiException $e) { // 5xx - Server errors (auto-retried by default) } catch (NetdataException $e) { // Base exception - catches all of the above $responseBody = $e->responseBody; // raw API response }
| Exception | HTTP Status | Auto-Retry |
|---|---|---|
AuthenticationException |
401 | No |
NotFoundException |
404 | No |
ValidationException |
422 | No |
RateLimitException |
429 | Yes |
ApiException |
5xx | Yes |
Testing
Use NetdataFake to mock API calls in your tests:
use DavitVardanyan\Netdata\Testing\NetdataFake; $fake = NetdataFake::create() ->fakeNodes([ ['id' => 'node-1', 'name' => 'web-server', 'os' => 'linux'], ['id' => 'node-2', 'name' => 'db-server', 'os' => 'linux'], ]) ->fakeAlerts([ 'alerts' => [ ['nm' => 'cpu_high', 'sum' => 'CPU usage is high', 'cr' => 0, 'wr' => 1, 'cl' => 0, 'ctx' => ['system.cpu']], ], ]) ->fakeInfo([ 'version' => 'v2.9.0', 'uid' => 'uid', 'hostname' => 'host', 'os' => 'linux', 'architecture' => 'x86_64', 'cpus' => 4, 'host_labels' => [], ]); $client = $fake->toClient(); // Use in your tests $nodes = $client->nodes()->list(); assert($nodes->count() === 2); // Assert calls were made $fake->assertCalled('/api/v3/nodes'); $fake->assertCalledTimes('/api/v3/nodes', 1); $fake->assertNothingSent(); // fails if any calls were recorded
Convenience Fake Methods
$fake = NetdataFake::create() ->fakeData([...]) // /api/v3/data ->fakeNodes([...]) // /api/v3/nodes ->fakeAlerts([...]) // /api/v3/alerts ->fakeContexts([...]) // /api/v3/contexts ->fakeWeights([...]) // /api/v3/weights ->fakeInfo([...]) // /api/v3/info ->fakeFunctions([...]) // /api/v3/functions ->fakeSearch([...]); // /api/v3/q
Faking Raw Responses
$fake = NetdataFake::create() ->fakeRawResponse('/api/v3/badge.svg', '<svg>badge</svg>') ->fakeRawResponse('/api/v3/allmetrics', 'system_cpu{dim="user"} 12.5');
Faking Arbitrary Responses
$fake = NetdataFake::create() ->fakeResponse('/api/v3/alert_config', ['configs' => [...]]);
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Run the quality checks:
composer install vendor/bin/phpunit vendor/bin/phpstan analyse vendor/bin/php-cs-fixer fix
- Commit your changes
- Push to the branch
- Open a Pull Request
License
The MIT License (MIT). See LICENSE for more information.