diff --git a/app/Traits/HasMetrics.php b/app/Traits/HasMetrics.php index 20b3752f5..712f09a48 100644 --- a/app/Traits/HasMetrics.php +++ b/app/Traits/HasMetrics.php @@ -15,9 +15,16 @@ trait HasMetrics public function getMemoryMetrics(int $mins = 5): ?array { - $field = $this->isServerMetrics() ? 'usedPercent' : 'used'; + if ($this->isServerMetrics()) { + return $this->getMetrics('memory', $mins, 'usedPercent'); + } - return $this->getMetrics('memory', $mins, $field); + $metrics = $this->getMetrics('memory', $mins, 'used'); + if ($metrics === null) { + return null; + } + + return convertContainerMemoryBytesToMegabytes($metrics); } private function getMetrics(string $type, int $mins, string $valueField): ?array diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index b183f5903..cf63c4776 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -4724,6 +4724,23 @@ function downsampleLTTB(array $data, int $threshold): array return $sampled; } +/** + * Convert Sentinel container memory samples from bytes to megabytes. + * + * Sentinel stores container `used` memory in bytes. Application and database + * metric charts label the series as megabytes, so the values must be converted + * before they are sent to the frontend. + * + * @param array $metrics + * @return array + */ +function convertContainerMemoryBytesToMegabytes(array $metrics): array +{ + return array_map(static function (array $point): array { + return [(int) $point[0], round(((float) $point[1]) / 1024 / 1024, 2)]; + }, $metrics); +} + /** * Resolve shared environment variable patterns like {{environment.VAR}}, {{project.VAR}}, {{team.VAR}}. * diff --git a/tests/Unit/ContainerMemoryMetricsConversionTest.php b/tests/Unit/ContainerMemoryMetricsConversionTest.php new file mode 100644 index 000000000..8ad4ca79e --- /dev/null +++ b/tests/Unit/ContainerMemoryMetricsConversionTest.php @@ -0,0 +1,33 @@ +toBe([ + [1_700_000_000_000, 81.06], + [1_700_000_005_000, 100.0], + ]); +}); + +it('preserves timestamps and converts a zero byte sample to zero megabytes', function () { + expect(convertContainerMemoryBytesToMegabytes([ + [1_700_000_000_000, 0.0], + ]))->toBe([ + [1_700_000_000_000, 0.0], + ]); +}); + +it('leaves an empty series unchanged', function () { + expect(convertContainerMemoryBytesToMegabytes([]))->toBe([]); +});