feat(analytics): compact traffic metrics and scale latency units

This commit is contained in:
Andras Bacsai
2026-10-26 17:59:06 +01:00
parent ea1b701a94
commit 8d8f8e8988
8 changed files with 55 additions and 15 deletions
+18 -3
View File
@@ -5064,8 +5064,8 @@ function formatBytes(?int $bytes, int $precision = 2): string
}
/**
* Compact human-readable count (e.g. 26_360 -> "26.36k", 1_200_000 -> "1.2M").
* Trailing zeros are trimmed so round values read cleanly ("1k", not "1.00k").
* Compact human-readable count (e.g. 26_360 -> "26.36K", 1_200_000 -> "1.2M").
* Trailing zeros are trimmed so round values read cleanly ("1K", not "1.00K").
* Used for the dense metric columns in the traffic-analytics lists.
*/
function compactNumber(?int $n): string
@@ -5079,12 +5079,27 @@ function compactNumber(?int $n): string
[$divisor, $suffix] = match (true) {
$n >= 1_000_000_000 => [1_000_000_000, 'B'],
$n >= 1_000_000 => [1_000_000, 'M'],
default => [1000, 'k'],
default => [1000, 'K'],
};
return rtrim(rtrim(number_format($n / $divisor, 2, '.', ''), '0'), '.').$suffix;
}
/**
* Compact response time for the traffic-analytics latency figures
* (e.g. 85.4 -> "85.4 ms", 2_450 -> "2.5 s", 312_000 -> "5.2 min").
*/
function formatLatency(float|int|null $ms): string
{
$ms = (float) $ms;
return match (true) {
$ms >= 60_000 => number_format($ms / 60_000, 1).' min',
$ms >= 1000 => number_format($ms / 1000, 1).' s',
default => number_format($ms, 1).' ms',
};
}
/**
* Validates that a file path is safely within the /tmp/ directory.
* Protects against unsafe parent directory paths by resolving the real path
+3 -3
View File
@@ -139,7 +139,7 @@ $appListboxOptions = array_merge(
<div class="grid grid-cols-2 gap-px overflow-hidden rounded-lg bg-neutral-200 sm:grid-cols-3 lg:grid-cols-5 dark:bg-white/[0.07]">
<div class="flex flex-col bg-[var(--coollabs-base)] px-4 py-3">
<span class="text-[11px] font-medium tracking-wide text-neutral-500 uppercase dark:text-fg-dim">Requests</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['requests'] ?? 0) }}</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg" title="{{ number_format($overview['requests'] ?? 0) }} requests">{{ compactNumber($overview['requests'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-requests',
@@ -157,7 +157,7 @@ $appListboxOptions = array_merge(
{!! $approxBadge('Summed across servers or services; visitors seen on more than one may be double-counted.') !!}
@endif
</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['uniqueVisitors'] ?? 0) }}</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg" title="{{ number_format($overview['uniqueVisitors'] ?? 0) }} unique visitors">{{ compactNumber($overview['uniqueVisitors'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-visitors',
@@ -201,7 +201,7 @@ $appListboxOptions = array_merge(
{!! $approxBadge('Highest p95 latency across servers or services; not a true merged percentile.') !!}
@endif
</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['latencyP95'] ?? 0, 1) }} ms</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ formatLatency($overview['latencyP95'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-latency',
@@ -56,7 +56,7 @@ $spark = 'refreshChartData-'.$chartId.'-status';
<a href="{{ route('analytics') }}" {{ wireNavigate() }}
class="group flex flex-col bg-white px-4 py-3 transition-colors hover:bg-neutral-50 dark:bg-[color-mix(in_srgb,var(--color-app)_95%,white)] dark:hover:bg-[color-mix(in_srgb,var(--color-app)_93%,white)]">
<span class="text-[11px] font-medium tracking-wide text-neutral-500 uppercase dark:text-fg-dim">Requests</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['requests'] ?? 0) }}</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg" title="{{ number_format($overview['requests'] ?? 0) }} requests">{{ compactNumber($overview['requests'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-requests',
@@ -75,7 +75,7 @@ $spark = 'refreshChartData-'.$chartId.'-status';
{!! $approxBadge('Summed across '.$servers->count().' servers; visitors seen on multiple servers may be double-counted.') !!}
@endif
</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['uniqueVisitors'] ?? 0) }}</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg" title="{{ number_format($overview['uniqueVisitors'] ?? 0) }} unique visitors">{{ compactNumber($overview['uniqueVisitors'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-visitors',
@@ -62,7 +62,7 @@ $approxBadge = fn (string $tooltip) => '<span title="'.e($tooltip).'" class="ml-
<div class="grid grid-cols-2 gap-px overflow-hidden rounded-lg bg-neutral-200 sm:grid-cols-3 lg:grid-cols-5 dark:bg-white/[0.07]">
<div class="flex flex-col bg-[var(--coollabs-base)] px-4 py-3">
<span class="text-[11px] font-medium tracking-wide text-neutral-500 uppercase dark:text-fg-dim">Requests</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['requests'] ?? 0) }}</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg" title="{{ number_format($overview['requests'] ?? 0) }} requests">{{ compactNumber($overview['requests'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-requests',
@@ -80,7 +80,7 @@ $approxBadge = fn (string $tooltip) => '<span title="'.e($tooltip).'" class="ml-
{!! $approxBadge('Summed across services; visitors of more than one service may be double-counted.') !!}
@endif
</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['uniqueVisitors'] ?? 0) }}</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg" title="{{ number_format($overview['uniqueVisitors'] ?? 0) }} unique visitors">{{ compactNumber($overview['uniqueVisitors'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-visitors',
@@ -124,7 +124,7 @@ $approxBadge = fn (string $tooltip) => '<span title="'.e($tooltip).'" class="ml-
{!! $approxBadge('Highest p95 latency across services; not a true merged percentile.') !!}
@endif
</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ number_format($overview['latencyP95'] ?? 0, 1) }} ms</span>
<span class="mt-1 text-xl font-semibold text-black tabular-nums dark:text-fg">{{ formatLatency($overview['latencyP95'] ?? 0) }}</span>
<div class="mt-auto pt-3">
@include('livewire.traffic._sparkline', [
'id' => $chartId.'-spark-latency',
@@ -235,6 +235,8 @@
(() => {
checkTheme();
const formatMemory = value => value >= 1024 ? `${Number((value / 1024).toFixed(1))} GB` : `${Math.round(value)} MB`;
const memoryChart = new ApexCharts(document.getElementById('{!! $chartId !!}-memory'), {
chart: {
height: 240,
@@ -294,7 +296,7 @@
style: {
colors: textColor,
},
formatter: value => `${Math.round(value)} MB`,
formatter: formatMemory,
},
},
noData: {
@@ -354,7 +356,7 @@
style: {
colors: textColor,
},
formatter: value => `${Math.round(value)} MB`,
formatter: formatMemory,
},
},
noData: {
@@ -368,7 +370,7 @@
name: 'Memory',
color: ramColor,
data: chartData[0].seriesData,
formatter: value => `${Math.round(value)} MB`,
formatter: formatMemory,
}]);
});
})();
@@ -81,7 +81,7 @@
title="Combined 4xx and 5xx response rate">{{ $errorRate }}%</span>
<span class="hidden w-16 shrink-0 text-right text-[11px] tabular-nums text-neutral-400 sm:inline dark:text-fg-faint">{{ formatBytes($bytesOut) }}</span>
<span class="hidden w-16 shrink-0 text-right text-[11px] tabular-nums text-neutral-400 md:inline dark:text-fg-faint"
title="p95 latency">{{ number_format($p95, 1) }} ms</span>
title="p95 latency: {{ number_format($p95, 1) }} ms">{{ formatLatency($p95) }}</span>
</div>
@endforeach
</div>
+12
View File
@@ -0,0 +1,12 @@
<?php
it('formats counts with K, M, and B suffixes', function (?int $input, string $expected) {
expect(compactNumber($input))->toBe($expected);
})->with([
'null' => [null, '0'],
'below a thousand' => [999, '999'],
'round thousand' => [1000, '1K'],
'thousands' => [26_360, '26.36K'],
'millions' => [1_200_000, '1.2M'],
'billions' => [3_456_789_012, '3.46B'],
]);
+11
View File
@@ -0,0 +1,11 @@
<?php
it('formats latency in ms, s, or min', function (float|int|null $input, string $expected) {
expect(formatLatency($input))->toBe($expected);
})->with([
'null' => [null, '0.0 ms'],
'milliseconds' => [85.44, '85.4 ms'],
'just below a second' => [999.9, '999.9 ms'],
'seconds' => [2_450, '2.5 s'],
'minutes' => [312_000, '5.2 min'],
]);