📜 ⬆️ ⬇️

Symfony Bundle for exporting statistics in Prometheus format



While working on different micro (and not so) services written using symfony, I faced the need to export metrics for Prometheus each time. At first, we simply copied the same code between projects, but when there were more than three of them, I decided that I could not continue like this (I won’t bore you with explanations why this is inconvenient; I think everyone understands this himself).

It was decided to allocate all this household into a separate bundle: ArtprimaPrometheusMetricsBundle .

Having chosen common metrics for all applications, I started writing a bundle. The Jimdo / prometheus_client_php client was selected as the library, which allows using the following statistics as storage: Redis (via ext-redis), APCu (via ext-apcu) and InMemory (in PHP memory, only for the duration of the process). I’ll make a reservation right away that in practice we only have APCu (I needed to have per-instance statistics, whereas in Redis they will be shared, unless I deploy Redis to each instance). And InMemory in general, IMHO, can only be used for tests.
')
With Jimdo / prometheus_client_php, a problem immediately arose - there was no release for a long time, and the necessary features (APCu) in the form of a release are not available. In this regard, I made my fork client , which differs only in the fact that there is a necessary tag for the formation of the release.

The second problem I encountered is recipes for symfony. In the official repo, you can not even meddle, and in the community for a very long time, there are pull-requests (at the moment the bundle is almost a month, and the PR recipe is still under consideration). In this connection, during installation, you need to carry out the necessary settings manually. The benefit of them is not so much.

Actually, you need to configure the main configuration:

#config/packages/prometheus-metrics.yaml artprima_prometheus_metrics: # namespace     prometheus namespace: myapp #    type: in_memory #  : in_memory, apcu, redis #   ,         ignored_routes: [some_route_name, another_route_name] #     "redis" (   ) redis: host: 127.0.0.1 port: 6379 timeout: 0.1 read_timeout: 10 persistent_connections: false password: ~ 

Then you need to export the route:

 #    /metrics/prometheus app_metrics: resource: '@ArtprimaPrometheusMetricsBundle/Resources/config/routing.xml' 

Alternatively, you can configure the route manually:

 app_metrics: path: /mypath/mymetrics controller: Artprima\PrometheusMetricsBundle\Controller\MetricsController::prometheus 

Is done. As a result, your metrics will be available at http [s]: // your_host / metrics / prometheus (if you have not changed the path). And after some time you get something like this:

metrics example
# HELP myapp_http_2xx_responses_total total 2xx response count
# TYPE myapp_http_2xx_responses_total counter
myapp_http_2xx_responses_total{action="GET-app_ep1"} 3911
myapp_http_2xx_responses_total{action="GET-app_ep2"} 29974
myapp_http_2xx_responses_total{action="GET-app_ep3"} 323
myapp_http_2xx_responses_total{action="GET-app_ep4"} 18
myapp_http_2xx_responses_total{action="GET-app_ep5"} 3627
myapp_http_2xx_responses_total{action="GET-app_search"} 5962
myapp_http_2xx_responses_total{action="GET-app_ep8"} 42967
myapp_http_2xx_responses_total{action="GET-app_variants"} 641
myapp_http_2xx_responses_total{action="all"} 87423
# HELP myapp_http_4xx_responses_total total 4xx response count
# TYPE myapp_http_4xx_responses_total counter
myapp_http_4xx_responses_total{action="GET-app_ep2"} 71
myapp_http_4xx_responses_total{action="GET-app_ep8"} 2584
myapp_http_4xx_responses_total{action="all"} 2660
# HELP myapp_http_requests_total total request count
# TYPE myapp_http_requests_total counter
myapp_http_requests_total{action="GET-app_ep1"} 3922
myapp_http_requests_total{action="GET-app_ep2"} 30098
myapp_http_requests_total{action="GET-app_ep3"} 468
myapp_http_requests_total{action="GET-app_ep4"} 18
myapp_http_requests_total{action="GET-app_ep5"} 3631
myapp_http_requests_total{action="GET-app_search"} 5964
myapp_http_requests_total{action="GET-app_ep8"} 45556
myapp_http_requests_total{action="GET-app_variants"} 644
myapp_http_requests_total{action="all"} 90301
# HELP myapp_instance_name app instance name
# TYPE myapp_instance_name gauge
myapp_instance_name{instance="myapp-77c4d96744-cf9nz"} 1
# HELP myapp_request_durations_histogram_seconds request durations in seconds
# TYPE myapp_request_durations_histogram_seconds histogram
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.025"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.05"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.075"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.1"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.25"} 59
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.5"} 1915
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="0.75"} 3115
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="1"} 3553
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="2.5"} 3879
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="5"} 3911
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="7.5"} 3911
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="10"} 3911
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep1",le="+Inf"} 3911
myapp_request_durations_histogram_seconds_count{action="GET-app_ep1"} 3911
myapp_request_durations_histogram_seconds_sum{action="GET-app_ep1"} 2413.185
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.025"} 50
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.05"} 62
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.075"} 63
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.1"} 72
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.25"} 914
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.5"} 2761
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="0.75"} 14326
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="1"} 23571
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="2.5"} 29569
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="5"} 30045
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="7.5"} 30045
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="10"} 30045
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep2",le="+Inf"} 30045
myapp_request_durations_histogram_seconds_count{action="GET-app_ep2"} 30045
myapp_request_durations_histogram_seconds_sum{action="GET-app_ep2"} 26552.86
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.005"} 141
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.01"} 144
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.025"} 144
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.05"} 144
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.075"} 145
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.1"} 145
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.25"} 145
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.5"} 199
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="0.75"} 408
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="1"} 442
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="2.5"} 468
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="5"} 468
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="7.5"} 468
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="10"} 468
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep3",le="+Inf"} 468
myapp_request_durations_histogram_seconds_count{action="GET-app_ep3"} 468
myapp_request_durations_histogram_seconds_sum{action="GET-app_ep3"} 216.495
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.025"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.05"} 4
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.075"} 10
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.1"} 13
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.25"} 16
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.5"} 17
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="0.75"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="1"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="2.5"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="5"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="7.5"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="10"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep4",le="+Inf"} 18
myapp_request_durations_histogram_seconds_count{action="GET-app_ep4"} 18
myapp_request_durations_histogram_seconds_sum{action="GET-app_ep4"} 2.291
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.025"} 1
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.05"} 16
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.075"} 97
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.1"} 269
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.25"} 2308
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.5"} 3351
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="0.75"} 3566
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="1"} 3612
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="2.5"} 3627
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="5"} 3627
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="7.5"} 3627
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="10"} 3627
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep5",le="+Inf"} 3627
myapp_request_durations_histogram_seconds_count{action="GET-app_ep5"} 3627
myapp_request_durations_histogram_seconds_sum{action="GET-app_ep5"} 959.773
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.025"} 18
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.05"} 547
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.075"} 968
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.1"} 1387
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.25"} 3784
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.5"} 5377
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="0.75"} 5811
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="1"} 5913
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="2.5"} 5959
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="5"} 5960
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="7.5"} 5960
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="10"} 5960
myapp_request_durations_histogram_seconds_bucket{action="GET-app_search",le="+Inf"} 5962
myapp_request_durations_histogram_seconds_count{action="GET-app_search"} 5962
myapp_request_durations_histogram_seconds_sum{action="GET-app_search"} 1516.982
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.025"} 2724
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.05"} 8348
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.075"} 18828
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.1"} 28811
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.25"} 39709
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.5"} 43958
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="0.75"} 45161
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="1"} 45436
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="2.5"} 45541
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="5"} 45549
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="7.5"} 45549
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="10"} 45549
myapp_request_durations_histogram_seconds_bucket{action="GET-app_ep8",le="+Inf"} 45551
myapp_request_durations_histogram_seconds_count{action="GET-app_ep8"} 45551
myapp_request_durations_histogram_seconds_sum{action="GET-app_ep8"} 6125.712
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.005"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.01"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.025"} 0
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.05"} 252
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.075"} 451
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.1"} 511
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.25"} 583
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.5"} 631
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="0.75"} 640
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="1"} 641
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="2.5"} 641
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="5"} 641
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="7.5"} 641
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="10"} 641
myapp_request_durations_histogram_seconds_bucket{action="GET-app_variants",le="+Inf"} 641
myapp_request_durations_histogram_seconds_count{action="GET-app_variants"} 641
myapp_request_durations_histogram_seconds_sum{action="GET-app_variants"} 62.744
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.005"} 145
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.01"} 148
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.025"} 2942
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.05"} 9378
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.075"} 20567
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.1"} 31213
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.25"} 47523
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.5"} 58214
myapp_request_durations_histogram_seconds_bucket{action="all",le="0.75"} 73050
myapp_request_durations_histogram_seconds_bucket{action="all",le="1"} 83191
myapp_request_durations_histogram_seconds_bucket{action="all",le="2.5"} 89707
myapp_request_durations_histogram_seconds_bucket{action="all",le="5"} 90224
myapp_request_durations_histogram_seconds_bucket{action="all",le="7.5"} 90224
myapp_request_durations_histogram_seconds_bucket{action="all",le="10"} 90224
myapp_request_durations_histogram_seconds_bucket{action="all",le="+Inf"} 90228
myapp_request_durations_histogram_seconds_count{action="all"} 90228
myapp_request_durations_histogram_seconds_sum{action="all"} 37850.074


Naturally, the basic metrics may not be enough soon, so you always have the opportunity to write your own metrics generator (in addition to the existing one) and export it like this:

 # config/services.yaml App\Metrics\MyMetricsGenerator: tags: - { name: prometheus_metrics_bundle.metrics_generator } 

In this case, your generator must implement the Artprima\PrometheusMetricsBundle\Metrics\MetricsGeneratorInterface . You can see what a generator might look like in Artprima\PrometheusMetricsBundle\Metrics\AppMetrics . The main thing you need to know here is that the collectRequest method collectRequest called on the kernel.request event, and the collectResponse method is collectResponse on the kernel.terminate event.

I accept criticism on the merits. Both in the form of tips and PR :-)

PS Warning comments that we invented the bicycle: yes, I know that there are alternatives. And, most likely, they are certainly better. In particular, one of them is TweedeGolfPrometheusBundle . Unfortunately, I don’t remember why we didn’t choose this solution, but a little more than six months ago we tried it and refused it. One way or another, I think that having a choice is always good, so our bundle was published in OpenSource.

Source: https://habr.com/ru/post/429800/


All Articles