]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/exporters/prometheus/test/prometheus_exporter_utils_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / exporters / prometheus / test / prometheus_exporter_utils_test.cc
CommitLineData
1e59de90
TL
1// Copyright The OpenTelemetry Authors
2// SPDX-License-Identifier: Apache-2.0
3
4#ifdef ENABLE_METRICS_PREVIEW
5# include <gtest/gtest.h>
6# include <map>
7# include <numeric>
8# include <string>
9# include <typeinfo>
10
11# include <opentelemetry/version.h>
12# include "opentelemetry/exporters/prometheus/prometheus_exporter_utils.h"
13# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
14# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
15# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
16# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
17# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
18# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
19
20using opentelemetry::exporter::prometheus::PrometheusExporterUtils;
21namespace metric_sdk = opentelemetry::sdk::metrics;
22namespace metric_api = opentelemetry::metrics;
23namespace prometheus_client = ::prometheus;
24
25OPENTELEMETRY_BEGIN_NAMESPACE
26template <typename T>
27void assert_basic(prometheus_client::MetricFamily &metric,
28 const std::string &sanitized_name,
29 const std::string &description,
30 prometheus_client::MetricType type,
31 int label_num,
32 std::vector<T> vals)
33{
34 ASSERT_EQ(metric.name, sanitized_name); // name sanitized
35 ASSERT_EQ(metric.help, description); // description not changed
36 ASSERT_EQ(metric.type, type); // type translated
37
38 auto metric_data = metric.metric[0];
39 ASSERT_EQ(metric_data.label.size(), label_num);
40
41 switch (type)
42 {
43 case prometheus_client::MetricType::Counter: {
44 ASSERT_DOUBLE_EQ(metric_data.counter.value, vals[0]);
45 break;
46 }
47 case prometheus_client::MetricType::Gauge: {
48 ASSERT_EQ(metric_data.gauge.value, vals[0]);
49 break;
50 }
51 case prometheus_client::MetricType::Histogram: {
52 ASSERT_DOUBLE_EQ(metric_data.histogram.sample_count, vals[0]);
53 ASSERT_DOUBLE_EQ(metric_data.histogram.sample_sum, vals[1]);
54 auto buckets = metric_data.histogram.bucket;
55 ASSERT_EQ(buckets.size(), vals[2]);
56 break;
57 }
58 case prometheus_client::MetricType::Summary: {
59 ASSERT_DOUBLE_EQ(metric_data.summary.sample_count, vals[0]);
60 ASSERT_DOUBLE_EQ(metric_data.summary.sample_sum, vals[1]);
61 break;
62 }
63 case prometheus::MetricType::Untyped:
64 break;
65 }
66}
67
68void assert_histogram(prometheus_client::MetricFamily &metric,
69 std::vector<double> boundaries,
70 std::vector<int> correct)
71{
72 int cumulative_count = 0;
73 auto buckets = metric.metric[0].histogram.bucket;
74 for (size_t i = 0; i < buckets.size(); i++)
75 {
76 auto bucket = buckets[i];
77 if (i != buckets.size() - 1)
78 {
79 ASSERT_DOUBLE_EQ(boundaries[i], bucket.upper_bound);
80 }
81 else
82 {
83 ASSERT_DOUBLE_EQ(std::numeric_limits<double>::infinity(), bucket.upper_bound);
84 }
85 cumulative_count += correct[i];
86 ASSERT_EQ(cumulative_count, bucket.cumulative_count);
87 }
88}
89
90template <typename T>
91metric_sdk::Record get_record(const std::string &type,
92 int version,
93 const std::string &label,
94 std::shared_ptr<metric_sdk::Aggregator<T>> aggregator)
95{
96 std::string name = "test-" + type + "-metric-record-v_" + std::to_string(version) + ".0";
97 std::string desc = "this is a test " + type + " metric record";
98 metric_sdk::Record record(name, desc, label, aggregator);
99 return record;
100}
101
102TEST(PrometheusExporterUtils, TranslateToPrometheusEmptyInputReturnsEmptyCollection)
103{
104 std::vector<metric_sdk::Record> collection;
105 auto translated2 = PrometheusExporterUtils::TranslateToPrometheus(collection);
106 ASSERT_EQ(translated2.size(), 0);
107}
108
109TEST(PrometheusExporterUtils, TranslateToPrometheusIntegerCounter)
110{
111 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
112 new metric_sdk::CounterAggregator<int>(metric_api::InstrumentKind::Counter));
113
114 std::vector<metric_sdk::Record> collection;
115
116 auto record1 = get_record("int-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
117 aggregator->update(10);
118 aggregator->checkpoint();
119 collection.emplace_back(record1);
120
121 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
122 ASSERT_EQ(translated.size(), collection.size());
123
124 auto metric1 = translated[0];
125 std::vector<int> vals = {10};
126 assert_basic(metric1, "test_int_counter_metric_record_v_1_0", record1.GetDescription(),
127 prometheus_client::MetricType::Counter, 3, vals);
128
129 auto record2 = get_record("int-counter", 2, "{,}", aggregator);
130 aggregator->update(20);
131 aggregator->update(30);
132 aggregator->checkpoint();
133 collection.emplace_back(record2);
134
135 translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
136 ASSERT_EQ(translated.size(), collection.size());
137
138 auto metric2 = translated[1];
139 vals = {50};
140 assert_basic(metric2, "test_int_counter_metric_record_v_2_0", record2.GetDescription(),
141 prometheus_client::MetricType::Counter, 0, vals);
142}
143
144TEST(PrometheusExporterUtils, TranslateToPrometheusDoubleCounter)
145{
146 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
147 new metric_sdk::CounterAggregator<double>(metric_api::InstrumentKind::Counter));
148
149 std::vector<metric_sdk::Record> collection;
150 aggregator->update(10.5);
151 aggregator->checkpoint();
152 auto record1 = get_record("double-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
153 aggregator->update(22.4);
154 aggregator->update(31.2);
155 aggregator->checkpoint();
156 auto record2 = get_record("double-counter", 2, "{,}", aggregator);
157 collection.emplace_back(record1);
158 collection.emplace_back(record2);
159
160 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
161 ASSERT_EQ(translated.size(), collection.size());
162
163 auto metric1 = translated[0];
164 std::vector<double> vals = {53.6};
165 assert_basic(metric1, "test_double_counter_metric_record_v_1_0", record1.GetDescription(),
166 prometheus_client::MetricType::Counter, 3, vals);
167 auto metric2 = translated[1];
168 assert_basic(metric2, "test_double_counter_metric_record_v_2_0", record2.GetDescription(),
169 prometheus_client::MetricType::Counter, 0, vals);
170}
171
172TEST(PrometheusExporterUtils, TranslateToPrometheusShortCounter)
173{
174 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
175 new metric_sdk::CounterAggregator<short>(metric_api::InstrumentKind::Counter));
176
177 std::vector<metric_sdk::Record> collection;
178 aggregator->update(10);
179 aggregator->checkpoint();
180 auto record1 = get_record("short-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
181 aggregator->update(20);
182 aggregator->update(30);
183 aggregator->checkpoint();
184 auto record2 = get_record("short-counter", 2, "{,}", aggregator);
185 collection.emplace_back(record1);
186 collection.emplace_back(record2);
187
188 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
189 ASSERT_EQ(translated.size(), collection.size());
190
191 auto metric1 = translated[0];
192 std::vector<short> vals = {50};
193 assert_basic(metric1, "test_short_counter_metric_record_v_1_0", record1.GetDescription(),
194 prometheus_client::MetricType::Counter, 3, vals);
195 auto metric2 = translated[1];
196 assert_basic(metric2, "test_short_counter_metric_record_v_2_0", record2.GetDescription(),
197 prometheus_client::MetricType::Counter, 0, vals);
198}
199
200TEST(PrometheusExporterUtils, TranslateToPrometheusFloatCounter)
201{
202 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
203 new metric_sdk::CounterAggregator<float>(metric_api::InstrumentKind::Counter));
204
205 std::vector<metric_sdk::Record> collection;
206 aggregator->update(10.5f);
207 aggregator->checkpoint();
208 auto record1 = get_record("float-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
209 aggregator->update(22.4f);
210 aggregator->update(31.2f);
211 aggregator->checkpoint();
212 auto record2 = get_record("float-counter", 2, "{,}", aggregator);
213 collection.emplace_back(record1);
214 collection.emplace_back(record2);
215
216 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
217 ASSERT_EQ(translated.size(), collection.size());
218
219 auto metric1 = translated[0];
220 std::vector<float> vals = {53.6f};
221 assert_basic(metric1, "test_float_counter_metric_record_v_1_0", record1.GetDescription(),
222 prometheus_client::MetricType::Counter, 3, vals);
223 auto metric2 = translated[1];
224 assert_basic(metric2, "test_float_counter_metric_record_v_2_0", record2.GetDescription(),
225 prometheus_client::MetricType::Counter, 0, vals);
226}
227
228TEST(PrometheusExporterUtils, TranslateToPrometheusGauge)
229{
230 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
231 new metric_sdk::GaugeAggregator<int>(metric_api::InstrumentKind::Counter));
232
233 std::vector<metric_sdk::Record> collection;
234 aggregator->update(10);
235 aggregator->checkpoint();
236 auto record1 = get_record("gauge", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
237 aggregator->update(20);
238 aggregator->update(30);
239 aggregator->checkpoint();
240 auto record2 = get_record("gauge", 2, "{,}", aggregator);
241 collection.emplace_back(record1);
242 collection.emplace_back(record2);
243
244 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
245 ASSERT_EQ(translated.size(), collection.size());
246
247 auto metric1 = translated[0];
248 std::vector<int> vals = {30};
249 assert_basic(metric1, "test_gauge_metric_record_v_1_0", record1.GetDescription(),
250 prometheus_client::MetricType::Gauge, 3, vals);
251 auto metric2 = translated[1];
252 assert_basic(metric2, "test_gauge_metric_record_v_2_0", record2.GetDescription(),
253 prometheus_client::MetricType::Gauge, 0, vals);
254}
255
256TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramUniform)
257{
258 std::vector<double> boundaries{10, 20, 30, 40, 50};
259 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
260 new metric_sdk::HistogramAggregator<int>(metric_api::InstrumentKind::Counter, boundaries));
261
262 std::vector<metric_sdk::Record> collection;
263 auto record = get_record("histogram-uniform", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
264 int count_num = 60;
265 for (int i = 0; i < count_num; i++)
266 {
267 aggregator->update(i);
268 }
269 aggregator->checkpoint();
270 collection.emplace_back(record);
271
272 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
273 ASSERT_EQ(translated.size(), collection.size());
274
275 auto metric = translated[0];
276 std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0],
277 (int)boundaries.size() + 1};
278 assert_basic(metric, "test_histogram_uniform_metric_record_v_1_0", record.GetDescription(),
279 prometheus_client::MetricType::Histogram, 3, vals);
280 std::vector<int> correct = aggregator->get_counts();
281 assert_histogram(metric, boundaries, correct);
282}
283
284TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramNormal)
285{
286 std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
287 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
288 new metric_sdk::HistogramAggregator<int>(metric_api::InstrumentKind::Counter, boundaries));
289
290 std::vector<metric_sdk::Record> collection;
291 auto record = get_record("histogram-normal", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
292 std::vector<int> values{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
293 for (int i : values)
294 {
295 aggregator->update(i);
296 }
297 aggregator->checkpoint();
298 collection.emplace_back(record);
299
300 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
301 ASSERT_EQ(translated.size(), collection.size());
302
303 auto metric = translated[0];
304 std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0],
305 (int)boundaries.size() + 1};
306 assert_basic(metric, "test_histogram_normal_metric_record_v_1_0", record.GetDescription(),
307 prometheus_client::MetricType::Histogram, 3, vals);
308 std::vector<int> correct = aggregator->get_counts();
309 assert_histogram(metric, boundaries, correct);
310}
311
312TEST(PrometheusExporterUtils, TranslateToPrometheusExact)
313{
314 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
315 new metric_sdk::ExactAggregator<int>(metric_api::InstrumentKind::Counter, true));
316
317 std::vector<metric_sdk::Record> collection;
318 int count_num = 100;
319 for (int i = 0; i <= count_num; i++)
320 {
321 aggregator->update(i);
322 }
323 aggregator->checkpoint();
324 auto record = get_record("exact", 1, "{label-1:v1,label_2:v2,label3:v3,}", aggregator);
325 collection.emplace_back(record);
326
327 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
328 ASSERT_EQ(translated.size(), collection.size());
329
330 auto metric = translated[0];
331 std::vector<int> vals = {101, 5050};
332 assert_basic(metric, "test_exact_metric_record_v_1_0", record.GetDescription(),
333 prometheus_client::MetricType::Summary, 3, vals);
334 auto quantile = metric.metric[0].summary.quantile;
335 ASSERT_EQ(quantile.size(), 6);
336 ASSERT_DOUBLE_EQ(quantile[0].value, 0);
337 ASSERT_DOUBLE_EQ(quantile[1].value, 50);
338 ASSERT_DOUBLE_EQ(quantile[2].value, 90);
339 ASSERT_DOUBLE_EQ(quantile[3].value, 95);
340 ASSERT_DOUBLE_EQ(quantile[4].value, 99);
341 ASSERT_DOUBLE_EQ(quantile[5].value, 100);
342}
343
344TEST(PrometheusExporterUtils, TranslateToPrometheusExactNoQuantile)
345{
346 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
347 new metric_sdk::ExactAggregator<int>(metric_api::InstrumentKind::Counter, false));
348
349 std::vector<metric_sdk::Record> collection;
350 int count_num = 10;
351 for (int i = 0; i < count_num; i++)
352 {
353 aggregator->update(i);
354 }
355 aggregator->checkpoint();
356 auto record = get_record("exact-no-quantile", 1, "{label1:v1,label2:v2,}", aggregator);
357 collection.emplace_back(record);
358
359 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
360 ASSERT_EQ(translated.size(), collection.size());
361
362 auto metric = translated[0];
363 std::vector<int> vals = {count_num, 45};
364 assert_basic(metric, "test_exact_no_quantile_metric_record_v_1_0", record.GetDescription(),
365 prometheus_client::MetricType::Summary, 2, vals);
366 auto quantile = metric.metric[0].summary.quantile;
367 ASSERT_EQ(quantile.size(), 0);
368}
369
370TEST(PrometheusExporterUtils, TranslateToPrometheusMinMaxSumCount)
371{
372 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
373 new metric_sdk::MinMaxSumCountAggregator<int>(metric_api::InstrumentKind::Counter));
374
375 std::vector<metric_sdk::Record> collection;
376 // min: 1, max: 10, sum: 55, count: 10
377 for (int i = 1; i <= 10; i++)
378 {
379 aggregator->update(i);
380 }
381 aggregator->checkpoint();
382 auto record = get_record("mmsc", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
383 collection.emplace_back(record);
384
385 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
386 ASSERT_EQ(translated.size(), collection.size());
387
388 auto metric = translated[0];
389 // in this version of implementation, we use the sum/count as a gauge
390 std::vector<double> vals = {5.5};
391 assert_basic(metric, "test_mmsc_metric_record_v_1_0", record.GetDescription(),
392 prometheus_client::MetricType::Gauge, 3, vals);
393}
394
395TEST(PrometheusExporterUtils, TranslateToPrometheusSketch)
396{
397 auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
398 new metric_sdk::SketchAggregator<int>(metric_api::InstrumentKind::Counter, 0.0005));
399
400 std::vector<metric_sdk::Record> collection;
401 for (int i = 0; i <= 100; i++)
402 {
403 aggregator->update(i);
404 }
405 aggregator->checkpoint();
406 auto record = get_record("sketch", 1, "{label1:v1,label2:v2,}", aggregator);
407 collection.emplace_back(record);
408
409 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
410 ASSERT_EQ(translated.size(), collection.size());
411
412 auto metric = translated[0];
413 std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0]};
414 assert_basic(metric, "test_sketch_metric_record_v_1_0", record.GetDescription(),
415 prometheus_client::MetricType::Summary, 2, vals);
416
417 auto quantile = metric.metric[0].summary.quantile;
418 ASSERT_EQ(quantile.size(), 6);
419 ASSERT_DOUBLE_EQ(quantile[0].value, 0);
420 ASSERT_DOUBLE_EQ(quantile[1].value, 49);
421 ASSERT_DOUBLE_EQ(quantile[2].value, 89);
422 ASSERT_DOUBLE_EQ(quantile[3].value, 94);
423 ASSERT_DOUBLE_EQ(quantile[4].value, 98);
424 ASSERT_DOUBLE_EQ(quantile[5].value, 99);
425}
426
427TEST(PrometheusExporterUtils, TranslateToPrometheusMultipleAggregators)
428{
429 auto counter_aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
430 new metric_sdk::CounterAggregator<double>(metric_api::InstrumentKind::Counter));
431 auto gauge_aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
432 new metric_sdk::GaugeAggregator<int>(metric_api::InstrumentKind::Counter));
433
434 std::vector<metric_sdk::Record> collection;
435 counter_aggregator->update(10);
436 counter_aggregator->update(20);
437 counter_aggregator->checkpoint();
438 auto record1 = get_record("counter", 1, "{label1:v1,label2:v2,label3:v3,}", counter_aggregator);
439 gauge_aggregator->update(10);
440 gauge_aggregator->update(30);
441 gauge_aggregator->update(20);
442 gauge_aggregator->checkpoint();
443 auto record2 = get_record("gauge", 1, "{label1:v1,}", gauge_aggregator);
444 collection.emplace_back(record1);
445 collection.emplace_back(record2);
446
447 auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
448 ASSERT_EQ(translated.size(), collection.size());
449
450 auto metric1 = translated[0];
451 std::vector<int> vals = {30};
452 assert_basic(metric1, "test_counter_metric_record_v_1_0", record1.GetDescription(),
453 prometheus_client::MetricType::Counter, 3, vals);
454 auto metric2 = translated[1];
455 vals = {20};
456 assert_basic(metric2, "test_gauge_metric_record_v_1_0", record2.GetDescription(),
457 prometheus_client::MetricType::Gauge, 1, vals);
458}
459OPENTELEMETRY_END_NAMESPACE
460#endif