teamchallengeapps / upcloud-metrics
Poll UpCloud managed database metrics and dispatch an event when CPU, disk or memory usage breaches configured thresholds.
Package info
github.com/teamchallengeapps/upcloud-metrics
pkg:composer/teamchallengeapps/upcloud-metrics
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.5
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.26|^9.0|^10.0
- phpunit/phpunit: ^9.0|^10.0|^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
About
This package polls the UpCloud managed database metrics API for a single database, averages CPU, disk and memory usage over a rolling window, and dispatches an event when any of them breach a threshold you configure. It doesn't send alerts anywhere itself — what you do with a breach (post to incident.io, Slack, log it, whatever) is entirely up to your application's own event listener.
Behaviour worth knowing
- Only the master/primary node is monitored, for every metric. On a cluster with a standby/replica node (e.g. MySQL), the standby is deliberately excluded — it typically runs backups/snapshots and can legitimately spike CPU, disk and memory during normal operation, which would otherwise cause false-positive alerts. If UpCloud doesn't label a node
masterin its response (as with Valkey clusters), the first node in the API response is used instead. - Averages, not instant samples. Each metric's readings are grouped into
chunkMinutes-sized windows (most recent first) and averaged, so a single noisy sample won't trigger a breach. - CPU, disk and memory are each optional, aside from CPU which is required. Pass
null(or omit)diskThreshold/memThresholdand that metric is skipped entirely. - One event per breach, not one per metric. If CPU, disk and memory all breach in the same run, you get a single
DatabaseMetricsBreachedevent carrying all of them, not three separate ones.
Installation
composer require teamchallengeapps/upcloud-metrics
The package uses Laravel package auto-discovery. If you've disabled it, register the service provider manually:
\TeamChallengeApps\UpCloudMetrics\UpCloudMetricsServiceProvider::class,
Configuration
Publish the config file:
php artisan vendor:publish --provider="TeamChallengeApps\UpCloudMetrics\UpCloudMetricsServiceProvider" --tag="config"
This adds config/upcloud-metrics.php, which reads your UpCloud API credentials from the environment:
UPCLOUD_USERNAME=your-upcloud-username
UPCLOUD_PASSWORD=your-upcloud-password
These are the same username/password you'd use to log in to the UpCloud Hub — the metrics endpoint uses HTTP basic auth, not an API token.
Usage
Dispatching a check
Dispatch CheckDatabaseMetrics for each database you want checked, typically from a scheduled command:
use TeamChallengeApps\UpCloudMetrics\Jobs\CheckDatabaseMetrics; CheckDatabaseMetrics::dispatch( name: 'mysql-uk-lon1', uuid: '4e254a5f-099c-4860-8310-902a0ebefcfa', chunkMinutes: 10, cpuThreshold: 75, diskThreshold: 85, memThreshold: 85, );
name— a label for the database, used to identify it in the dispatched event (doesn't need to match anything in UpCloud).uuid— the UpCloud database's UUID.chunkMinutes— the size of the rolling average window, e.g.10means "over the last 10 minutes".cpuThreshold— percentage (0–100) CPU usage must average at or above to breach. Required.diskThreshold/memThreshold— same, for disk and memory usage. Optional; passnull(the default) to skip that metric.
Since the job implements ShouldQueue, you can also queue it (dispatch(...) from a queued context) or run it inline without queueing:
(new CheckDatabaseMetrics( name: 'mysql-uk-lon1', uuid: '4e254a5f-099c-4860-8310-902a0ebefcfa', chunkMinutes: 10, cpuThreshold: 75, memThreshold: 85, ))->handle();
A typical scheduled command, checking several databases with different thresholds. services.upcloud.databases here is your own app config, not something this package provides — structure it however suits you:
foreach (config('services.upcloud.databases') as $name => $database) { CheckDatabaseMetrics::dispatch( name: $name, uuid: $database['uuid'], chunkMinutes: 10, cpuThreshold: $database['cpu_threshold'], diskThreshold: $database['disk_threshold'] ?? null, memThreshold: $database['mem_threshold'] ?? null, ); }
Handling a breach
Listen for DatabaseMetricsBreached and decide what to do with it:
use Illuminate\Support\Facades\Event; use TeamChallengeApps\UpCloudMetrics\Events\DatabaseMetricsBreached; Event::listen(function (DatabaseMetricsBreached $event) { // $event->name string — the name you passed to the job // $event->uuid string — the database's UUID // $event->chunkMinutes int — the averaging window used // $event->breaches Collection keyed by metric ('cpu_usage', 'disk_usage', 'mem_usage') foreach ($event->breaches as $metric => $breach) { $breach['threshold']; // int|float — the threshold that was breached $breach['data']; // Collection<string, float> — period start time => average value, for each breaching period } });
Testing
composer test
Contributing
Please submit improvements and fixes :)
Changelog
Look at the CHANGELOG.md for this package.