Lines 100.00% 14 / 14
Functions and Methods 100.00% 4 / 4
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
PrometheusTextEncoder 100.00% 14 / 14 100.00% 4 / 4 9 100.00% 1 / 1
 encodeFamilies 100.00% 5 / 5 100.00% 1 / 1 3
 encodeFamily 100.00% 4 / 4 100.00% 1 / 1 2
 encodeSample 100.00% 1 / 1 100.00% 1 / 1 1
 encodeLabels 100.00% 4 / 4 100.00% 1 / 1 3
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Runtime\Metrics;
6
7use Stewart\Runtime\Metrics\Exposition\MetricFamily;
8use Stewart\Runtime\Metrics\Exposition\MetricLabels;
9use Stewart\Runtime\Metrics\Exposition\MetricSample;
10use Stewart\Runtime\Metrics\Exposition\PrometheusNumber;
11
12final readonly class PrometheusTextEncoder
13{
14    public const string CONTENT_TYPE = 'text/plain; version=0.0.4; charset=utf-8';
15
16    private const array HELP_ESCAPES = ['\\' => '\\\\', "\n" => '\\n'];
17
18    private const array LABEL_VALUE_ESCAPES = ['\\' => '\\\\', '"' => '\\"', "\n" => '\\n'];
19
20    /** @param list<MetricFamily> $families */
21    public function encodeFamilies(array $families): string
22    {
23        $text = '';
24
25        foreach ($families as $family) {
26            if ($family->hasSamples()) {
27                $text .= $this->encodeFamily($family);
28            }
29        }
30
31        return $text;
32    }
33
34    private function encodeFamily(MetricFamily $family): string
35    {
36        $text = \sprintf("# HELP %s %s\n# TYPE %s %s\n", $family->name, strtr($family->help, self::HELP_ESCAPES), $family->name, $family->type->value);
37
38        foreach ($family->listSamples() as $sample) {
39            $text .= $this->encodeSample($family->name, $sample);
40        }
41
42        return $text;
43    }
44
45    private function encodeSample(string $familyName, MetricSample $sample): string
46    {
47        return \sprintf("%s%s%s %s\n", $familyName, $sample->suffix->value, $this->encodeLabels($sample->labels), PrometheusNumber::formatValue($sample->value));
48    }
49
50    private function encodeLabels(MetricLabels $labels): string
51    {
52        $pairs = [];
53
54        foreach ($labels->listValuesByName() as $name => $value) {
55            $pairs[] = \sprintf('%s="%s"', $name, strtr($value, self::LABEL_VALUE_ESCAPES));
56        }
57
58        return $pairs === [] ? '' : '{' . implode(',', $pairs) . '}';
59    }
60}