PrometheusResponseFactory   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 10
eloc 34
dl 0
loc 112
ccs 32
cts 32
cp 1
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A formatLabelName() 0 4 1
A formatLabelValue() 0 3 1
A getLine() 0 3 1
A getContent() 0 9 2
A create() 0 15 2
A formatLabels() 0 14 3
1
<?php
2
3
namespace Lamoda\Metric\Responder\ResponseFactory;
4
5
use GuzzleHttp\Psr7\Response;
6
use Lamoda\Metric\Common\MetricSourceInterface;
7
use Lamoda\Metric\Responder\ResponseFactoryInterface;
8
use Psr\Http\Message\ResponseInterface;
9
10
/**
11
 * Creates Prometheus formatted metrics response.
12
 */
13
final class PrometheusResponseFactory implements ResponseFactoryInterface
14
{
15
    private const FORMAT_LINE = '%s%s %s';
16
    private const LABELS_ENCLOSURE = '{%s}';
17
    private const FORMAT_LABEL = '%s="%s"';
18
    private const GLUE_LABELS = ',';
19
    private const GLUE_LINES = PHP_EOL;
20
21
    /** Not `A-Z`, `0-9` or `_`. */
22
    private const PATTERN_FILTER_LABEL_NAME = '/\W/';
23
24
    private const CONTENT_TYPE = 'text/plain; version=0.0.4';
25
26
    /**
27
     * {@inheritdoc}
28
     */
29 1
    public function create(MetricSourceInterface $source, array $options = []): ResponseInterface
30
    {
31 1
        $data = [];
32 1
        foreach ($source->getMetrics() as $metric) {
33 1
            $data[] = [
34 1
                'name' => ($options['prefix'] ?? '') . $metric->getName(),
35 1
                'value' => $metric->resolve(),
36 1
                'tags' => $metric->getTags(),
37
            ];
38
        }
39
40 1
        return new Response(
41 1
            200,
42 1
            ['Content-Type' => self::CONTENT_TYPE],
43 1
            $this->getContent($data)
44
        );
45
    }
46
47
    /**
48
     * Get response content.
49
     *
50
     * @param array[] $data
51
     *
52
     * @return string
53
     */
54 1
    private function getContent(array $data): string
55
    {
56 1
        $lines = [];
57 1
        foreach ($data as $line) {
58 1
            $lines[] = $this->getLine($line['name'], $line['tags'], $line['value']);
59
        }
60 1
        $lines = array_filter($lines);
61
62 1
        return implode(self::GLUE_LINES, $lines) . PHP_EOL;
63
    }
64
65
    /**
66
     * Get single line of Prometheus output.
67
     *
68
     * @param string   $name
69
     * @param string[] $tags
70
     * @param float    $value
71
     *
72
     * @return string
73
     */
74 1
    private function getLine(string $name, array $tags, float $value): string
75
    {
76 1
        return sprintf(self::FORMAT_LINE, $name, $this->formatLabels($tags), $value);
77
    }
78
79
    /**
80
     * Get tags string.
81
     *
82
     * @param array $labels
83
     *
84
     * @return string
85
     */
86 1
    private function formatLabels(array $labels): string
87
    {
88 1
        if ($labels === []) {
89 1
            return '';
90
        }
91
92 1
        $tagsString = [];
93 1
        foreach ($labels as $name => $value) {
94 1
            $name = $this->formatLabelName($name);
95 1
            $value = $this->formatLabelValue($value);
96 1
            $tagsString[] = sprintf(self::FORMAT_LABEL, $name, $value);
97
        }
98
99 1
        return sprintf(self::LABELS_ENCLOSURE, implode(self::GLUE_LABELS, $tagsString));
100
    }
101
102
    /**
103
     * Add slashes to values.
104
     *
105
     * @param $value
106
     *
107
     * @return mixed
108
     */
109 1
    private function formatLabelValue(string $value): string
110
    {
111 1
        return addcslashes($value, "\n\"\\");
112
    }
113
114
    /**
115
     * Remove unsupported symbols from.
116
     *
117
     * @param string $name
118
     *
119
     * @return string
120
     */
121 1
    private function formatLabelName(string $name): string
122
    {
123
        // Only letters, digits and slashes.
124 1
        return preg_replace(self::PATTERN_FILTER_LABEL_NAME, '', $name);
125
    }
126
}
127