mirror of
https://github.com/tiennm99/coolify.git
synced 2026-08-20 02:27:57 +00:00
Sentinel stores container used memory in bytes while application and database charts label the series as megabytes. Convert those samples before they reach the frontend so the graph is not inflated by ~1024x.
97 lines
3.0 KiB
PHP
97 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace App\Traits;
|
|
|
|
use App\Models\Server;
|
|
use Illuminate\Contracts\Encryption\DecryptException;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
trait HasMetrics
|
|
{
|
|
public function getCpuMetrics(int $mins = 5): ?array
|
|
{
|
|
return $this->getMetrics('cpu', $mins, 'percent');
|
|
}
|
|
|
|
public function getMemoryMetrics(int $mins = 5): ?array
|
|
{
|
|
if ($this->isServerMetrics()) {
|
|
return $this->getMetrics('memory', $mins, 'usedPercent');
|
|
}
|
|
|
|
$metrics = $this->getMetrics('memory', $mins, 'used');
|
|
if ($metrics === null) {
|
|
return null;
|
|
}
|
|
|
|
return convertContainerMemoryBytesToMegabytes($metrics);
|
|
}
|
|
|
|
private function getMetrics(string $type, int $mins, string $valueField): ?array
|
|
{
|
|
$server = $this->getMetricsServer();
|
|
if (! $server->isMetricsEnabled()) {
|
|
return null;
|
|
}
|
|
|
|
$from = now()->subMinutes($mins)->toIso8601ZuluString();
|
|
$endpoint = $this->getMetricsEndpoint($type, $from);
|
|
|
|
$previousToken = null;
|
|
try {
|
|
$previousToken = $server->settings->sentinel_token;
|
|
} catch (DecryptException) {
|
|
// fall through to ensureValidSentinelToken which will regenerate
|
|
}
|
|
$token = $server->settings->ensureValidSentinelToken();
|
|
if ($token !== $previousToken) {
|
|
Log::warning('Regenerated sentinel token during metrics read; sentinel container restart required', ['server_id' => $server->id]);
|
|
}
|
|
|
|
$response = instant_remote_process(
|
|
["docker exec coolify-sentinel sh -c 'curl -H \"Authorization: Bearer {$token}\" {$endpoint}'"],
|
|
$server,
|
|
false
|
|
);
|
|
|
|
if (str($response)->contains('error')) {
|
|
$error = json_decode($response, true);
|
|
$error = data_get($error, 'error', 'Something is not okay, are you okay?');
|
|
if ($error === 'Unauthorized') {
|
|
$error = 'Unauthorized, please check your metrics token or restart Sentinel to set a new token.';
|
|
}
|
|
throw new \Exception($error);
|
|
}
|
|
|
|
$metrics = collect(json_decode($response, true))->map(function ($metric) use ($valueField) {
|
|
return [(int) $metric['time'], (float) ($metric[$valueField] ?? 0.0)];
|
|
})->toArray();
|
|
|
|
if ($mins > 60 && count($metrics) > 1000) {
|
|
$metrics = downsampleLTTB($metrics, 1000);
|
|
}
|
|
|
|
return $metrics;
|
|
}
|
|
|
|
private function isServerMetrics(): bool
|
|
{
|
|
return $this instanceof Server;
|
|
}
|
|
|
|
private function getMetricsServer(): Server
|
|
{
|
|
return $this->isServerMetrics() ? $this : $this->destination->server;
|
|
}
|
|
|
|
private function getMetricsEndpoint(string $type, string $from): string
|
|
{
|
|
$base = 'http://localhost:8888/api';
|
|
if ($this->isServerMetrics()) {
|
|
return "{$base}/{$type}/history?from={$from}";
|
|
}
|
|
|
|
return "{$base}/container/{$this->uuid}/{$type}/history?from={$from}";
|
|
}
|
|
}
|