mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-04 10:42:23 +00:00
Co-authored-by: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
111 lines
3.3 KiB
PHP
111 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Concerns;
|
|
|
|
/**
|
|
* Shared derivations for the traffic chart payload: per-bucket sparkline series,
|
|
* the device-donut labels/series, and the globe's marker data. Consumed
|
|
* by both the global and per-application analytics components, which expose
|
|
* `$series` (status buckets) and `$breakdowns` (dimension rows).
|
|
*/
|
|
trait BuildsTrafficChartPayload
|
|
{
|
|
/**
|
|
* Per-bucket total requests, for the Requests spark.
|
|
*
|
|
* @return array<int, int>
|
|
*/
|
|
public function requestsSpark(): array
|
|
{
|
|
return array_map(fn ($b) => (int) ($b['requests'] ?? 0), $this->series);
|
|
}
|
|
|
|
/**
|
|
* Whether there is plottable request-over-time data for the Requests chart. False when
|
|
* there are no series buckets (no data) or every bucket is empty (no traffic in the
|
|
* range), so the views can render a no-data state instead of a blank chart.
|
|
*/
|
|
public function hasRequestSeries(): bool
|
|
{
|
|
return array_sum($this->requestsSpark()) > 0;
|
|
}
|
|
|
|
/**
|
|
* Per-bucket error requests (4xx + 5xx), for the Error-rate spark.
|
|
*
|
|
* @return array<int, int>
|
|
*/
|
|
public function errorsSpark(): array
|
|
{
|
|
return array_map(
|
|
fn ($b) => (int) ($b['s4xx'] ?? 0) + (int) ($b['s5xx'] ?? 0),
|
|
$this->series,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Per-bucket bandwidth (bytes in + out), for the Bandwidth spark.
|
|
*
|
|
* @return array<int, int>
|
|
*/
|
|
public function bandwidthSpark(): array
|
|
{
|
|
return array_map(
|
|
fn ($b) => (int) ($b['bytesIn'] ?? 0) + (int) ($b['bytesOut'] ?? 0),
|
|
$this->series,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Per-bucket unique visitors, for the Visitors spark.
|
|
*
|
|
* @return array<int, int>
|
|
*/
|
|
public function uniquesSpark(): array
|
|
{
|
|
return array_map(fn ($b) => (int) ($b['uniqueVisitors'] ?? 0), $this->series);
|
|
}
|
|
|
|
/**
|
|
* Per-bucket p95 latency (ms), for the Latency spark.
|
|
*
|
|
* @return array<int, float>
|
|
*/
|
|
public function latencySpark(): array
|
|
{
|
|
return array_map(fn ($b) => round((float) ($b['p95'] ?? 0), 1), $this->series);
|
|
}
|
|
|
|
/**
|
|
* Marker data for the globe: country markers and city markers, one set for each view.
|
|
*
|
|
* @return array{countries: array<int, array{code: string, requests: int}>, cities: array<int, array{lat: float, lon: float, requests: int}>}
|
|
*/
|
|
protected function geoMarkers(): array
|
|
{
|
|
return trafficGeoMarkers($this->breakdowns['country'] ?? [], trafficCityRows($this->breakdowns['city'] ?? []));
|
|
}
|
|
|
|
/**
|
|
* Device-donut data. Raw Sentinel device values are folded into friendly labels
|
|
* (pc → Desktop, smartphone → Mobile, …) and summed, then sorted by volume.
|
|
*
|
|
* @return array{labels: array<int, string>, series: array<int, int>}
|
|
*/
|
|
public function deviceChartData(): array
|
|
{
|
|
$totals = [];
|
|
foreach (($this->breakdowns['device'] ?? []) as $row) {
|
|
$value = (string) ($row['value'] ?? '');
|
|
$label = $value === '__other__' ? 'Other' : deviceLabel($value);
|
|
$totals[$label] = ($totals[$label] ?? 0) + (int) ($row['requests'] ?? 0);
|
|
}
|
|
arsort($totals);
|
|
|
|
return [
|
|
'labels' => array_keys($totals),
|
|
'series' => array_map('intval', array_values($totals)),
|
|
];
|
|
}
|
|
}
|