33namespace Lamoda \Metric \Responder \ResponseFactory ;
44
55use GuzzleHttp \Psr7 \Response ;
6+ use Lamoda \Metric \Common \MetricInterface ;
67use Lamoda \Metric \Common \MetricSourceInterface ;
78use Lamoda \Metric \Responder \ResponseFactoryInterface ;
89use Psr \Http \Message \ResponseInterface ;
@@ -29,21 +30,128 @@ final class PrometheusResponseFactory implements ResponseFactoryInterface
2930 public function create (MetricSourceInterface $ source , array $ options = []): ResponseInterface
3031 {
3132 $ data = [];
33+ $ histogramMetricsData = [];
34+ $ prefix = $ options ['prefix ' ] ?? '' ;
3235 foreach ($ source ->getMetrics () as $ metric ) {
36+ $ tags = $ metric ->getTags ();
37+
38+ if (isset ($ tags ['_meta ' ]) && ($ tags ['_meta ' ]['type ' ] ?? '' ) === 'histogram ' ) {
39+ $ histogramMetricsData = $ this ->prepareHistogramMetric ($ metric , $ histogramMetricsData );
40+ continue ;
41+ }
42+
3343 $ data [] = [
34- 'name ' => ( $ options [ ' prefix ' ] ?? '' ) . $ metric ->getName (),
44+ 'name ' => $ prefix . $ metric ->getName (),
3545 'value ' => $ metric ->resolve (),
36- 'tags ' => $ metric -> getTags () ,
46+ 'tags ' => $ tags ,
3747 ];
3848 }
49+
50+ $ histogramData = $ this ->calculateHistogramMetric ($ histogramMetricsData , $ prefix );
3951
4052 return new Response (
4153 200 ,
4254 ['Content-Type ' => self ::CONTENT_TYPE ],
43- $ this ->getContent ($ data )
55+ $ this ->getContent (array_merge ( $ data, $ histogramData ) )
4456 );
4557 }
4658
59+ private function buildHistogramMetricHash (MetricInterface $ metric ): string
60+ {
61+ return md5 ($ metric ->getName () . implode ('' , $ this ->clearTags ($ metric ->getTags ())));
62+ }
63+
64+ /**
65+ * @param array<string, string> $tags
66+ * @return array<string, string>
67+ */
68+ private function clearTags (array $ tags ): array
69+ {
70+ if (isset ($ tags ['_meta ' ])) {
71+ unset($ tags ['_meta ' ]);
72+ }
73+
74+ if (isset ($ tags ['le ' ])) {
75+ unset($ tags ['le ' ]);
76+ }
77+
78+ return $ tags ;
79+ }
80+
81+ /**
82+ * @param array<string, array<string, mixed>> $preparedHistogramMetricsData
83+ * @return array<string, array<string, mixed>>
84+ */
85+ private function prepareHistogramMetric (MetricInterface $ metric , array $ preparedHistogramMetricsData ): array
86+ {
87+ $ tags = $ metric ->getTags ();
88+ $ metaTags = $ tags ['_meta ' ];
89+ $ le = $ tags ['le ' ] ?? null ;
90+ $ tags = $ this ->clearTags ($ tags );
91+ $ keyMetric = $ this ->buildHistogramMetricHash ($ metric );
92+
93+ if (!isset ($ preparedHistogramMetricsData [$ keyMetric ])) {
94+ $ preparedHistogramMetricsData [$ keyMetric ] = [
95+ 'name ' => $ metric ->getName (),
96+ 'buckets ' => $ metaTags ['buckets ' ],
97+ 'tags ' => $ tags ,
98+ 'data ' => [],
99+ 'sum ' => 0 ,
100+ ];
101+ }
102+
103+ if (isset ($ metaTags ['is_sum ' ])) {
104+ $ preparedHistogramMetricsData [$ keyMetric ]['sum ' ] = $ metric ->resolve ();
105+ }
106+
107+ if ($ le !== null ) {
108+ $ preparedHistogramMetricsData [$ keyMetric ]['data ' ][(string ) $ le ] = $ metric ->resolve ();
109+ }
110+
111+ return $ preparedHistogramMetricsData ;
112+ }
113+
114+ /**
115+ * @return array<string, array<int, mixed>> $histogramMetricsData
116+ * @return array<int, array<string, string>>
117+ */
118+ private function calculateHistogramMetric (array $ histogramMetricsData , string $ prefix = '' ): array
119+ {
120+ $ data = [];
121+ foreach ($ histogramMetricsData as $ histogramMetricData ) {
122+ $ total = 0 ;
123+ $ buckets = $ histogramMetricData ['buckets ' ];
124+ if (!in_array ('+Inf ' , $ buckets )) {
125+ $ buckets [] = '+Inf ' ;
126+ }
127+
128+ foreach ($ buckets as $ bucket ) {
129+ $ value = $ histogramMetricData ['data ' ][(string )$ bucket ] ?? 0 ;
130+ $ total += $ value ;
131+
132+ $ data [] = [
133+ 'name ' => $ prefix . $ histogramMetricData ['name ' ] . '_bucket ' ,
134+ 'value ' => $ total ,
135+ 'tags ' => array_merge ($ histogramMetricData ['tags ' ], ['le ' => (string ) $ bucket ])
136+ ];
137+ }
138+
139+ $ data [] = [
140+ 'name ' => $ prefix . $ histogramMetricData ['name ' ] . '_sum ' ,
141+ 'value ' => $ histogramMetricData ['sum ' ],
142+ 'tags ' => $ histogramMetricData ['tags ' ],
143+ ];
144+
145+ $ data [] = [
146+ 'name ' => $ prefix . $ histogramMetricData ['name ' ] . '_count ' ,
147+ 'value ' => $ total ,
148+ 'tags ' => $ histogramMetricData ['tags ' ],
149+ ];
150+ }
151+
152+ return $ data ;
153+ }
154+
47155 /**
48156 * Get response content.
49157 *
0 commit comments