]> git.proxmox.com Git - ceph.git/blobdiff - 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
diff --git a/ceph/src/jaegertracing/opentelemetry-cpp/exporters/prometheus/test/prometheus_exporter_utils_test.cc b/ceph/src/jaegertracing/opentelemetry-cpp/exporters/prometheus/test/prometheus_exporter_utils_test.cc
new file mode 100644 (file)
index 0000000..22ce3f5
--- /dev/null
@@ -0,0 +1,460 @@
+// Copyright The OpenTelemetry Authors
+// SPDX-License-Identifier: Apache-2.0
+
+#ifdef ENABLE_METRICS_PREVIEW
+#  include <gtest/gtest.h>
+#  include <map>
+#  include <numeric>
+#  include <string>
+#  include <typeinfo>
+
+#  include <opentelemetry/version.h>
+#  include "opentelemetry/exporters/prometheus/prometheus_exporter_utils.h"
+#  include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
+#  include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
+#  include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
+#  include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
+#  include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
+#  include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
+
+using opentelemetry::exporter::prometheus::PrometheusExporterUtils;
+namespace metric_sdk        = opentelemetry::sdk::metrics;
+namespace metric_api        = opentelemetry::metrics;
+namespace prometheus_client = ::prometheus;
+
+OPENTELEMETRY_BEGIN_NAMESPACE
+template <typename T>
+void assert_basic(prometheus_client::MetricFamily &metric,
+                  const std::string &sanitized_name,
+                  const std::string &description,
+                  prometheus_client::MetricType type,
+                  int label_num,
+                  std::vector<T> vals)
+{
+  ASSERT_EQ(metric.name, sanitized_name);  // name sanitized
+  ASSERT_EQ(metric.help, description);     // description not changed
+  ASSERT_EQ(metric.type, type);            // type translated
+
+  auto metric_data = metric.metric[0];
+  ASSERT_EQ(metric_data.label.size(), label_num);
+
+  switch (type)
+  {
+    case prometheus_client::MetricType::Counter: {
+      ASSERT_DOUBLE_EQ(metric_data.counter.value, vals[0]);
+      break;
+    }
+    case prometheus_client::MetricType::Gauge: {
+      ASSERT_EQ(metric_data.gauge.value, vals[0]);
+      break;
+    }
+    case prometheus_client::MetricType::Histogram: {
+      ASSERT_DOUBLE_EQ(metric_data.histogram.sample_count, vals[0]);
+      ASSERT_DOUBLE_EQ(metric_data.histogram.sample_sum, vals[1]);
+      auto buckets = metric_data.histogram.bucket;
+      ASSERT_EQ(buckets.size(), vals[2]);
+      break;
+    }
+    case prometheus_client::MetricType::Summary: {
+      ASSERT_DOUBLE_EQ(metric_data.summary.sample_count, vals[0]);
+      ASSERT_DOUBLE_EQ(metric_data.summary.sample_sum, vals[1]);
+      break;
+    }
+    case prometheus::MetricType::Untyped:
+      break;
+  }
+}
+
+void assert_histogram(prometheus_client::MetricFamily &metric,
+                      std::vector<double> boundaries,
+                      std::vector<int> correct)
+{
+  int cumulative_count = 0;
+  auto buckets         = metric.metric[0].histogram.bucket;
+  for (size_t i = 0; i < buckets.size(); i++)
+  {
+    auto bucket = buckets[i];
+    if (i != buckets.size() - 1)
+    {
+      ASSERT_DOUBLE_EQ(boundaries[i], bucket.upper_bound);
+    }
+    else
+    {
+      ASSERT_DOUBLE_EQ(std::numeric_limits<double>::infinity(), bucket.upper_bound);
+    }
+    cumulative_count += correct[i];
+    ASSERT_EQ(cumulative_count, bucket.cumulative_count);
+  }
+}
+
+template <typename T>
+metric_sdk::Record get_record(const std::string &type,
+                              int version,
+                              const std::string &label,
+                              std::shared_ptr<metric_sdk::Aggregator<T>> aggregator)
+{
+  std::string name = "test-" + type + "-metric-record-v_" + std::to_string(version) + ".0";
+  std::string desc = "this is a test " + type + " metric record";
+  metric_sdk::Record record(name, desc, label, aggregator);
+  return record;
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusEmptyInputReturnsEmptyCollection)
+{
+  std::vector<metric_sdk::Record> collection;
+  auto translated2 = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated2.size(), 0);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusIntegerCounter)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::CounterAggregator<int>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+
+  auto record1 = get_record("int-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  aggregator->update(10);
+  aggregator->checkpoint();
+  collection.emplace_back(record1);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric1          = translated[0];
+  std::vector<int> vals = {10};
+  assert_basic(metric1, "test_int_counter_metric_record_v_1_0", record1.GetDescription(),
+               prometheus_client::MetricType::Counter, 3, vals);
+
+  auto record2 = get_record("int-counter", 2, "{,}", aggregator);
+  aggregator->update(20);
+  aggregator->update(30);
+  aggregator->checkpoint();
+  collection.emplace_back(record2);
+
+  translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric2 = translated[1];
+  vals         = {50};
+  assert_basic(metric2, "test_int_counter_metric_record_v_2_0", record2.GetDescription(),
+               prometheus_client::MetricType::Counter, 0, vals);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusDoubleCounter)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+      new metric_sdk::CounterAggregator<double>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+  aggregator->update(10.5);
+  aggregator->checkpoint();
+  auto record1 = get_record("double-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  aggregator->update(22.4);
+  aggregator->update(31.2);
+  aggregator->checkpoint();
+  auto record2 = get_record("double-counter", 2, "{,}", aggregator);
+  collection.emplace_back(record1);
+  collection.emplace_back(record2);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric1             = translated[0];
+  std::vector<double> vals = {53.6};
+  assert_basic(metric1, "test_double_counter_metric_record_v_1_0", record1.GetDescription(),
+               prometheus_client::MetricType::Counter, 3, vals);
+  auto metric2 = translated[1];
+  assert_basic(metric2, "test_double_counter_metric_record_v_2_0", record2.GetDescription(),
+               prometheus_client::MetricType::Counter, 0, vals);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusShortCounter)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
+      new metric_sdk::CounterAggregator<short>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+  aggregator->update(10);
+  aggregator->checkpoint();
+  auto record1 = get_record("short-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  aggregator->update(20);
+  aggregator->update(30);
+  aggregator->checkpoint();
+  auto record2 = get_record("short-counter", 2, "{,}", aggregator);
+  collection.emplace_back(record1);
+  collection.emplace_back(record2);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric1            = translated[0];
+  std::vector<short> vals = {50};
+  assert_basic(metric1, "test_short_counter_metric_record_v_1_0", record1.GetDescription(),
+               prometheus_client::MetricType::Counter, 3, vals);
+  auto metric2 = translated[1];
+  assert_basic(metric2, "test_short_counter_metric_record_v_2_0", record2.GetDescription(),
+               prometheus_client::MetricType::Counter, 0, vals);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusFloatCounter)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
+      new metric_sdk::CounterAggregator<float>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+  aggregator->update(10.5f);
+  aggregator->checkpoint();
+  auto record1 = get_record("float-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  aggregator->update(22.4f);
+  aggregator->update(31.2f);
+  aggregator->checkpoint();
+  auto record2 = get_record("float-counter", 2, "{,}", aggregator);
+  collection.emplace_back(record1);
+  collection.emplace_back(record2);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric1            = translated[0];
+  std::vector<float> vals = {53.6f};
+  assert_basic(metric1, "test_float_counter_metric_record_v_1_0", record1.GetDescription(),
+               prometheus_client::MetricType::Counter, 3, vals);
+  auto metric2 = translated[1];
+  assert_basic(metric2, "test_float_counter_metric_record_v_2_0", record2.GetDescription(),
+               prometheus_client::MetricType::Counter, 0, vals);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusGauge)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::GaugeAggregator<int>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+  aggregator->update(10);
+  aggregator->checkpoint();
+  auto record1 = get_record("gauge", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  aggregator->update(20);
+  aggregator->update(30);
+  aggregator->checkpoint();
+  auto record2 = get_record("gauge", 2, "{,}", aggregator);
+  collection.emplace_back(record1);
+  collection.emplace_back(record2);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric1          = translated[0];
+  std::vector<int> vals = {30};
+  assert_basic(metric1, "test_gauge_metric_record_v_1_0", record1.GetDescription(),
+               prometheus_client::MetricType::Gauge, 3, vals);
+  auto metric2 = translated[1];
+  assert_basic(metric2, "test_gauge_metric_record_v_2_0", record2.GetDescription(),
+               prometheus_client::MetricType::Gauge, 0, vals);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramUniform)
+{
+  std::vector<double> boundaries{10, 20, 30, 40, 50};
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::HistogramAggregator<int>(metric_api::InstrumentKind::Counter, boundaries));
+
+  std::vector<metric_sdk::Record> collection;
+  auto record = get_record("histogram-uniform", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  int count_num = 60;
+  for (int i = 0; i < count_num; i++)
+  {
+    aggregator->update(i);
+  }
+  aggregator->checkpoint();
+  collection.emplace_back(record);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric           = translated[0];
+  std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0],
+                           (int)boundaries.size() + 1};
+  assert_basic(metric, "test_histogram_uniform_metric_record_v_1_0", record.GetDescription(),
+               prometheus_client::MetricType::Histogram, 3, vals);
+  std::vector<int> correct = aggregator->get_counts();
+  assert_histogram(metric, boundaries, correct);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramNormal)
+{
+  std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::HistogramAggregator<int>(metric_api::InstrumentKind::Counter, boundaries));
+
+  std::vector<metric_sdk::Record> collection;
+  auto record = get_record("histogram-normal", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  std::vector<int> values{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
+  for (int i : values)
+  {
+    aggregator->update(i);
+  }
+  aggregator->checkpoint();
+  collection.emplace_back(record);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric           = translated[0];
+  std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0],
+                           (int)boundaries.size() + 1};
+  assert_basic(metric, "test_histogram_normal_metric_record_v_1_0", record.GetDescription(),
+               prometheus_client::MetricType::Histogram, 3, vals);
+  std::vector<int> correct = aggregator->get_counts();
+  assert_histogram(metric, boundaries, correct);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusExact)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::ExactAggregator<int>(metric_api::InstrumentKind::Counter, true));
+
+  std::vector<metric_sdk::Record> collection;
+  int count_num = 100;
+  for (int i = 0; i <= count_num; i++)
+  {
+    aggregator->update(i);
+  }
+  aggregator->checkpoint();
+  auto record = get_record("exact", 1, "{label-1:v1,label_2:v2,label3:v3,}", aggregator);
+  collection.emplace_back(record);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric           = translated[0];
+  std::vector<int> vals = {101, 5050};
+  assert_basic(metric, "test_exact_metric_record_v_1_0", record.GetDescription(),
+               prometheus_client::MetricType::Summary, 3, vals);
+  auto quantile = metric.metric[0].summary.quantile;
+  ASSERT_EQ(quantile.size(), 6);
+  ASSERT_DOUBLE_EQ(quantile[0].value, 0);
+  ASSERT_DOUBLE_EQ(quantile[1].value, 50);
+  ASSERT_DOUBLE_EQ(quantile[2].value, 90);
+  ASSERT_DOUBLE_EQ(quantile[3].value, 95);
+  ASSERT_DOUBLE_EQ(quantile[4].value, 99);
+  ASSERT_DOUBLE_EQ(quantile[5].value, 100);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusExactNoQuantile)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::ExactAggregator<int>(metric_api::InstrumentKind::Counter, false));
+
+  std::vector<metric_sdk::Record> collection;
+  int count_num = 10;
+  for (int i = 0; i < count_num; i++)
+  {
+    aggregator->update(i);
+  }
+  aggregator->checkpoint();
+  auto record = get_record("exact-no-quantile", 1, "{label1:v1,label2:v2,}", aggregator);
+  collection.emplace_back(record);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric           = translated[0];
+  std::vector<int> vals = {count_num, 45};
+  assert_basic(metric, "test_exact_no_quantile_metric_record_v_1_0", record.GetDescription(),
+               prometheus_client::MetricType::Summary, 2, vals);
+  auto quantile = metric.metric[0].summary.quantile;
+  ASSERT_EQ(quantile.size(), 0);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusMinMaxSumCount)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::MinMaxSumCountAggregator<int>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+  // min: 1, max: 10, sum: 55, count: 10
+  for (int i = 1; i <= 10; i++)
+  {
+    aggregator->update(i);
+  }
+  aggregator->checkpoint();
+  auto record = get_record("mmsc", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
+  collection.emplace_back(record);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric = translated[0];
+  // in this version of implementation, we use the sum/count as a gauge
+  std::vector<double> vals = {5.5};
+  assert_basic(metric, "test_mmsc_metric_record_v_1_0", record.GetDescription(),
+               prometheus_client::MetricType::Gauge, 3, vals);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusSketch)
+{
+  auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::SketchAggregator<int>(metric_api::InstrumentKind::Counter, 0.0005));
+
+  std::vector<metric_sdk::Record> collection;
+  for (int i = 0; i <= 100; i++)
+  {
+    aggregator->update(i);
+  }
+  aggregator->checkpoint();
+  auto record = get_record("sketch", 1, "{label1:v1,label2:v2,}", aggregator);
+  collection.emplace_back(record);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric           = translated[0];
+  std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0]};
+  assert_basic(metric, "test_sketch_metric_record_v_1_0", record.GetDescription(),
+               prometheus_client::MetricType::Summary, 2, vals);
+
+  auto quantile = metric.metric[0].summary.quantile;
+  ASSERT_EQ(quantile.size(), 6);
+  ASSERT_DOUBLE_EQ(quantile[0].value, 0);
+  ASSERT_DOUBLE_EQ(quantile[1].value, 49);
+  ASSERT_DOUBLE_EQ(quantile[2].value, 89);
+  ASSERT_DOUBLE_EQ(quantile[3].value, 94);
+  ASSERT_DOUBLE_EQ(quantile[4].value, 98);
+  ASSERT_DOUBLE_EQ(quantile[5].value, 99);
+}
+
+TEST(PrometheusExporterUtils, TranslateToPrometheusMultipleAggregators)
+{
+  auto counter_aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
+      new metric_sdk::CounterAggregator<double>(metric_api::InstrumentKind::Counter));
+  auto gauge_aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
+      new metric_sdk::GaugeAggregator<int>(metric_api::InstrumentKind::Counter));
+
+  std::vector<metric_sdk::Record> collection;
+  counter_aggregator->update(10);
+  counter_aggregator->update(20);
+  counter_aggregator->checkpoint();
+  auto record1 = get_record("counter", 1, "{label1:v1,label2:v2,label3:v3,}", counter_aggregator);
+  gauge_aggregator->update(10);
+  gauge_aggregator->update(30);
+  gauge_aggregator->update(20);
+  gauge_aggregator->checkpoint();
+  auto record2 = get_record("gauge", 1, "{label1:v1,}", gauge_aggregator);
+  collection.emplace_back(record1);
+  collection.emplace_back(record2);
+
+  auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
+  ASSERT_EQ(translated.size(), collection.size());
+
+  auto metric1          = translated[0];
+  std::vector<int> vals = {30};
+  assert_basic(metric1, "test_counter_metric_record_v_1_0", record1.GetDescription(),
+               prometheus_client::MetricType::Counter, 3, vals);
+  auto metric2 = translated[1];
+  vals         = {20};
+  assert_basic(metric2, "test_gauge_metric_record_v_1_0", record2.GetDescription(),
+               prometheus_client::MetricType::Gauge, 1, vals);
+}
+OPENTELEMETRY_END_NAMESPACE
+#endif