Skip to content

Commit

Permalink
Combine Cpu/Network/Memory stats into ServerStats, have the admin A…
Browse files Browse the repository at this point in the history
…PI endpoint return a documented OpenAPI return format, then use that on the frontend.
  • Loading branch information
BusterNeece committed Feb 23, 2025
1 parent 6cfa6c9 commit d92ff13
Show file tree
Hide file tree
Showing 30 changed files with 1,187 additions and 866 deletions.
164 changes: 58 additions & 106 deletions backend/src/Controller/Api/Admin/ServerStatsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@

use App\Container\EnvironmentAwareTrait;
use App\Controller\SingleActionInterface;
use App\Entity\Api\Admin\ServerStats\CpuStats as ApiCpuStats;
use App\Entity\Api\Admin\ServerStats\CpuStatsSection;
use App\Entity\Api\Admin\ServerStats\MemoryStats as ApiMemoryStats;
use App\Entity\Api\Admin\ServerStats\NetworkInterfaceReceived;
use App\Entity\Api\Admin\ServerStats\NetworkInterfaceStats;
use App\Entity\Api\Admin\ServerStats\NetworkInterfaceTransmitted;
use App\Entity\Api\Admin\ServerStats\ServerStats as ApiServerStats;
use App\Entity\Api\Admin\ServerStats\StorageStats;
use App\Http\Response;
use App\Http\ServerRequest;
use App\OpenApi;
use App\Radio\Quota;
use App\Service\CpuStats;
use App\Service\MemoryStats;
use App\Service\NetworkStats;
use App\Service\ServerStats;
use Brick\Math\BigInteger;
use Brick\Math\RoundingMode;
use OpenApi\Attributes as OA;
Expand All @@ -28,7 +33,8 @@
responses: [
new OA\Response(
response: 200,
description: 'Success' // TODO: Response Body
description: 'Success',
content: new OA\JsonContent(ref: '#/components/schemas/Api_Admin_ServerStats')
),
new OA\Response(ref: OpenApi::REF_RESPONSE_ACCESS_DENIED, response: 403),
new OA\Response(ref: OpenApi::REF_RESPONSE_NOT_FOUND, response: 404),
Expand All @@ -45,29 +51,25 @@ public function __invoke(
Response $response,
array $params
): ResponseInterface {
$firstCpuMeasurement = CpuStats::getCurrentLoad();
$firstNetworkMeasurement = NetworkStats::getNetworkUsage();
$firstCpuMeasurement = ServerStats::getCurrentLoad();
$firstNetworkMeasurement = ServerStats::getNetworkUsage();

$measurementTime = 1;
sleep($measurementTime);

$secondCpuMeasurement = CpuStats::getCurrentLoad();
$secondNetworkMeasurement = NetworkStats::getNetworkUsage();
$secondCpuMeasurement = ServerStats::getCurrentLoad();
$secondNetworkMeasurement = ServerStats::getNetworkUsage();

$cpuTotal = [];
/** @var CpuStatsSection|null $cpuTotal */
$cpuTotal = null;

/** @var CpuStatsSection[] $statsPerCore */
$statsPerCore = [];

foreach ($secondCpuMeasurement as $index => $currentCoreData) {
$previousCpuData = $firstCpuMeasurement[$index];
$deltaCpuData = CpuStats::calculateDelta($currentCoreData, $previousCpuData);

$cpuStats = [
'name' => $deltaCpuData->name,
'usage' => CpuStats::getUsage($deltaCpuData),
'idle' => CpuStats::getIdle($deltaCpuData),
'io_wait' => CpuStats::getIoWait($deltaCpuData),
'steal' => CpuStats::getSteal($deltaCpuData),
];
$deltaCpuData = ServerStats::calculateCpuDelta($currentCoreData, $previousCpuData);
$cpuStats = CpuStatsSection::fromCpuData($deltaCpuData);

if ($deltaCpuData->name === 'total') {
$cpuTotal = $cpuStats;
Expand All @@ -76,11 +78,14 @@ public function __invoke(
}
}

assert($cpuTotal !== null);

/** @var NetworkInterfaceStats[] $networkInterfaces */
$networkInterfaces = [];

foreach ($secondNetworkMeasurement as $index => $currentNetworkMeasurement) {
$previousNetworkMeasurement = $firstNetworkMeasurement[$index];
$deltaNetworkData = NetworkStats::calculateDelta(
$deltaNetworkData = ServerStats::calculateNetworkDelta(
$currentNetworkMeasurement,
$previousNetworkMeasurement
);
Expand All @@ -93,40 +98,20 @@ public function __invoke(
->dividedBy($measurementTime, RoundingMode::HALF_UP)
->toBigInteger();

$networkInterfaceStats = [
'interface_name' => $deltaNetworkData->interfaceName,
'received' => [
'speed' => [
'bytes' => $bytesPerTimeReceived,
'readable' => Quota::getReadableSize($bytesPerTimeReceived),
],
'packets' => $deltaNetworkData->received->packets,
'errs' => $deltaNetworkData->received->errs,
'drop' => $deltaNetworkData->received->drop,
'fifo' => $deltaNetworkData->received->fifo,
'frame' => $deltaNetworkData->received->frame,
'compressed' => $deltaNetworkData->received->compressed,
'multicast' => $deltaNetworkData->received->multicast,
],
'transmitted' => [
'speed' => [
'bytes' => $bytesPerTimeTransmitted,
'readable' => Quota::getReadableSize($bytesPerTimeTransmitted),
],
'packets' => $deltaNetworkData->transmitted->packets,
'errs' => $deltaNetworkData->transmitted->errs,
'drop' => $deltaNetworkData->transmitted->drop,
'fifo' => $deltaNetworkData->transmitted->fifo,
'frame' => $deltaNetworkData->transmitted->colls,
'carrier' => $deltaNetworkData->transmitted->carrier,
'compressed' => $deltaNetworkData->transmitted->compressed,
],
];

$networkInterfaces[] = $networkInterfaceStats;
$networkInterfaces[] = new NetworkInterfaceStats(
$deltaNetworkData->interfaceName,
NetworkInterfaceReceived::fromReceived(
$deltaNetworkData->received,
$bytesPerTimeReceived
),
NetworkInterfaceTransmitted::fromTransmitted(
$deltaNetworkData->transmitted,
$bytesPerTimeTransmitted
)
);
}

$memoryStats = MemoryStats::getMemoryUsage();
$memoryStats = ServerStats::getMemoryUsage();

$spaceTotalFloat = disk_total_space($this->environment->getStationDirectory());
$spaceTotal = (is_float($spaceTotalFloat))
Expand All @@ -140,59 +125,26 @@ public function __invoke(

$spaceUsed = $spaceTotal->minus($spaceFree);

$stats = [
'cpu' => [
'total' => $cpuTotal,
'cores' => $statsPerCore,
'load' => sys_getloadavg(),
],
'memory' => [
'bytes' => [
'total' => $memoryStats->memTotal,
'free' => $memoryStats->memFree,
'buffers' => $memoryStats->buffers,
'cached' => $memoryStats->getCachedMemory(),
'sReclaimable' => $memoryStats->sReclaimable,
'shmem' => $memoryStats->shmem,
'used' => $memoryStats->getUsedMemory(),
],
'readable' => [
'total' => Quota::getReadableSize($memoryStats->memTotal, 2),
'free' => Quota::getReadableSize($memoryStats->memFree, 2),
'buffers' => Quota::getReadableSize($memoryStats->buffers, 2),
'cached' => Quota::getReadableSize($memoryStats->getCachedMemory(), 2),
'sReclaimable' => Quota::getReadableSize($memoryStats->sReclaimable, 2),
'shmem' => Quota::getReadableSize($memoryStats->shmem, 2),
'used' => Quota::getReadableSize($memoryStats->getUsedMemory(), 2),
],
],
'swap' => [
'bytes' => [
'total' => $memoryStats->swapTotal,
'free' => $memoryStats->swapFree,
'used' => $memoryStats->getUsedSwap(),
],
'readable' => [
'total' => Quota::getReadableSize($memoryStats->swapTotal, 2),
'free' => Quota::getReadableSize($memoryStats->swapFree, 2),
'used' => Quota::getReadableSize($memoryStats->getUsedSwap(), 2),
],
],
'disk' => [
'bytes' => [
'total' => $spaceTotal,
'free' => $spaceFree,
'used' => $spaceUsed,
],
'readable' => [
'total' => Quota::getReadableSize($spaceTotal),
'free' => Quota::getReadableSize($spaceFree),
'used' => Quota::getReadableSize($spaceUsed),
],
],
'network' => $networkInterfaces,
];

return $response->withJson($stats);
return $response->withJson(
new ApiServerStats(
new ApiCpuStats(
$cpuTotal,
$statsPerCore,
sys_getloadavg() ?: [0, 0, 0]
),
ApiMemoryStats::fromMemory($memoryStats),
StorageStats::fromStorage(
$memoryStats->swapTotal,
$memoryStats->swapFree,
$memoryStats->getUsedSwap(),
),
StorageStats::fromStorage(
$spaceTotal,
$spaceFree,
$spaceUsed
),
$networkInterfaces,
)
);
}
}
4 changes: 2 additions & 2 deletions backend/src/Controller/Api/PrometheusAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use App\Controller\SingleActionInterface;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Service\MemoryStats;
use App\Service\ServerStats;
use Brick\Math\BigDecimal;
use Brick\Math\BigInteger;
use Brick\Math\RoundingMode;
Expand Down Expand Up @@ -68,7 +68,7 @@ private function addCpuMeasurements(CollectorRegistry $registry): void

private function addRamMeasurements(CollectorRegistry $registry): void
{
$memoryStats = MemoryStats::getMemoryUsage();
$memoryStats = ServerStats::getMemoryUsage();

$registry->getOrRegisterGauge(
self::APP_NAMESPACE,
Expand Down
24 changes: 24 additions & 0 deletions backend/src/Entity/Api/Admin/ServerStats/CpuStats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace App\Entity\Api\Admin\ServerStats;

use OpenApi\Attributes as OA;

#[OA\Schema(
schema: 'Api_Admin_ServerStats_CpuStats',
type: 'object'
)]
final class CpuStats
{
public function __construct(
#[OA\Property]
public CpuStatsSection $total,
#[OA\Property(items: new OA\Items(ref: '#/components/schemas/Api_Admin_ServerStats_CpuStatsSection'))]
public array $cores,
#[OA\Property(items: new OA\Items(type: 'integer', format: 'int64'))]
public array $load
) {
}
}
42 changes: 42 additions & 0 deletions backend/src/Entity/Api/Admin/ServerStats/CpuStatsSection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace App\Entity\Api\Admin\ServerStats;

use App\Service\ServerStats\CpuData;
use OpenApi\Attributes as OA;

#[OA\Schema(
schema: 'Api_Admin_ServerStats_CpuStatsSection',
type: 'object'
)]
final class CpuStatsSection
{
#[OA\Property]
public string $name;

#[OA\Property]
public string $usage;

#[OA\Property]
public string $idle;

#[OA\Property]
public string $io_wait;

#[OA\Property]
public string $steal;

public static function fromCpuData(CpuData $cpuData): self
{
$return = new self();
$return->name = $cpuData->name;
$return->usage = (string)$cpuData->getUsage();
$return->idle = (string)$cpuData->getIdle();
$return->io_wait = (string)$cpuData->getIoWait();
$return->steal = (string)$cpuData->getSteal();

return $return;
}
}
87 changes: 87 additions & 0 deletions backend/src/Entity/Api/Admin/ServerStats/MemoryStats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

declare(strict_types=1);

namespace App\Entity\Api\Admin\ServerStats;

use App\Radio\Quota;
use App\Service\ServerStats\MemoryData;
use OpenApi\Attributes as OA;

#[OA\Schema(
schema: 'Api_Admin_ServerStats_MemoryStats',
type: 'object'
)]
final class MemoryStats
{
#[OA\Property]
public string $total_bytes;

#[OA\Property]
public string $total_readable;

#[OA\Property]
public string $free_bytes;

#[OA\Property]
public string $free_readable;

#[OA\Property]
public string $buffers_bytes;

#[OA\Property]
public string $buffers_readable;

#[OA\Property]
public string $cached_bytes;

#[OA\Property]
public string $cached_readable;

#[OA\Property]
public string $sReclaimable_bytes;

#[OA\Property]
public string $sReclaimable_readable;

#[OA\Property]
public string $shmem_bytes;

#[OA\Property]
public string $shmem_readable;

#[OA\Property]
public string $used_bytes;

#[OA\Property]
public string $used_readable;

public static function fromMemory(MemoryData $memoryStats): self
{
$record = new self();

$record->total_bytes = (string)$memoryStats->memTotal;
$record->total_readable = Quota::getReadableSize($memoryStats->memTotal, 2);

$record->free_bytes = (string)$memoryStats->memFree;
$record->free_readable = Quota::getReadableSize($memoryStats->memFree, 2);

$record->buffers_bytes = (string)$memoryStats->buffers;
$record->buffers_readable = Quota::getReadableSize($memoryStats->buffers, 2);

$record->cached_bytes = (string)$memoryStats->cached;
$record->cached_readable = Quota::getReadableSize($memoryStats->cached, 2);

$record->sReclaimable_bytes = (string)$memoryStats->sReclaimable;
$record->sReclaimable_readable = Quota::getReadableSize($memoryStats->sReclaimable, 2);

$record->shmem_bytes = (string)$memoryStats->shmem;
$record->shmem_readable = Quota::getReadableSize($memoryStats->shmem, 2);

$usedBytes = $memoryStats->getUsedMemory();
$record->used_bytes = (string)$usedBytes;
$record->used_readable = Quota::getReadableSize($usedBytes, 2);

return $record;
}
}
Loading

0 comments on commit d92ff13

Please sign in to comment.