Skip to content

Commit

Permalink
[EXPORTER] Add config options to prometheus exporter (#3104)
Browse files Browse the repository at this point in the history
  • Loading branch information
psx95 authored Oct 21, 2024
1 parent 1185405 commit b1488cd
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ struct PrometheusExporterOptions

// Populating otel_scope_name/otel_scope_labels attributes
bool without_otel_scope = false;

// Option to export metrics without the unit suffix
bool without_units = false;

// Option to export metrics without the type suffix
bool without_type_suffix = false;
};

} // namespace metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,18 @@ class PrometheusExporterUtils
* @param populate_target_info whether to populate target_info
* @param without_otel_scope whether to populate otel_scope_name and otel_scope_version
* attributes
* @param without_units exporter configuration controlling whether to append unit suffix in
* the exported metrics.
* @param without_type_suffix exporter configuration controlling whether to append type suffix in
* the exported metrics.
* @return a collection of translated metrics that is acceptable by Prometheus
*/
static std::vector<::prometheus::MetricFamily> TranslateToPrometheus(
const sdk::metrics::ResourceMetrics &data,
bool populate_target_info = true,
bool without_otel_scope = false);
bool without_otel_scope = false,
bool without_units = false,
bool without_type_suffix = false);

private:
/**
Expand All @@ -61,7 +67,9 @@ class PrometheusExporterUtils

static std::string MapToPrometheusName(const std::string &name,
const std::string &unit,
::prometheus::MetricType prometheus_type);
::prometheus::MetricType prometheus_type,
bool without_units,
bool without_type_suffix);

/**
* A utility function that returns the equivalent Prometheus name for the provided OTLP metric
Expand Down
25 changes: 24 additions & 1 deletion exporters/prometheus/src/exporter_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,33 @@ inline bool GetPrometheusPopulateTargetInfo()
return exists ? setting : true;
}

inline bool GetPrometheusWithoutUnits()
{
constexpr char kPrometheusWithoutUnits[] = "OTEL_CPP_PROMETHEUS_EXPORTER_WITHOUT_UNITS";
bool setting;
const auto exists =
opentelemetry::sdk::common::GetBoolEnvironmentVariable(kPrometheusWithoutUnits, setting);

return exists ? setting : false;
}

inline bool GetPrometheusWithoutTypeSuffix()
{
constexpr char kPrometheusWithoutTypeSuffix[] =
"OTEL_CPP_PROMETHEUS_EXPORTER_WITHOUT_TYPE_SUFFIX";
bool setting;
const auto exists =
opentelemetry::sdk::common::GetBoolEnvironmentVariable(kPrometheusWithoutTypeSuffix, setting);

return exists ? setting : false;
}

PrometheusExporterOptions::PrometheusExporterOptions()
: url(GetPrometheusDefaultHttpEndpoint()),
populate_target_info(GetPrometheusPopulateTargetInfo()),
without_otel_scope(GetPrometheusWithoutOtelScope())
without_otel_scope(GetPrometheusWithoutOtelScope()),
without_units(GetPrometheusWithoutUnits()),
without_type_suffix(GetPrometheusWithoutTypeSuffix())
{}

} // namespace metrics
Expand Down
62 changes: 37 additions & 25 deletions exporters/prometheus/src/exporter_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,15 @@ std::string SanitizeLabel(std::string label_key)
* Helper function to convert OpenTelemetry metrics data collection
* to Prometheus metrics data collection
*
* @param records a collection of metrics in OpenTelemetry
* @param data a collection of metrics in OpenTelemetry
* @return a collection of translated metrics that is acceptable by Prometheus
*/
std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateToPrometheus(
const sdk::metrics::ResourceMetrics &data,
bool populate_target_info,
bool without_otel_scope)
bool without_otel_scope,
bool without_units,
bool without_type_suffix)
{

// initialize output vector
Expand Down Expand Up @@ -150,7 +152,8 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
}
const prometheus_client::MetricType type = TranslateType(kind, is_monotonic);
metric_family.name = MapToPrometheusName(metric_data.instrument_descriptor.name_,
metric_data.instrument_descriptor.unit_, type);
metric_data.instrument_descriptor.unit_, type,
without_units, without_type_suffix);
metric_family.type = type;
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope =
without_otel_scope ? nullptr : instrumentation_info.scope_;
Expand Down Expand Up @@ -492,34 +495,43 @@ std::string PrometheusExporterUtils::CleanUpString(const std::string &str)
std::string PrometheusExporterUtils::MapToPrometheusName(
const std::string &name,
const std::string &unit,
prometheus_client::MetricType prometheus_type)
prometheus_client::MetricType prometheus_type,
bool without_units,
bool without_type_suffix)
{
auto sanitized_name = SanitizeNames(name);
std::string prometheus_equivalent_unit = GetEquivalentPrometheusUnit(unit);

// Append prometheus unit if not null or empty.
if (!prometheus_equivalent_unit.empty() &&
sanitized_name.find(prometheus_equivalent_unit) == std::string::npos)
{
sanitized_name += "_" + prometheus_equivalent_unit;
}

// Special case - counter
if (prometheus_type == prometheus_client::MetricType::Counter)
{
auto t_pos = sanitized_name.rfind("_total");
bool ends_with_total = t_pos == sanitized_name.size() - 6;
if (!ends_with_total)
auto sanitized_name = SanitizeNames(name);
// append unit suffixes
if (!without_units)
{
std::string prometheus_equivalent_unit = GetEquivalentPrometheusUnit(unit);
// Append prometheus unit if not null or empty.
if (!prometheus_equivalent_unit.empty() &&
sanitized_name.find(prometheus_equivalent_unit) == std::string::npos)
{
sanitized_name += "_total";
sanitized_name += "_" + prometheus_equivalent_unit;
}
// Special case - gauge
if (unit == "1" && prometheus_type == prometheus_client::MetricType::Gauge &&
sanitized_name.find("ratio") == std::string::npos)
{
// this is replacing the unit name
sanitized_name += "_ratio";
}
}

// Special case - gauge
if (unit == "1" && prometheus_type == prometheus_client::MetricType::Gauge &&
sanitized_name.find("ratio") == std::string::npos)
// append type suffixes
if (!without_type_suffix)
{
sanitized_name += "_ratio";
// Special case - counter
if (prometheus_type == prometheus_client::MetricType::Counter)
{
auto t_pos = sanitized_name.rfind("_total");
bool ends_with_total = t_pos == sanitized_name.size() - 6;
if (!ends_with_total)
{
sanitized_name += "_total";
}
}
}

return CleanUpString(SanitizeNames(sanitized_name));
Expand Down
94 changes: 92 additions & 2 deletions exporters/prometheus/test/exporter_utils_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@ class SanitizeNameTester
}
static std::string mapToPrometheusName(const std::string &name,
const std::string &unit,
prometheus_client::MetricType prometheus_type)
prometheus_client::MetricType prometheus_type,
bool without_units = false,
bool without_type_suffix = false)
{
return PrometheusExporterUtils::MapToPrometheusName(name, unit, prometheus_type);
return PrometheusExporterUtils::MapToPrometheusName(name, unit, prometheus_type, without_units,
without_type_suffix);
}
};
} // namespace metrics
Expand Down Expand Up @@ -419,6 +422,93 @@ TEST(PrometheusExporterUtils, ConvertRateExpressedToPrometheusUnit)
"_per_minute");
}

TEST(PromentheusExporterUtils, PrometheusNameMapping)
{
// General test cases on unit expansions and name sanitization
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric___name", "g", prometheus::MetricType::Counter),
"sample_metric_name_grams_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "s", prometheus::MetricType::Counter),
"sample_metric_name_seconds_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "s", prometheus::MetricType::Gauge),
"sample_metric_name_seconds");
// Test without_units & without_type_suffix with Counters and unit = 1
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Counter),
"sample_metric_name_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Counter, true, false),
"sample_metric_name_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Counter, false, true),
"sample_metric_name");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Counter, true, true),
"sample_metric_name");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Counter, true, true),
"sample_metric_name");
// Test without_units & without_type_suffix with Counters and non-special units
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "%", prometheus::MetricType::Counter),
"sample_metric_name_percent_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "m", prometheus::MetricType::Counter, true, false),
"sample_metric_name_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "By", prometheus::MetricType::Counter, false, true),
"sample_metric_name_bytes");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "s", prometheus::MetricType::Counter, true, true),
"sample_metric_name");
// Special case Gauges & ratio
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Gauge),
"sample_metric_name_ratio");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Gauge, false, true),
"sample_metric_name_ratio");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Gauge, true, false),
"sample_metric_name");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "1", prometheus::MetricType::Gauge, true, true),
"sample_metric_name");
// Test without_type_suffix affects only counters
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Counter),
"sample_metric_name_hertz_total");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Counter, false, true),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Gauge),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Gauge, false, true),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Histogram),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Histogram, false, true),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Summary),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Summary, false, true),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Info),
"sample_metric_name_hertz");
ASSERT_EQ(exporter::metrics::SanitizeNameTester::mapToPrometheusName(
"sample_metric_name", "Hz", prometheus::MetricType::Info, false, true),
"sample_metric_name_hertz");
}

TEST_F(AttributeCollisionTest, JoinsCollidingKeys)
{
CheckTranslation({{"foo.a", "value1"}, {"foo_a", "value2"}}, {{"foo_a", "value1;value2"},
Expand Down

1 comment on commit b1488cd

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'OpenTelemetry-cpp sdk Benchmark'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: b1488cd Previous: 1185405 Ratio
BM_BaselineBuffer/2 14211432.933807373 ns/iter 6245968.341827393 ns/iter 2.28

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.