Lines
94.11%
16 / 17
Functions and Methods
75.00%
3 / 4
Classes and Traits
0.00%
0 / 1
| Name | Lines | Functions and Methods | CRAP | Classes and Traits | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| ServiceCallStatsRecorder | 94.11% | 16 / 17 | 75.00% | 3 / 4 | 9.02 | 0.00% | 0 / 1 | |||
| __construct | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 1 | |||||
| recordCall | 88.88% | 8 / 9 | 0.00% | 0 / 1 | 4.02 | |||||
| buildServiceCallStats | 100.00% | 1 / 1 | 100.00% | 1 / 1 | 2 | |||||
| buildLatencyHistogram | 100.00% | 6 / 6 | 100.00% | 1 / 1 | 2 | |||||
| 1 | <?php | |
| 2 | ||
| 3 | declare(strict_types=1); | |
| 4 | ||
| 5 | namespace Stewart\Runtime\Broker; | |
| 6 | ||
| 7 | use Stewart\Contracts\Time\Duration; | |
| 8 | use Stewart\Runtime\Control\Protocol\Status\LatencyHistogram; | |
| 9 | use Stewart\Runtime\Control\Protocol\Status\ServiceCallStats; | |
| 10 | use Stewart\Runtime\Model\ServiceCallOutcome; | |
| 11 | ||
| 12 | final class ServiceCallStatsRecorder | |
| 13 | { | |
| 14 | // Prometheus' default seconds buckets, in milliseconds. | |
| 15 | private const array BOUNDS_MS = [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000]; | |
| 16 | ||
| 17 | private int $count = 0; | |
| 18 | ||
| 19 | /** @var array<int, int> */ | |
| 20 | private array $bucketCounts = []; | |
| 21 | ||
| 22 | private int $timed = 0; | |
| 23 | ||
| 24 | private int $sumMicroseconds = 0; | |
| 25 | ||
| 26 | public function __construct(private readonly ServiceCallOutcome $outcome) {} | |
| 27 | ||
| 28 | public function recordCall(?Duration $latency): void | |
| 29 | { | |
| 30 | ++$this->count; | |
| 31 | ||
| 32 | if ($latency === null) { | |
| 33 | return; | |
| 34 | } | |
| 35 | ||
| 36 | ++$this->timed; | |
| 37 | $this->sumMicroseconds += $latency->toMicroseconds(); | |
| 38 | ||
| 39 | foreach (self::BOUNDS_MS as $index => $bound) { | |
| 40 | if ($latency->toMicroseconds() <= $bound * 1000) { | |
| 41 | $this->bucketCounts[$index] = ($this->bucketCounts[$index] ?? 0) + 1; | |
| 42 | ||
| 43 | return; | |
| 44 | } | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | public function buildServiceCallStats(): ServiceCallStats | |
| 49 | { | |
| 50 | return new ServiceCallStats($this->outcome, $this->count, $this->timed === 0 ? null : $this->buildLatencyHistogram()); | |
| 51 | } | |
| 52 | ||
| 53 | private function buildLatencyHistogram(): LatencyHistogram | |
| 54 | { | |
| 55 | $cumulative = []; | |
| 56 | $running = 0; | |
| 57 | ||
| 58 | foreach (array_keys(self::BOUNDS_MS) as $index) { | |
| 59 | $running += $this->bucketCounts[$index] ?? 0; | |
| 60 | $cumulative[] = $running; | |
| 61 | } | |
| 62 | ||
| 63 | return new LatencyHistogram(self::BOUNDS_MS, $cumulative, $this->timed, Duration::microseconds($this->sumMicroseconds)); | |
| 64 | } | |
| 65 | } |