Slim3Setup::getPathWithMethods()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 9
rs 9.6666
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of the PHPProm package.
5
 *
6
 * (c) Philip Lehmann-Böhm <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace PHPProm\Integration;
13
14
use \Psr\Http\Message\ServerRequestInterface as Request;
15
use \Psr\Http\Message\ResponseInterface as Response;
16
use \Slim\App;
17
use PHPProm\PrometheusExport;
18
use PHPProm\Storage\AbstractStorage;
19
use PHPProm\StopWatch;
20
use Slim\Route;
21
22
/**
23
 * Class Slim3Setup
24
 * Setups Slim applications to measure:
25
 * - the time of each route
26
 * - the used memory of each route
27
 * - the amount of requests of each route
28
 * It also offers an function to be used for a Prometheus scrapable endpoint.
29
 * @package PHPProm\Integration
30
 */
31
class Slim3Setup {
32
33
34
    /**
35
     * Sets up the Slim middleware where the actual measurements happen.
36
     *
37
     * @param App $app
38
     * the Silex application
39
     * @param AbstractStorage $storage
40
     * the storage for the measurements
41
     */
42
    protected function setupMiddleware(App $app, AbstractStorage $storage) {
43
        $storage->addAvailableMetric('route_time', 'name', 'request times per route in seconds', 'gauge', 'Nan');
44
        $storage->addAvailableMetric('route_memory', 'name', 'request memory per route in bytes', 'gauge', 'Nan');
45
        $storage->addAvailableMetric('route_requests_total', 'name', 'total requests per route', 'counter', 0);
46
47
        $app->add(function(Request $request, Response $response, App $next) use ($storage) {
48
            $method    = $request->getMethod();
49
            $pattern   = str_replace('/', '_', $request->getAttribute('route')->getPattern());
50
            $route     = $method.$pattern;
51
            $routeTime = new StopWatch($storage);
52
            $routeTime->start();
53
            $response = $next($request, $response);
54
            $routeTime->stop('route_time', $route);
55
            $storage->storeMeasurement('route_memory', $route, memory_get_peak_usage(true));
56
            $storage->incrementMeasurement('route_requests_total', $route);
57
            return $response;
58
        });
59
    }
60
61
    /**
62
     * Gets the path with all methods from a route.
63
     *
64
     * @param Route $route
65
     * the route to get the path and methods from
66
     * @return array
67
     * the pathes with methods
68
     */
69
    protected function getPathWithMethods(Route $route) {
70
        $routes  = [];
71
        $pattern = str_replace('/', '_', $route->getPattern());
72
        $methods = $route->getMethods();
73
        foreach ($methods as $method) {
74
            $routes[] = $method.$pattern;
75
        }
76
        return $routes;
77
    }
78
79
    /**
80
     * Sets up the Slim middlewares where the actual measurements happen
81
     * and returns a function to be used for a Prometheus scrapable endpoint.
82
     *
83
     * @param App $app
84
     * the Slim application
85
     * @param AbstractStorage $storage
86
     * the storage for the measurements
87
     *
88
     * @return \Closure
89
     * the function to be used for a Prometheus scrapable endpoint
90
     */
91
    public function setupAndGetMetricsRoute(App $app, AbstractStorage $storage) {
92
        $this->setupMiddleware($app, $storage);
93
        $self = $this;
94
        return function(Request $request, Response $response) use ($app, $storage, $self) {
95
            $routes          = [];
96
            $availableRoutes = $app->getContainer()->get('router')->getRoutes();
97
            foreach ($availableRoutes as $route) {
98
                $routes = array_merge($routes, $self->getPathWithMethods($route));
99
            }
100
            $export       = new PrometheusExport();
101
            $responseBody = $export->getExport($storage, $routes);
102
103
            $response = $response->withHeader('Content-type', 'text/plain; version=0.0.4');
104
            $response->getBody()->write($responseBody);
105
106
        };
107
    }
108
}
109