Skip to content

Commit

Permalink
Export resource for prometheus (#2301)
Browse files Browse the repository at this point in the history
  • Loading branch information
owent authored Oct 3, 2023
1 parent 0803e6a commit 0eaa794
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 43 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ Increment the:

* [DEPRECATION] Deprecate ZPAGES
[#2291](https://github.com/open-telemetry/opentelemetry-cpp/pull/2291)
* [EXPORTER] Prometheus exporter emit resource attributes
[#2301](https://github.com/open-telemetry/opentelemetry-cpp/pull/2301)
* [EXPORTER] Remove explicit timestamps from metric points exported by Prometheus
[#2324](https://github.com/open-telemetry/opentelemetry-cpp/pull/2324)
* [EXPORTER] Handle attribute key collisions caused by sanitation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class PrometheusCollector : public prometheus_client::Collectable
* This constructor initializes the collection for metrics to export
* in this class with default capacity
*/
explicit PrometheusCollector(sdk::metrics::MetricReader *reader);
explicit PrometheusCollector(sdk::metrics::MetricReader *reader, bool populate_target_info);

/**
* Collects all metrics data from metricsToCollect collection.
Expand All @@ -42,6 +42,7 @@ class PrometheusCollector : public prometheus_client::Collectable

private:
sdk::metrics::MetricReader *reader_;
bool populate_target_info_;

/*
* Lock when operating the metricsToCollect collection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ struct PrometheusExporterOptions

// The endpoint the Prometheus backend can collect metrics from
std::string url;

// Populating target_info
bool populate_target_info = true;
};

} // namespace metrics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,25 @@ class PrometheusExporterUtils
* to Prometheus metrics data collection
*
* @param records a collection of metrics in OpenTelemetry
* @param populate_target_info whether to populate target_info
* @return a collection of translated metrics that is acceptable by Prometheus
*/
static std::vector<::prometheus::MetricFamily> TranslateToPrometheus(
const sdk::metrics::ResourceMetrics &data);
const sdk::metrics::ResourceMetrics &data,
bool populate_target_info = true);

private:
/**
* Append key-value pair to prometheus labels.
*
* @param name label name
* @param value label value
* @param labels target labels
*/
static void AddPrometheusLabel(std::string name,
std::string value,
std::vector<::prometheus::ClientMetric::Label> *labels);

static opentelemetry::sdk::metrics::AggregationType getAggregationType(
const opentelemetry::sdk::metrics::PointType &point_type);

Expand All @@ -41,6 +54,13 @@ class PrometheusExporterUtils
static ::prometheus::MetricType TranslateType(opentelemetry::sdk::metrics::AggregationType kind,
bool is_monotonic = true);

/**
* Add a target_info metric to collect resource attributes
*/
static void SetTarget(const sdk::metrics::ResourceMetrics &data,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
std::vector<::prometheus::MetricFamily> *output);

/**
* Set metric data for:
* Counter => Prometheus Counter
Expand All @@ -50,7 +70,8 @@ class PrometheusExporterUtils
const opentelemetry::sdk::metrics::PointAttributes &labels,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
::prometheus::MetricType type,
::prometheus::MetricFamily *metric_family);
::prometheus::MetricFamily *metric_family,
const opentelemetry::sdk::resource::Resource *resource);

/**
* Set metric data for:
Expand All @@ -62,15 +83,17 @@ class PrometheusExporterUtils
const std::vector<uint64_t> &counts,
const opentelemetry::sdk::metrics::PointAttributes &labels,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
::prometheus::MetricFamily *metric_family);
::prometheus::MetricFamily *metric_family,
const opentelemetry::sdk::resource::Resource *resource);

/**
* Set time and labels to metric data
*/
static void SetMetricBasic(
::prometheus::ClientMetric &metric,
const opentelemetry::sdk::metrics::PointAttributes &labels,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope);
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
const opentelemetry::sdk::resource::Resource *resource);

/**
* Convert attribute value to string
Expand Down
11 changes: 8 additions & 3 deletions exporters/prometheus/src/collector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ namespace metrics
* This constructor initializes the collection for metrics to export
* in this class with default capacity
*/
PrometheusCollector::PrometheusCollector(sdk::metrics::MetricReader *reader) : reader_(reader) {}
PrometheusCollector::PrometheusCollector(sdk::metrics::MetricReader *reader,
bool populate_target_info)
: reader_(reader), populate_target_info_(populate_target_info)
{}

/**
* Collects all metrics data from metricsToCollect collection.
Expand All @@ -36,8 +39,10 @@ std::vector<prometheus_client::MetricFamily> PrometheusCollector::Collect() cons
collection_lock_.lock();

std::vector<prometheus_client::MetricFamily> result;
reader_->Collect([&result](sdk::metrics::ResourceMetrics &metric_data) {
auto prometheus_metric_data = PrometheusExporterUtils::TranslateToPrometheus(metric_data);

reader_->Collect([&result, this](sdk::metrics::ResourceMetrics &metric_data) {
auto prometheus_metric_data =
PrometheusExporterUtils::TranslateToPrometheus(metric_data, this->populate_target_info_);
for (auto &data : prometheus_metric_data)
result.emplace_back(data);
return true;
Expand Down
3 changes: 2 additions & 1 deletion exporters/prometheus/src/exporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ PrometheusExporter::PrometheusExporter(const PrometheusExporterOptions &options)
Shutdown(); // set MetricReader in shutdown state.
return;
}
collector_ = std::shared_ptr<PrometheusCollector>(new PrometheusCollector(this));
collector_ = std::shared_ptr<PrometheusCollector>(
new PrometheusCollector(this, options_.populate_target_info));

exposer_->RegisterCollectable(collector_);
}
Expand Down
102 changes: 85 additions & 17 deletions exporters/prometheus/src/exporter_utils.cc
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

#include <limits>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "prometheus/metric_family.h"
#include "prometheus/metric_type.h"

#include <prometheus/metric_type.h>
#include "opentelemetry/exporters/prometheus/exporter_utils.h"
#include "opentelemetry/sdk/metrics/export/metric_producer.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/resource/semantic_conventions.h"
#include "opentelemetry/trace/semantic_conventions.h"

#include "opentelemetry/sdk/common/global_log_handler.h"

Expand Down Expand Up @@ -111,11 +119,25 @@ std::string SanitizeName(std::string name)
* @return a collection of translated metrics that is acceptable by Prometheus
*/
std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateToPrometheus(
const sdk::metrics::ResourceMetrics &data)
const sdk::metrics::ResourceMetrics &data,
bool populate_target_info)
{

// initialize output vector
std::size_t reserve_size = 1;
for (const auto &instrumentation_info : data.scope_metric_data_)
{
reserve_size += instrumentation_info.metric_data_.size();
}

std::vector<prometheus_client::MetricFamily> output;
output.reserve(reserve_size);

// Append target_info as the first metric
if (populate_target_info && !data.scope_metric_data_.empty())
{
SetTarget(data, (*data.scope_metric_data_.begin()).scope_, &output);
}

for (const auto &instrumentation_info : data.scope_metric_data_)
{
Expand Down Expand Up @@ -151,10 +173,11 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
}
else
{
sum = nostd::get<int64_t>(histogram_point_data.sum_);
sum = static_cast<double>(nostd::get<int64_t>(histogram_point_data.sum_));
}
SetData(std::vector<double>{sum, (double)histogram_point_data.count_}, boundaries, counts,
point_data_attr.attributes, instrumentation_info.scope_, &metric_family);
point_data_attr.attributes, instrumentation_info.scope_, &metric_family,
data.resource_);
}
else if (type == prometheus_client::MetricType::Gauge)
{
Expand All @@ -165,15 +188,15 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
nostd::get<sdk::metrics::LastValuePointData>(point_data_attr.point_data);
std::vector<metric_sdk::ValueType> values{last_value_point_data.value_};
SetData(values, point_data_attr.attributes, instrumentation_info.scope_, type,
&metric_family);
&metric_family, data.resource_);
}
else if (nostd::holds_alternative<sdk::metrics::SumPointData>(point_data_attr.point_data))
{
auto sum_point_data =
nostd::get<sdk::metrics::SumPointData>(point_data_attr.point_data);
std::vector<metric_sdk::ValueType> values{sum_point_data.value_};
SetData(values, point_data_attr.attributes, instrumentation_info.scope_, type,
&metric_family);
&metric_family, data.resource_);
}
else
{
Expand All @@ -190,7 +213,7 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
nostd::get<sdk::metrics::SumPointData>(point_data_attr.point_data);
std::vector<metric_sdk::ValueType> values{sum_point_data.value_};
SetData(values, point_data_attr.attributes, instrumentation_info.scope_, type,
&metric_family);
&metric_family, data.resource_);
}
else
{
Expand All @@ -206,6 +229,17 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
return output;
}

void PrometheusExporterUtils::AddPrometheusLabel(
std::string name,
std::string value,
std::vector<::prometheus::ClientMetric::Label> *labels)
{
prometheus_client::ClientMetric::Label prometheus_label;
prometheus_label.name = std::move(name);
prometheus_label.value = std::move(value);
labels->emplace_back(std::move(prometheus_label));
}

metric_sdk::AggregationType PrometheusExporterUtils::getAggregationType(
const metric_sdk::PointType &point_type)
{
Expand Down Expand Up @@ -259,6 +293,37 @@ prometheus_client::MetricType PrometheusExporterUtils::TranslateType(
}
}

void PrometheusExporterUtils::SetTarget(
const sdk::metrics::ResourceMetrics &data,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
std::vector<::prometheus::MetricFamily> *output)
{
if (output == nullptr || data.resource_ == nullptr)
{
return;
}

prometheus_client::MetricFamily metric_family;
metric_family.name = "target";
metric_family.help = "Target metadata";
metric_family.type = prometheus_client::MetricType::Info;
metric_family.metric.emplace_back();

prometheus_client::ClientMetric &metric = metric_family.metric.back();
metric.info.value = 1.0;

metric_sdk::PointAttributes empty_attributes;
SetMetricBasic(metric, empty_attributes, scope, data.resource_);

for (auto &label : data.resource_->GetAttributes())
{
AddPrometheusLabel(SanitizeName(label.first), AttributeValueToString(label.second),
&metric.label);
}

output->emplace_back(std::move(metric_family));
}

/**
* Set metric data for:
* sum => Prometheus Counter
Expand All @@ -269,11 +334,12 @@ void PrometheusExporterUtils::SetData(
const metric_sdk::PointAttributes &labels,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
prometheus_client::MetricType type,
prometheus_client::MetricFamily *metric_family)
prometheus_client::MetricFamily *metric_family,
const opentelemetry::sdk::resource::Resource *resource)
{
metric_family->metric.emplace_back();
prometheus_client::ClientMetric &metric = metric_family->metric.back();
SetMetricBasic(metric, labels, scope);
SetMetricBasic(metric, labels, scope, resource);
SetValue(values, type, &metric);
}

Expand All @@ -288,11 +354,12 @@ void PrometheusExporterUtils::SetData(
const std::vector<uint64_t> &counts,
const metric_sdk::PointAttributes &labels,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
prometheus_client::MetricFamily *metric_family)
prometheus_client::MetricFamily *metric_family,
const opentelemetry::sdk::resource::Resource *resource)
{
metric_family->metric.emplace_back();
prometheus_client::ClientMetric &metric = metric_family->metric.back();
SetMetricBasic(metric, labels, scope);
SetMetricBasic(metric, labels, scope, resource);
SetValue(values, boundaries, counts, &metric);
}

Expand All @@ -302,9 +369,10 @@ void PrometheusExporterUtils::SetData(
void PrometheusExporterUtils::SetMetricBasic(
prometheus_client::ClientMetric &metric,
const metric_sdk::PointAttributes &labels,
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope)
const opentelemetry::sdk::instrumentationscope::InstrumentationScope *scope,
const opentelemetry::sdk::resource::Resource *resource)
{
if (labels.empty())
if (labels.empty() && nullptr == resource)
{
return;
}
Expand Down Expand Up @@ -410,7 +478,7 @@ void PrometheusExporterUtils::SetValue(std::vector<T> values,
const auto &value_var = values[0];
if (nostd::holds_alternative<int64_t>(value_var))
{
value = nostd::get<int64_t>(value_var);
value = static_cast<double>(nostd::get<int64_t>(value_var));
}
else
{
Expand Down Expand Up @@ -445,9 +513,9 @@ void PrometheusExporterUtils::SetValue(std::vector<T> values,
const std::vector<uint64_t> &counts,
prometheus_client::ClientMetric *metric)
{
metric->histogram.sample_sum = values[0];
metric->histogram.sample_count = values[1];
int cumulative = 0;
metric->histogram.sample_sum = static_cast<double>(values[0]);
metric->histogram.sample_count = static_cast<std::uint64_t>(values[1]);
std::uint64_t cumulative = 0;
std::vector<prometheus_client::ClientMetric::Bucket> buckets;
uint32_t idx = 0;
for (const auto &boundary : boundaries)
Expand Down
4 changes: 2 additions & 2 deletions exporters/prometheus/test/collector_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,12 @@ TEST(PrometheusCollector, BasicTests)
MockMetricReader *reader = new MockMetricReader();
MockMetricProducer *producer = new MockMetricProducer();
reader->SetMetricProducer(producer);
PrometheusCollector collector(reader);
PrometheusCollector collector(reader, true);
auto data = collector.Collect();

// Collection size should be the same as the size
// of the records collection produced by MetricProducer.
ASSERT_EQ(data.size(), 1);
ASSERT_EQ(data.size(), 2);
delete reader;
delete producer;
}
Loading

2 comments on commit 0eaa794

@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 api Benchmark'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: 0eaa794 Previous: 0803e6a Ratio
BM_NaiveSpinLockThrashing/2/process_time/real_time 1.4963269233703613 ms/iter 0.22241872809044957 ms/iter 6.73

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

@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: 0eaa794 Previous: 0803e6a Ratio
BM_BaselineBuffer/2 10840594.76852417 ns/iter 3652688.980102539 ns/iter 2.97
BM_LockFreeBuffer/4 8000161.647796631 ns/iter 1968713.4542582948 ns/iter 4.06

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

Please sign in to comment.