From fd57488cea000f39c0ca9214d48bcf59cbbc5df8 Mon Sep 17 00:00:00 2001 From: Karteekmurthys Date: Wed, 27 Mar 2024 09:27:51 -0700 Subject: [PATCH] [native] Expose REST API to fetch worker stats in Prometheus format Add Prometheus Reporter using the prometheus-cpp library. Add a CMake flag PRESTO_ENABLE_PROMETHEUS_REPORTER to enable Prometheus Reporter. Add REST API '/v1/info/metrics' to fetch worker metrics from Prometheus Reporter in prometheus format. This endpoint is only enabled if the Prometheus Reporter is enabled. Co-authored-by:jaystarshot --- .circleci/continue_config.yml | 1 + presto-native-execution/CMakeLists.txt | 3 + presto-native-execution/Makefile | 3 + presto-native-execution/etc/config.properties | 3 +- .../presto_cpp/main/CMakeLists.txt | 5 + .../presto_cpp/main/PrestoMain.cpp | 6 - .../presto_cpp/main/PrestoServer.cpp | 21 +- .../presto_cpp/main/PrestoServer.h | 2 +- .../main/runtime-metrics/CMakeLists.txt | 24 ++ .../PrometheusStatsReporter.cpp | 238 ++++++++++++++++++ .../runtime-metrics/PrometheusStatsReporter.h | 98 ++++++++ .../main/runtime-metrics/tests/CMakeLists.txt | 19 ++ .../tests/PrometheusReporterTest.cpp | 154 ++++++++++++ .../main/tests/HttpServerWrapper.cpp | 6 - .../scripts/setup-adapters.sh | 2 +- 15 files changed, 565 insertions(+), 20 deletions(-) create mode 100644 presto-native-execution/presto_cpp/main/runtime-metrics/CMakeLists.txt create mode 100644 presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.cpp create mode 100644 presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.h create mode 100644 presto-native-execution/presto_cpp/main/runtime-metrics/tests/CMakeLists.txt create mode 100644 presto-native-execution/presto_cpp/main/runtime-metrics/tests/PrometheusReporterTest.cpp diff --git a/.circleci/continue_config.yml b/.circleci/continue_config.yml index 58b97488f419..0522d8df8cd5 100644 --- a/.circleci/continue_config.yml +++ b/.circleci/continue_config.yml @@ -118,6 +118,7 @@ jobs: -DPRESTO_ENABLE_PARQUET=ON \ -DPRESTO_ENABLE_REMOTE_FUNCTIONS=ON \ -DPRESTO_ENABLE_JWT=ON \ + -DPRESTO_ENABLE_PROMETHEUS_REPORTER=ON \ -DCMAKE_PREFIX_PATH=/usr/local \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DMAX_LINK_JOBS=2 diff --git a/presto-native-execution/CMakeLists.txt b/presto-native-execution/CMakeLists.txt index 7c22c13be84d..192c4d31ad29 100644 --- a/presto-native-execution/CMakeLists.txt +++ b/presto-native-execution/CMakeLists.txt @@ -57,6 +57,9 @@ option(PRESTO_ENABLE_TESTING "Enable tests" ON) option(PRESTO_ENABLE_JWT "Enable JWT (JSON Web Token) authentication" OFF) +option(PRESTO_ENABLE_PROMETHEUS_REPORTER + "Enables capturing of runtime metrics using prometheus client" OFF) + # Set all Velox options below add_compile_definitions(FOLLY_HAVE_INT128_T=1) diff --git a/presto-native-execution/Makefile b/presto-native-execution/Makefile index c58ba47a25c6..ef83d75bb110 100644 --- a/presto-native-execution/Makefile +++ b/presto-native-execution/Makefile @@ -38,6 +38,9 @@ endif ifeq ($(PRESTO_ENABLE_JWT), ON) EXTRA_CMAKE_FLAGS += -DPRESTO_ENABLE_JWT=ON endif +ifeq ($(PRESTO_ENABLE_PROMETHEUS_REPORTER), ON) + EXTRA_CMAKE_FLAGS += -DPRESTO_ENABLE_PROMETHEUS_REPORTER=ON +endif CMAKE_FLAGS := -DTREAT_WARNINGS_AS_ERRORS=${TREAT_WARNINGS_AS_ERRORS} CMAKE_FLAGS += -DENABLE_ALL_WARNINGS=${ENABLE_WALL} diff --git a/presto-native-execution/etc/config.properties b/presto-native-execution/etc/config.properties index 73654217fa15..b29e663f30eb 100644 --- a/presto-native-execution/etc/config.properties +++ b/presto-native-execution/etc/config.properties @@ -2,4 +2,5 @@ discovery.uri=http://127.0.0.1:58215 presto.version=testversion http-server.http.port=7777 shutdown-onset-sec=1 -register-test-functions=true \ No newline at end of file +register-test-functions=true +runtime-metrics-collection-enabled=true diff --git a/presto-native-execution/presto_cpp/main/CMakeLists.txt b/presto-native-execution/presto_cpp/main/CMakeLists.txt index f691866cbfa4..0911039d2ce5 100644 --- a/presto-native-execution/presto_cpp/main/CMakeLists.txt +++ b/presto-native-execution/presto_cpp/main/CMakeLists.txt @@ -108,3 +108,8 @@ set_property(TARGET presto_server PROPERTY JOB_POOL_LINK presto_link_job_pool) if(PRESTO_ENABLE_TESTING) add_subdirectory(tests) endif() + +if(PRESTO_ENABLE_PROMETHEUS_REPORTER) + add_subdirectory(runtime-metrics) + target_link_libraries(presto_server prometheus_reporter) +endif() diff --git a/presto-native-execution/presto_cpp/main/PrestoMain.cpp b/presto-native-execution/presto_cpp/main/PrestoMain.cpp index 9e74b5b1dacf..d0fd9d528636 100644 --- a/presto-native-execution/presto_cpp/main/PrestoMain.cpp +++ b/presto-native-execution/presto_cpp/main/PrestoMain.cpp @@ -17,7 +17,6 @@ #include #include "presto_cpp/main/PrestoServer.h" #include "presto_cpp/main/common/Utils.h" -#include "velox/common/base/StatsReporter.h" DEFINE_string(etc_dir, ".", "etc directory for presto configuration"); @@ -30,8 +29,3 @@ int main(int argc, char* argv[]) { presto.run(); PRESTO_SHUTDOWN_LOG(INFO) << "Exiting main()"; } - -// Initialize singleton for the reporter. -folly::Singleton reporter([]() { - return new facebook::velox::DummyStatsReporter(); -}); diff --git a/presto-native-execution/presto_cpp/main/PrestoServer.cpp b/presto-native-execution/presto_cpp/main/PrestoServer.cpp index 538d2df2cac3..61f9fc020526 100644 --- a/presto-native-execution/presto_cpp/main/PrestoServer.cpp +++ b/presto-native-execution/presto_cpp/main/PrestoServer.cpp @@ -164,10 +164,6 @@ void PrestoServer::run() { baseVeloxQueryConfig->initialize( fmt::format("{}/velox.properties", configDirectoryPath_), true); - if (systemConfig->enableRuntimeMetricsCollection()) { - enableRuntimeMetricReporting(); - } - httpPort = systemConfig->httpServerHttpPort(); if (systemConfig->httpServerHttpsEnabled()) { httpsPort = systemConfig->httpServerHttpsPort(); @@ -372,6 +368,21 @@ void PrestoServer::run() { .sendWithEOM(); }); + if (systemConfig->enableRuntimeMetricsCollection()) { + enableWorkerStatsReporting(); + if (folly::Singleton::try_get()) { + httpServer_->registerGet( + "/v1/info/metrics", + [](proxygen::HTTPMessage* /*message*/, + const std::vector>& /*body*/, + proxygen::ResponseHandler* downstream) { + http::sendOkResponse( + downstream, + folly::Singleton::try_get() + ->fetchMetrics()); + }); + } + } registerFunctions(); registerRemoteFunctions(); registerVectorSerdes(); @@ -1171,7 +1182,7 @@ std::string PrestoServer::getBaseSpillDirectory() const { return SystemConfig::instance()->spillerSpillPath().value_or(""); } -void PrestoServer::enableRuntimeMetricReporting() { +void PrestoServer::enableWorkerStatsReporting() { // This flag must be set to register the counters. facebook::velox::BaseStatsReporter::registered = true; registerStatsCounters(); diff --git a/presto-native-execution/presto_cpp/main/PrestoServer.h b/presto-native-execution/presto_cpp/main/PrestoServer.h index 0c34f57feb1f..42bb848c9ee4 100644 --- a/presto-native-execution/presto_cpp/main/PrestoServer.h +++ b/presto-native-execution/presto_cpp/main/PrestoServer.h @@ -170,7 +170,7 @@ class PrestoServer { virtual std::string getBaseSpillDirectory() const; /// Invoked to enable stats reporting and register counters. - virtual void enableRuntimeMetricReporting(); + virtual void enableWorkerStatsReporting(); /// Invoked to get the list of filters passed to the http server. std::vector> diff --git a/presto-native-execution/presto_cpp/main/runtime-metrics/CMakeLists.txt b/presto-native-execution/presto_cpp/main/runtime-metrics/CMakeLists.txt new file mode 100644 index 000000000000..bab9cd054672 --- /dev/null +++ b/presto-native-execution/presto_cpp/main/runtime-metrics/CMakeLists.txt @@ -0,0 +1,24 @@ +# 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. + +# Add as a source to presto_server to allow global reporter Singleton +# initialization. + +find_package(prometheus-cpp CONFIG REQUIRED) + +# Prepare a static library to link with prometheus_reporter_test +add_library(prometheus_reporter OBJECT PrometheusStatsReporter.cpp) +target_link_libraries(prometheus_reporter presto_common prometheus-cpp::core) + +if(PRESTO_ENABLE_TESTING) + add_subdirectory(tests) +endif() diff --git a/presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.cpp b/presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.cpp new file mode 100644 index 000000000000..2079beb3864f --- /dev/null +++ b/presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.cpp @@ -0,0 +1,238 @@ +/* + * 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 "presto_cpp/main/runtime-metrics/PrometheusStatsReporter.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace facebook::presto::prometheus { + +// Initialize singleton for the reporter +folly::Singleton reporter( + []() -> facebook::velox::BaseStatsReporter* { + return facebook::presto::prometheus::PrometheusStatsReporter:: + createPrometheusReporter() + .release(); + }); + +static constexpr std::string_view kSummarySuffix("_summary"); + +struct PrometheusStatsReporter::PrometheusImpl { + explicit PrometheusImpl(const ::prometheus::Labels& labels) { + registry = std::make_shared<::prometheus::Registry>(); + for (const auto& itr : labels) { + this->labels[itr.first] = itr.second; + } + } + + ::prometheus::Labels labels; + std::shared_ptr<::prometheus::Registry> registry; +}; + +PrometheusStatsReporter::PrometheusStatsReporter( + const std::map& labels) { + impl_ = std::make_shared(labels); +} + +void PrometheusStatsReporter::registerMetricExportType( + const char* key, + facebook::velox::StatType statType) const { + if (registeredMetricsMap_.count(key)) { + VLOG(1) << "Trying to register already registered metric " << key; + return; + } + // '.' is replaced with '_'. + std::string sanitizedMetricKey = std::string(key); + std::replace(sanitizedMetricKey.begin(), sanitizedMetricKey.end(), '.', '_'); + switch (statType) { + case facebook::velox::StatType::COUNT: { + // A new MetricFamily object is built for every new metric key. + auto& counterFamily = ::prometheus::BuildCounter() + .Name(sanitizedMetricKey) + .Register(*impl_->registry); + auto& counter = counterFamily.Add(impl_->labels); + registeredMetricsMap_.emplace( + std::string(key), StatsInfo{statType, &counter}); + } break; + case facebook::velox::StatType::SUM: + case facebook::velox::StatType::AVG: + case facebook::velox::StatType::RATE: { + auto& gaugeFamily = ::prometheus::BuildGauge() + .Name(sanitizedMetricKey) + .Register(*impl_->registry); + auto& gauge = gaugeFamily.Add(impl_->labels); + registeredMetricsMap_.emplace( + std::string(key), StatsInfo{statType, &gauge}); + } break; + default: + VELOX_UNSUPPORTED( + "Unsupported metric type {}", velox::statTypeString(statType)); + } +} + +void PrometheusStatsReporter::registerMetricExportType( + folly::StringPiece key, + facebook::velox::StatType statType) const { + registerMetricExportType(key.toString().c_str(), statType); +} + +void PrometheusStatsReporter::registerHistogramMetricExportType( + const char* key, + int64_t bucketWidth, + int64_t min, + int64_t max, + const std::vector& pcts) const { + if (registeredMetricsMap_.count(key)) { + // Already registered; + VLOG(1) << "Trying to register already registered metric " << key; + return; + } + auto numBuckets = (max - min) / bucketWidth; + auto bound = min + bucketWidth; + std::string sanitizedMetricKey = std::string(key); + // '.' is replaced with '_'. + std::replace(sanitizedMetricKey.begin(), sanitizedMetricKey.end(), '.', '_'); + + auto& histogramFamily = ::prometheus::BuildHistogram() + .Name(sanitizedMetricKey) + .Register(*impl_->registry); + + ::prometheus::Histogram::BucketBoundaries bucketBoundaries; + while (numBuckets > 0) { + bucketBoundaries.push_back(bound); + bound += bucketWidth; + numBuckets--; + } + VELOX_CHECK_GE(bucketBoundaries.size(), 1); + auto& histogramMetric = histogramFamily.Add(impl_->labels, bucketBoundaries); + + registeredMetricsMap_.emplace( + key, StatsInfo{velox::StatType::HISTOGRAM, &histogramMetric}); + // If percentiles are provided, create a Summary type metric and register. + if (pcts.size() > 0) { + auto summaryMetricKey = sanitizedMetricKey + std::string(kSummarySuffix); + auto& summaryFamily = ::prometheus::BuildSummary() + .Name(summaryMetricKey) + .Register(*impl_->registry); + ::prometheus::Summary::Quantiles quantiles; + for (auto pct : pcts) { + quantiles.push_back( + ::prometheus::detail::CKMSQuantiles::Quantile(pct / (double)100, 0)); + } + auto& summaryMetric = summaryFamily.Add({impl_->labels}, quantiles); + registeredMetricsMap_.emplace( + std::string(key).append(kSummarySuffix), + StatsInfo{velox::StatType::HISTOGRAM, &summaryMetric}); + } +} + +void PrometheusStatsReporter::registerHistogramMetricExportType( + folly::StringPiece key, + int64_t bucketWidth, + int64_t min, + int64_t max, + const std::vector& pcts) const { + registerHistogramMetricExportType( + key.toString().c_str(), bucketWidth, min, max, pcts); +} + +void PrometheusStatsReporter::addMetricValue( + const std::string& key, + size_t value) const { + addMetricValue(key.c_str(), value); +} + +void PrometheusStatsReporter::addMetricValue(const char* key, size_t value) + const { + auto metricIterator = registeredMetricsMap_.find(key); + if (metricIterator == registeredMetricsMap_.end()) { + VLOG(1) << "addMetricValue called for unregistered metric " << key; + return; + } + auto statsInfo = metricIterator->second; + switch (statsInfo.statType) { + case velox::StatType::COUNT: { + auto counter = + reinterpret_cast<::prometheus::Counter*>(statsInfo.metricPtr); + counter->Increment(value); + } break; + case velox::StatType::SUM: + case velox::StatType::AVG: + case velox::StatType::RATE: { + // Overrides the existing state. + auto gauge = reinterpret_cast<::prometheus::Gauge*>(statsInfo.metricPtr); + gauge->Set(value); + } break; + default: + VELOX_UNSUPPORTED( + "Unsupported metric type {}", + velox::statTypeString(statsInfo.statType)); + }; +} + +void PrometheusStatsReporter::addMetricValue( + folly::StringPiece key, + size_t value) const { + addMetricValue(key.toString().c_str(), value); +} + +void PrometheusStatsReporter::addHistogramMetricValue( + const std::string& key, + size_t value) const { + addHistogramMetricValue(key.c_str(), value); +} + +void PrometheusStatsReporter::addHistogramMetricValue( + const char* key, + size_t value) const { + auto metricIterator = registeredMetricsMap_.find(key); + if (metricIterator == registeredMetricsMap_.end()) { + VLOG(1) << "addMetricValue for unregistered metric " << key; + return; + } + auto histogram = reinterpret_cast<::prometheus::Histogram*>( + metricIterator->second.metricPtr); + histogram->Observe(value); + + std::string summaryKey = std::string(key).append(kSummarySuffix); + metricIterator = registeredMetricsMap_.find(summaryKey); + if (metricIterator != registeredMetricsMap_.end()) { + auto summary = reinterpret_cast<::prometheus::Summary*>( + metricIterator->second.metricPtr); + summary->Observe(value); + } +} + +void PrometheusStatsReporter::addHistogramMetricValue( + folly::StringPiece key, + size_t value) const { + addHistogramMetricValue(key.toString().c_str(), value); +} + +std::string PrometheusStatsReporter::fetchMetrics() { + if (registeredMetricsMap_.empty()) { + return ""; + } + ::prometheus::TextSerializer serializer; + // Registry::Collect() acquires lock on a mutex. + return serializer.Serialize(impl_->registry->Collect()); +} + +}; // namespace facebook::presto::prometheus diff --git a/presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.h b/presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.h new file mode 100644 index 000000000000..14eabc261815 --- /dev/null +++ b/presto-native-execution/presto_cpp/main/runtime-metrics/PrometheusStatsReporter.h @@ -0,0 +1,98 @@ +/* + * 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 "presto_cpp/main/common/Configs.h" +#include "velox/common/base/Exceptions.h" +#include "velox/common/base/GTestMacros.h" +#include "velox/common/base/StatsReporter.h" + +namespace facebook::presto::prometheus { + +struct StatsInfo { + velox::StatType statType; + void* metricPtr; +}; + +/// Prometheus CPP library exposes following classes: +/// 1. Registry. +/// 2. Family. +/// 3. Specific metric type classes like Counter, Gauge, Histogram etc. +/// +/// A family of metrics will have the same metric name. For example +/// http_latency_ms. Different members of a family will have unique labels. +/// For metric http_latency_ms labels could be {method="GET"}, {method="PUT"}, +/// {method="POST"} etc. Prometheus treats {, [labels]} as unique +/// metric object. +class PrometheusStatsReporter : public facebook::velox::BaseStatsReporter { + class PrometheusImpl; + + public: + explicit PrometheusStatsReporter( + const std::map& labels); + + void registerMetricExportType(const char* key, velox::StatType) + const override; + + void registerMetricExportType(folly::StringPiece key, velox::StatType) + const override; + + void registerHistogramMetricExportType( + const char* key, + int64_t bucketWidth, + int64_t min, + int64_t max, + const std::vector& pcts) const override; + + void registerHistogramMetricExportType( + folly::StringPiece key, + int64_t bucketWidth, + int64_t min, + int64_t max, + const std::vector& pcts) const override; + + void addMetricValue(const std::string& key, size_t value = 1) const override; + + void addMetricValue(const char* key, size_t value = 1) const override; + + void addMetricValue(folly::StringPiece key, size_t value = 1) const override; + + void addHistogramMetricValue(const std::string& key, size_t value) + const override; + + void addHistogramMetricValue(const char* key, size_t value) const override; + + void addHistogramMetricValue(folly::StringPiece key, size_t value) + const override; + + std::string fetchMetrics() override; + + static std::unique_ptr createPrometheusReporter() { + auto nodeConfig = NodeConfig::instance(); + const std::string cluster = nodeConfig->nodeEnvironment(); + const char* hostName = std::getenv("HOSTNAME"); + const std::string worker = !hostName ? "" : hostName; + std::map labels{ + {"cluster", cluster}, {"worker", worker}}; + return std::make_unique(labels); + } + + private: + std::shared_ptr impl_; + // A map of labels assigned to each metric which helps in filtering at client + // end. + mutable std::unordered_map registeredMetricsMap_; + VELOX_FRIEND_TEST(PrometheusReporterTest, testCountAndGauge); + VELOX_FRIEND_TEST(PrometheusReporterTest, testHistogramSummary); +}; // class PrometheusReporter +}; // namespace facebook::presto::prometheus diff --git a/presto-native-execution/presto_cpp/main/runtime-metrics/tests/CMakeLists.txt b/presto-native-execution/presto_cpp/main/runtime-metrics/tests/CMakeLists.txt new file mode 100644 index 000000000000..8f05d33d6101 --- /dev/null +++ b/presto-native-execution/presto_cpp/main/runtime-metrics/tests/CMakeLists.txt @@ -0,0 +1,19 @@ +# 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. + +add_executable(prometheus_reporter_test PrometheusReporterTest.cpp) +add_test( + NAME prometheus_reporter_test + COMMAND prometheus_reporter_test + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(prometheus_reporter_test velox_exec_test_lib + prometheus_reporter gtest gtest_main) diff --git a/presto-native-execution/presto_cpp/main/runtime-metrics/tests/PrometheusReporterTest.cpp b/presto-native-execution/presto_cpp/main/runtime-metrics/tests/PrometheusReporterTest.cpp new file mode 100644 index 000000000000..e2b7ffa178e8 --- /dev/null +++ b/presto-native-execution/presto_cpp/main/runtime-metrics/tests/PrometheusReporterTest.cpp @@ -0,0 +1,154 @@ +/* + * 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 "presto_cpp/main/runtime-metrics/PrometheusStatsReporter.h" + +#include + +namespace facebook::presto::prometheus { +class PrometheusReporterTest : public testing::Test { + public: + void SetUp() override { + reporter = std::make_shared(testLabels); + } + void verifySerializedResult( + const std::string& fullSerializedResult, + std::vector& expected) { + auto i = 0; + std::stringstream ss(fullSerializedResult); + std::string line; + while (getline(ss, line, '\n')) { + EXPECT_EQ(line, expected[i++]); + } + } + const std::map testLabels = { + {"cluster", "test_cluster"}, + {"worker", "test_worker_pod"}}; + const std::string labelsSerialized = + R"(cluster="test_cluster",worker="test_worker_pod")"; + std::shared_ptr reporter; +}; + +TEST_F(PrometheusReporterTest, testCountAndGauge) { + reporter->registerMetricExportType( + "test.key1", facebook::velox::StatType::COUNT); + reporter->registerMetricExportType( + "test.key2", facebook::velox::StatType::AVG); + reporter->registerMetricExportType( + "test.key3", facebook::velox::StatType::SUM); + reporter->registerMetricExportType( + "test.key4", facebook::velox::StatType::RATE); + EXPECT_EQ( + facebook::velox::StatType::COUNT, + reporter->registeredMetricsMap_.find("test.key1")->second.statType); + EXPECT_EQ( + facebook::velox::StatType::AVG, + reporter->registeredMetricsMap_.find("test.key2")->second.statType); + EXPECT_EQ( + facebook::velox::StatType::SUM, + reporter->registeredMetricsMap_.find("test.key3")->second.statType); + EXPECT_EQ( + facebook::velox::StatType::RATE, + reporter->registeredMetricsMap_.find("test.key4")->second.statType); + + std::vector testData = {10, 11, 15}; + for (auto i : testData) { + reporter->addMetricValue("test.key1", i); + reporter->addMetricValue("test.key2", i + 1000); + } + // Uses default value of 1 for second parameter. + reporter->addMetricValue("test.key1"); + auto fullSerializedResult = reporter->fetchMetrics(); + + std::vector expected = { + "# TYPE test_key1 counter", + "test_key1{" + labelsSerialized + "} 37", + "# TYPE test_key2 gauge", + "test_key2{" + labelsSerialized + "} 1015", + "# TYPE test_key3 gauge", + "test_key3{" + labelsSerialized + "} 0", + "# TYPE test_key4 gauge", + "test_key4{" + labelsSerialized + "} 0"}; + + verifySerializedResult(fullSerializedResult, expected); +}; + +TEST_F(PrometheusReporterTest, testHistogramSummary) { + std::string histSummaryKey = "test.histogram.key1"; + std::string histogramKey = "test.histogram.key2"; + // Register Histograms and Summaries. + reporter->registerHistogramMetricExportType( + histSummaryKey, 10, 0, 100, {50, 99, 100}); + // Only histogram. + reporter->registerHistogramMetricExportType(histogramKey, 10, 0, 100, {}); + int recordCount = 100; + int sum = 0; + for (int i = 0; i < recordCount; ++i) { + if (i < 20) { + reporter->addHistogramMetricValue(histSummaryKey, 20); + sum += 20; + } else if (i >= 20 && i < 50) { + reporter->addHistogramMetricValue(histSummaryKey, 50); + sum += 50; + } else { + reporter->addHistogramMetricValue(histSummaryKey, 85); + sum += 85; + } + } + reporter->addHistogramMetricValue(histogramKey, 10); + auto fullSerializedResult = reporter->fetchMetrics(); + std::replace(histSummaryKey.begin(), histSummaryKey.end(), '.', '_'); + std::replace(histogramKey.begin(), histogramKey.end(), '.', '_'); + std::vector histogramMetricsFormatted = { + "# TYPE " + histSummaryKey + " histogram", + histSummaryKey + "_count{" + labelsSerialized + "} " + + std::to_string(recordCount), + histSummaryKey + "_sum{" + labelsSerialized + "} " + std::to_string(sum), + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"10\"} 0", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"20\"} 20", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"30\"} 20", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"40\"} 20", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"50\"} 50", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"60\"} 50", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"70\"} 50", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"80\"} 50", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"90\"} 100", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"100\"} 100", + histSummaryKey + "_bucket{" + labelsSerialized + ",le=\"+Inf\"} 100", + "# TYPE test_histogram_key2 histogram", + histogramKey + "_count{" + labelsSerialized + "} 1", + histogramKey + "_sum{" + labelsSerialized + "} 10", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"10\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"20\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"30\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"40\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"50\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"60\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"70\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"80\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"90\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"100\"} 1", + histogramKey + "_bucket{" + labelsSerialized + ",le=\"+Inf\"} 1", + "# TYPE test_histogram_key1_summary summary", + histSummaryKey + "_summary_count{" + labelsSerialized + "} " + + std::to_string(recordCount), + histSummaryKey + "_summary_sum{" + labelsSerialized + "} " + + std::to_string(sum), + histSummaryKey + "_summary{" + labelsSerialized + ",quantile=\"0.5\"} 50", + histSummaryKey + "_summary{" + labelsSerialized + + ",quantile=\"0.99\"} 85", + histSummaryKey + "_summary{" + labelsSerialized + ",quantile=\"1\"} 85"}; + verifySerializedResult(fullSerializedResult, histogramMetricsFormatted); +} +} // namespace facebook::presto::prometheus diff --git a/presto-native-execution/presto_cpp/main/tests/HttpServerWrapper.cpp b/presto-native-execution/presto_cpp/main/tests/HttpServerWrapper.cpp index 25f050cb8871..d1a9c64a2976 100644 --- a/presto-native-execution/presto_cpp/main/tests/HttpServerWrapper.cpp +++ b/presto-native-execution/presto_cpp/main/tests/HttpServerWrapper.cpp @@ -37,10 +37,4 @@ void HttpServerWrapper::stop() { serverThread_.reset(); } } - -// Initialize singleton for the reporter -folly::Singleton reporter([]() { - return new facebook::velox::DummyStatsReporter(); -}); - } // namespace facebook::presto::test diff --git a/presto-native-execution/scripts/setup-adapters.sh b/presto-native-execution/scripts/setup-adapters.sh index d25423323c81..6c36424ebf90 100755 --- a/presto-native-execution/scripts/setup-adapters.sh +++ b/presto-native-execution/scripts/setup-adapters.sh @@ -28,7 +28,7 @@ function install_jwt_cpp { cmake_install -DBUILD_TESTS=OFF -DJWT_BUILD_EXAMPLES=OFF -DJWT_DISABLE_PICOJSON=ON -DJWT_CMAKE_FILES_INSTALL_DIR="${DEPENDENCY_DIR}/jwt-cpp" } -function install_prometheus_cpp() { +function install_prometheus_cpp { github_checkout jupp0r/prometheus-cpp v1.2.4 --depth 1 git submodule init git submodule update