Failed Conditions
Push — develop ( 859721...8283a1 )
by Denis
33:23
created

AppMetrics::collectStart()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 11
ccs 6
cts 7
cp 0.8571
rs 10
cc 3
nc 3
nop 1
crap 3.0261
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Artprima\PrometheusMetricsBundle\Metrics;
6
7
use Prometheus\CollectorRegistry;
8
use Prometheus\Exception\MetricNotFoundException;
9
use Symfony\Component\HttpKernel\Event\RequestEvent;
10
use Symfony\Component\HttpKernel\Event\TerminateEvent;
11
use Symfony\Component\Stopwatch\Stopwatch;
12
13
/**
14
 * Class AppMetrics.
15
 */
16
class AppMetrics implements MetricsGeneratorInterface
17
{
18
    private const STOPWATCH_CLASS = '\Symfony\Component\Stopwatch\Stopwatch';
19
20
    /**
21
     * @var Stopwatch
22
     */
23
    private $stopwatch;
24
25
    /**
26
     * @var string
27
     */
28
    private $namespace;
29
30
    /**
31
     * @var CollectorRegistry
32
     */
33
    private $collectionRegistry;
34
35 30
    public function init(string $namespace, CollectorRegistry $collectionRegistry)
36
    {
37 30
        $this->namespace          = $namespace;
38 30
        $this->collectionRegistry = $collectionRegistry;
39 30
    }
40
41 15
    public function collectRequest(RequestEvent $event)
42
    {
43 15
        $request       = $event->getRequest();
44 15
        $requestMethod = $request->getMethod();
45 15
        $requestRoute  = $request->attributes->get('_route');
46
47
        // do not track "OPTIONS" requests
48 15
        if ('OPTIONS' === $requestMethod) {
49 3
            return;
50
        }
51
52 12
        $this->setInstance($request->server->get('HOSTNAME') ?? 'dev');
53 12
        $this->incRequestsTotal($requestMethod, $requestRoute);
54 12
    }
55
56 12
    private function setInstance(string $value): void
57
    {
58 12
        $name = 'instance_name';
59
        try {
60
            // the trick with try/catch let's us setting the instance name only once
61 12
            $this->collectionRegistry->getGauge($this->namespace, $name);
62 12
        } catch (MetricNotFoundException $e) {
63
            /** @noinspection PhpUnhandledExceptionInspection */
64 12
            $gauge = $this->collectionRegistry->registerGauge(
65 12
                $this->namespace,
66 4
                $name,
67 12
                'app instance name',
68 12
                ['instance']
69
            );
70 12
            $gauge->set(1, [$value]);
71
        }
72 12
    }
73
74 12
    private function incRequestsTotal(?string $method = null, ?string $route = null): void
75
    {
76 12
        $counter = $this->collectionRegistry->getOrRegisterCounter(
77 12
            $this->namespace,
78 12
            'http_requests_total',
79 12
            'total request count',
80 12
            ['action']
81
        );
82
83 12
        $counter->inc(['all']);
84
85 12
        if (null !== $method && null !== $route) {
86 12
            $counter->inc([sprintf('%s-%s', $method, $route)]);
87
        }
88 12
    }
89
90 18
    public function collectResponse(TerminateEvent $event)
91
    {
92 18
        $response = $event->getResponse();
93 18
        $request  = $event->getRequest();
94
95 18
        $requestMethod = $request->getMethod();
96 18
        $requestRoute  = $request->attributes->get('_route');
97
98 18
        if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) {
99 12
            $this->inc2xxResponsesTotal($requestMethod, $requestRoute);
100 6
        } elseif ($response->getStatusCode() >= 400 && $response->getStatusCode() < 500) {
101 3
            $this->inc4xxResponsesTotal($requestMethod, $requestRoute);
102 3
        } elseif ($response->getStatusCode() >= 500) {
103 3
            $this->inc5xxResponsesTotal($requestMethod, $requestRoute);
104
        }
105
106 18
        if($this->stopwatch && $this->stopwatch->isStarted('execution_time')) {
107 9
            $evt = $this->stopwatch->stop('execution_time');
108 9
            if (null !== $evt) {
109 9
                $this->setRequestDuration($evt->getDuration() / 1000, $requestMethod, $requestRoute);
110
            }
111
        }
112 18
    }
113
114 12
    private function inc2xxResponsesTotal(?string $method = null, ?string $route = null): void
115
    {
116 12
        $counter = $this->collectionRegistry->getOrRegisterCounter(
117 12
            $this->namespace,
118 12
            'http_2xx_responses_total',
119 12
            'total 2xx response count',
120 12
            ['action']
121
        );
122 12
        $counter->inc(['all']);
123
124 12
        if (null !== $method && null !== $route) {
125 12
            $counter->inc([sprintf('%s-%s', $method, $route)]);
126
        }
127 12
    }
128
129 3
    private function inc4xxResponsesTotal(?string $method = null, ?string $route = null): void
130
    {
131 3
        $counter = $this->collectionRegistry->getOrRegisterCounter(
132 3
            $this->namespace,
133 3
            'http_4xx_responses_total',
134 3
            'total 4xx response count',
135 3
            ['action']
136
        );
137 3
        $counter->inc(['all']);
138
139 3
        if (null !== $method && null !== $route) {
140 3
            $counter->inc([sprintf('%s-%s', $method, $route)]);
141
        }
142 3
    }
143
144 3
    private function inc5xxResponsesTotal(?string $method = null, ?string $route = null): void
145
    {
146 3
        $counter = $this->collectionRegistry->getOrRegisterCounter(
147 3
            $this->namespace,
148 3
            'http_5xx_responses_total',
149 3
            'total 5xx response count',
150 3
            ['action']
151
        );
152 3
        $counter->inc(['all']);
153
154 3
        if (null !== $method && null !== $route) {
155 3
            $counter->inc([sprintf('%s-%s', $method, $route)]);
156
        }
157 3
    }
158
159 9
    private function setRequestDuration(float $duration, ?string $method = null, ?string $route = null): void
160
    {
161 9
        $histogram = $this->collectionRegistry->getOrRegisterHistogram(
162 9
            $this->namespace,
163 9
            'request_durations_histogram_seconds',
164 9
            'request durations in seconds',
165 9
            ['action']
166
        );
167 9
        $histogram->observe($duration, ['all']);
168
169 9
        if (null !== $method && null !== $route) {
170 9
            $histogram->observe($duration, [sprintf('%s-%s', $method, $route)]);
171
        }
172 9
    }
173
174 9
    public function collectStart(RequestEvent $event)
175
    {
176
        // do not track "OPTIONS" requests
177 9
        if ($event->getRequest()->isMethod('OPTIONS')) {
178
            return;
179
        }
180
181 9
        if (class_exists(self::STOPWATCH_CLASS)) {
182 9
            $className       = self::STOPWATCH_CLASS;
183 9
            $this->stopwatch = new $className();
184 9
            $this->stopwatch->start('execution_time');
185
        }
186 9
    }
187
}
188