Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions ci/do_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ elif [[ "$1" == "bazel.test" ]]; then
bazel test $BAZEL_TEST_OPTIONS //...
exit 0
elif [[ "$1" == "bazel.legacy.test" ]]; then
bazel build $BAZEL_OPTIONS -- //... -//exporters/otlp/...
bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/...
# we uses C++ future and async() function to test the Prometheus Exporter functionality,
# that make this test always fail. ignore Prometheus exporter here.
bazel build $BAZEL_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/...
bazel test $BAZEL_TEST_OPTIONS -- //... -//exporters/otlp/... -//exporters/prometheus/...
exit 0
elif [[ "$1" == "bazel.noexcept" ]]; then
# there are some exceptions and error handling code from the Prometheus Client
Expand Down
29 changes: 29 additions & 0 deletions exporters/prometheus/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@

package(default_visibility = ["//visibility:public"])

cc_library(
name = "prometheus_collector",
srcs = [
"src/prometheus_collector.cc",
],
hdrs = [
"include/opentelemetry/exporters/prometheus/prometheus_collector.h",
"include/opentelemetry/exporters/prometheus/prometheus_exporter_utils.h",
],
strip_include_prefix = "include",
deps = [
":prometheus_utils",
"//api",
"//sdk:headers",
"@com_github_jupp0r_prometheus_cpp//core",
],
)

cc_library(
name = "prometheus_utils",
srcs = [
Expand All @@ -30,6 +48,17 @@ cc_library(
],
)

cc_test(
name = "prometheus_collector_test",
srcs = [
"test/prometheus_collector_test.cc",
],
deps = [
":prometheus_collector",
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "prometheus_exporter_utils_test",
srcs = [
Expand Down
4 changes: 3 additions & 1 deletion exporters/prometheus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
include_directories(include)

find_package(prometheus-cpp CONFIG REQUIRED)
add_library(prometheus_exporter src/prometheus_exporter_utils.cc)

add_library(prometheus_exporter src/prometheus_collector.cc
src/prometheus_exporter_utils.cc)

if(BUILD_TESTING)
add_subdirectory(test)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <memory>
#include <mutex>
#include <vector>

#include "opentelemetry/sdk/metrics/record.h"
#include "prometheus/collectable.h"
#include "prometheus/metric_family.h"
#include "prometheus_exporter_utils.h"

namespace prometheus_client = ::prometheus;
namespace metric_sdk = opentelemetry::sdk::metrics;

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* The Prometheus Collector maintains the intermediate collection in Prometheus Exporter
*/
class PrometheusCollector : public prometheus_client::Collectable
{
public:
/**
* Default Constructor.
*
* This constructor initializes the collection for metrics to export
* in this class with default capacity
*/
explicit PrometheusCollector(int max_collection_size = 2048);

/**
* Collects all metrics data from metricsToCollect collection.
*
* @return all metrics in the metricsToCollect snapshot
*/
std::vector<prometheus_client::MetricFamily> Collect() const override;

/**
* This function is called by export() function and add the collection of
* records to the metricsToCollect collection
*
* @param records a collection of records to add to the metricsToCollect collection
*/
void AddMetricData(const std::vector<metric_sdk::Record> &records);

/**
* Get the current collection in the collector.
*
* @return the current metricsToCollect collection
*/
std::vector<metric_sdk::Record> GetCollection();

/**
* Gets the maximum size of the collection.
*
* @return max collection size
*/
int GetMaxCollectionSize() const;

private:
/**
* Collection of metrics data from the export() function, and to be export
* to user when they send a pull request. This collection is a pointer
* to a collection so Collect() is able to clear the collection, even
* though it is a const function.
*/
std::unique_ptr<std::vector<metric_sdk::Record>> metrics_to_collect_;

/**
* Maximum size of the metricsToCollect collection.
*/
int max_collection_size_;

/*
* Lock when operating the metricsToCollect collection
*/
mutable std::mutex collection_lock_;
};
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
175 changes: 175 additions & 0 deletions exporters/prometheus/src/prometheus_collector.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <iostream>

#include "opentelemetry/exporters/prometheus/prometheus_collector.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* Default Constructor.
*
* This constructor initializes the collection for metrics to export
* in this class with default capacity
*/
PrometheusCollector::PrometheusCollector(int max_collection_size)
: max_collection_size_(max_collection_size)
{
metrics_to_collect_ =
std::unique_ptr<std::vector<metric_sdk::Record>>(new std::vector<metric_sdk::Record>);
}

/**
* Collects all metrics data from metricsToCollect collection.
*
* @return all metrics in the metricsToCollect snapshot
*/
std::vector<prometheus_client::MetricFamily> PrometheusCollector::Collect() const
{
this->collection_lock_.lock();
if (metrics_to_collect_->empty())
{
this->collection_lock_.unlock();
return {};
}
this->collection_lock_.unlock();

std::vector<prometheus_client::MetricFamily> result;

// copy the intermediate collection, and then clear it
std::vector<metric_sdk::Record> copied_data;

this->collection_lock_.lock();
copied_data = std::vector<metric_sdk::Record>(*metrics_to_collect_);
metrics_to_collect_->clear();
this->collection_lock_.unlock();

result = PrometheusExporterUtils::TranslateToPrometheus(copied_data);
return result;
}

/**
* This function is called by export() function and add the collection of
* records to the metricsToCollect collection
*
* @param records a collection of records to add to the metricsToCollect collection
*/
void PrometheusCollector::AddMetricData(const std::vector<sdk::metrics::Record> &records)
{
if (records.empty())
{
return;
}

collection_lock_.lock();
if (metrics_to_collect_->size() + records.size() <= max_collection_size_)
{
/**
* ValidAggregator is a lambda that checks a Record to see if its
* Aggregator is a valid nostd::shared_ptr and not a nullptr.
*/
auto ValidAggregator = [](sdk::metrics::Record record) {
auto aggregator_variant = record.GetAggregator();
if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<int>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<short>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<float>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<double>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}

return true;
};

for (auto &r : records)
{
if (ValidAggregator(r))
{
metrics_to_collect_->emplace_back(r);
}
// Drop the record and write to std::cout
else
{
// Cannot call non const functions on const Record r
sdk::metrics::Record c = r;
std::cout << "Dropped Record containing invalid aggregator with name: " + c.GetName()
<< std::endl;
}
}
}
collection_lock_.unlock();
}

/**
* Get the current collection in the collector.
*
* @return the current metrics_to_collect collection
*/
std::vector<sdk::metrics::Record> PrometheusCollector::GetCollection()
{
return *metrics_to_collect_;
}

/**
* Gets the maximum size of the collection.
*
* @return max collection size
*/
int PrometheusCollector::GetMaxCollectionSize() const
{
return max_collection_size_;
}

} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
2 changes: 1 addition & 1 deletion exporters/prometheus/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
foreach(testname prometheus_exporter_utils_test)
foreach(testname prometheus_collector_test prometheus_exporter_utils_test)
add_executable(${testname} "${testname}.cc")
target_link_libraries(
${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
Expand Down
Loading