diff --git a/src/aio/test/CMakeLists.txt b/src/aio/test/CMakeLists.txt index cbc853d834..f142abbc5b 100644 --- a/src/aio/test/CMakeLists.txt +++ b/src/aio/test/CMakeLists.txt @@ -36,7 +36,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) set(MY_BINPLACES config.ini diff --git a/src/base/test/CMakeLists.txt b/src/base/test/CMakeLists.txt index b7e1c29d0e..7cd985982d 100644 --- a/src/base/test/CMakeLists.txt +++ b/src/base/test/CMakeLists.txt @@ -28,10 +28,12 @@ set(MY_PROJ_SRC "") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - dsn_runtime - dsn_utils - pegasus_base - gtest) + dsn_runtime + dsn_utils + pegasus_base + gtest + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/block_service/test/CMakeLists.txt b/src/block_service/test/CMakeLists.txt index b8aaad6520..53e4a4e670 100644 --- a/src/block_service/test/CMakeLists.txt +++ b/src/block_service/test/CMakeLists.txt @@ -35,7 +35,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/client/test/CMakeLists.txt b/src/client/test/CMakeLists.txt index 60f3762760..19060d8e00 100644 --- a/src/client/test/CMakeLists.txt +++ b/src/client/test/CMakeLists.txt @@ -30,7 +30,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt index fab0926249..8d7f72b29b 100644 --- a/src/common/test/CMakeLists.txt +++ b/src/common/test/CMakeLists.txt @@ -34,7 +34,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/failure_detector/test/CMakeLists.txt b/src/failure_detector/test/CMakeLists.txt index 54907d6ee8..c974786f34 100644 --- a/src/failure_detector/test/CMakeLists.txt +++ b/src/failure_detector/test/CMakeLists.txt @@ -37,7 +37,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) set(MY_BINPLACES run.sh diff --git a/src/geo/bench/CMakeLists.txt b/src/geo/bench/CMakeLists.txt index 559747b59d..691adc31cd 100644 --- a/src/geo/bench/CMakeLists.txt +++ b/src/geo/bench/CMakeLists.txt @@ -38,7 +38,9 @@ set(MY_PROJ_LIBS lz4 zstd snappy - dsn_utils) + dsn_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/geo/test/CMakeLists.txt b/src/geo/test/CMakeLists.txt index e29d506ae1..798a9f071b 100644 --- a/src/geo/test/CMakeLists.txt +++ b/src/geo/test/CMakeLists.txt @@ -35,7 +35,9 @@ set(MY_PROJ_LIBS s2 pegasus_client_static dsn_utils - gtest) + gtest + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/http/test/CMakeLists.txt b/src/http/test/CMakeLists.txt index 4400c0183f..6c3cbe38fb 100644 --- a/src/http/test/CMakeLists.txt +++ b/src/http/test/CMakeLists.txt @@ -29,7 +29,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/meta/test/CMakeLists.txt b/src/meta/test/CMakeLists.txt index 13a1efe9d1..30f8ed222d 100644 --- a/src/meta/test/CMakeLists.txt +++ b/src/meta/test/CMakeLists.txt @@ -44,7 +44,9 @@ set(MY_PROJ_LIBS zookeeper hashtable gtest - hdfs) + hdfs + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) set(MY_BINPLACES clear.sh diff --git a/src/meta/test/balancer_simulator/CMakeLists.txt b/src/meta/test/balancer_simulator/CMakeLists.txt index 69ddfc4a44..2ea7c4271f 100644 --- a/src/meta/test/balancer_simulator/CMakeLists.txt +++ b/src/meta/test/balancer_simulator/CMakeLists.txt @@ -30,7 +30,9 @@ set(MY_PROJ_LIBS dsn_meta_server dsn_ranger dsn_replication_common - gtest) + gtest + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) set(MY_BINPLACES "") dsn_add_test() diff --git a/src/nfs/test/CMakeLists.txt b/src/nfs/test/CMakeLists.txt index 4a22ce4867..acf4cce9cb 100644 --- a/src/nfs/test/CMakeLists.txt +++ b/src/nfs/test/CMakeLists.txt @@ -43,7 +43,9 @@ set(MY_PROJ_LIBS lz4 zstd snappy - test_utils) + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/perf_counter/test/CMakeLists.txt b/src/perf_counter/test/CMakeLists.txt index 1b1a8d2292..4b12b074aa 100644 --- a/src/perf_counter/test/CMakeLists.txt +++ b/src/perf_counter/test/CMakeLists.txt @@ -34,7 +34,9 @@ set(MY_PROJ_LIBS lz4 zstd snappy - gtest) + gtest + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) set(MY_BINPLACES clear.sh diff --git a/src/ranger/test/CMakeLists.txt b/src/ranger/test/CMakeLists.txt index 443791ff28..c28165f11e 100644 --- a/src/ranger/test/CMakeLists.txt +++ b/src/ranger/test/CMakeLists.txt @@ -24,7 +24,9 @@ set(MY_PROJ_LIBS dsn_meta_server dsn_replication_common dsn_utils - gtest) + gtest + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BINPLACES run.sh) dsn_add_test() diff --git a/src/redis_protocol/proxy/CMakeLists.txt b/src/redis_protocol/proxy/CMakeLists.txt index b741360568..8e26c5a8a1 100644 --- a/src/redis_protocol/proxy/CMakeLists.txt +++ b/src/redis_protocol/proxy/CMakeLists.txt @@ -26,14 +26,16 @@ set(MY_PROJ_SRC "") # "GLOB" for non-recursive search set(MY_SRC_SEARCH_MODE "GLOB") -set(MY_PROJ_LIBS pegasus.rproxylib - absl::flat_hash_set - absl::strings - pegasus_geo_lib - event - s2 - pegasus_client_static - ) +set(MY_PROJ_LIBS + pegasus.rproxylib + absl::flat_hash_set + absl::strings + pegasus_geo_lib + event + s2 + pegasus_client_static + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BINPLACES "config.ini") diff --git a/src/redis_protocol/proxy_ut/CMakeLists.txt b/src/redis_protocol/proxy_ut/CMakeLists.txt index cf7bb1df37..b3ed3e3137 100644 --- a/src/redis_protocol/proxy_ut/CMakeLists.txt +++ b/src/redis_protocol/proxy_ut/CMakeLists.txt @@ -29,15 +29,17 @@ set(MY_SRC_SEARCH_MODE "GLOB") set(MY_BOOST_LIBS Boost::system Boost::filesystem) -set(MY_PROJ_LIBS pegasus.rproxylib - pegasus_base - absl::flat_hash_set - absl::strings - pegasus_geo_lib - s2 - pegasus_client_static - gtest - ) +set(MY_PROJ_LIBS + pegasus.rproxylib + pegasus_base + absl::flat_hash_set + absl::strings + pegasus_geo_lib + s2 + pegasus_client_static + gtest + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BINPLACES "config.ini" "run.sh") diff --git a/src/sample/CMakeLists.txt b/src/sample/CMakeLists.txt index b0618dfca8..a84922cdd5 100644 --- a/src/sample/CMakeLists.txt +++ b/src/sample/CMakeLists.txt @@ -20,8 +20,9 @@ set(MY_PROJ_NAME "sample") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - pegasus_client_static - ) + pegasus_client_static + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::filesystem Boost::system) diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 11673f6930..bd51932b92 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -36,7 +36,9 @@ set(MY_PROJ_LIBS pegasus_base pegasus_client_static event - hashtable) + hashtable + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) set(MY_BINPLACES config.ini) diff --git a/src/server/test/CMakeLists.txt b/src/server/test/CMakeLists.txt index 082a98c1e4..64b17028cc 100644 --- a/src/server/test/CMakeLists.txt +++ b/src/server/test/CMakeLists.txt @@ -52,7 +52,9 @@ set(MY_PROJ_LIBS pegasus_base gtest gmock - hashtable) + hashtable + prometheus-cpp-core + prometheus-cpp-pull) add_definitions(-DPEGASUS_UNIT_TEST) add_definitions(-DENABLE_FAIL) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/bench_test/CMakeLists.txt b/src/test/bench_test/CMakeLists.txt index 5a52808d8d..c023528d1e 100644 --- a/src/test/bench_test/CMakeLists.txt +++ b/src/test/bench_test/CMakeLists.txt @@ -36,7 +36,9 @@ set(MY_PROJ_LIBS snappy sasl2 gssapi_krb5 - krb5) + krb5 + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/backup_restore/CMakeLists.txt b/src/test/function_test/backup_restore/CMakeLists.txt index 41a6c6ed2b..adbc10b8ea 100644 --- a/src/test/function_test/backup_restore/CMakeLists.txt +++ b/src/test/function_test/backup_restore/CMakeLists.txt @@ -30,7 +30,9 @@ set(MY_PROJ_LIBS krb5 function_test_utils pegasus_client_static - test_utils) + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/base_api/CMakeLists.txt b/src/test/function_test/base_api/CMakeLists.txt index 3e688f3a17..c104dc7335 100644 --- a/src/test/function_test/base_api/CMakeLists.txt +++ b/src/test/function_test/base_api/CMakeLists.txt @@ -28,17 +28,18 @@ set(MY_PROJ_SRC "") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - dsn_client - dsn_replication_common - dsn_utils - pegasus_client_static - gtest - sasl2 - gssapi_krb5 - krb5 - function_test_utils - test_utils - ) + dsn_client + dsn_replication_common + dsn_utils + pegasus_client_static + gtest + sasl2 + gssapi_krb5 + krb5 + function_test_utils + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/bulk_load/CMakeLists.txt b/src/test/function_test/bulk_load/CMakeLists.txt index 03f55fac24..0db6c2ef6c 100644 --- a/src/test/function_test/bulk_load/CMakeLists.txt +++ b/src/test/function_test/bulk_load/CMakeLists.txt @@ -43,7 +43,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/detect_hotspot/CMakeLists.txt b/src/test/function_test/detect_hotspot/CMakeLists.txt index 8a8070d854..dea8906e22 100644 --- a/src/test/function_test/detect_hotspot/CMakeLists.txt +++ b/src/test/function_test/detect_hotspot/CMakeLists.txt @@ -37,7 +37,9 @@ set(MY_PROJ_LIBS gssapi_krb5 krb5 function_test_utils - test_utils) + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/partition_split/CMakeLists.txt b/src/test/function_test/partition_split/CMakeLists.txt index b2cff9f606..557ed82927 100644 --- a/src/test/function_test/partition_split/CMakeLists.txt +++ b/src/test/function_test/partition_split/CMakeLists.txt @@ -28,17 +28,18 @@ set(MY_PROJ_SRC "") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - dsn_client - dsn_replication_common - dsn_utils - pegasus_client_static - gtest - sasl2 - gssapi_krb5 - krb5 - function_test_utils - test_utils - ) + dsn_client + dsn_replication_common + dsn_utils + pegasus_client_static + gtest + sasl2 + gssapi_krb5 + krb5 + function_test_utils + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/recovery/CMakeLists.txt b/src/test/function_test/recovery/CMakeLists.txt index a13d12734b..7eb58855c4 100644 --- a/src/test/function_test/recovery/CMakeLists.txt +++ b/src/test/function_test/recovery/CMakeLists.txt @@ -37,7 +37,9 @@ set(MY_PROJ_LIBS gssapi_krb5 krb5 function_test_utils - test_utils) + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/restore/CMakeLists.txt b/src/test/function_test/restore/CMakeLists.txt index 18b0ad4446..872b3b8082 100644 --- a/src/test/function_test/restore/CMakeLists.txt +++ b/src/test/function_test/restore/CMakeLists.txt @@ -37,7 +37,9 @@ set(MY_PROJ_LIBS krb5 function_test_utils pegasus_client_static - test_utils) + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/function_test/throttle/CMakeLists.txt b/src/test/function_test/throttle/CMakeLists.txt index 70460d0c5d..b6a5c48a4c 100644 --- a/src/test/function_test/throttle/CMakeLists.txt +++ b/src/test/function_test/throttle/CMakeLists.txt @@ -28,17 +28,18 @@ set(MY_PROJ_SRC "") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - dsn_client - dsn_replication_common - dsn_utils - pegasus_client_static - gtest - sasl2 - gssapi_krb5 - krb5 - function_test_utils - test_utils - ) + dsn_client + dsn_replication_common + dsn_utils + pegasus_client_static + gtest + sasl2 + gssapi_krb5 + krb5 + function_test_utils + test_utils + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/kill_test/CMakeLists.txt b/src/test/kill_test/CMakeLists.txt index df97448737..955817f565 100644 --- a/src/test/kill_test/CMakeLists.txt +++ b/src/test/kill_test/CMakeLists.txt @@ -28,17 +28,19 @@ set(MY_PROJ_SRC "") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - pegasus_base - pegasus_client_static - dsn_client - dsn_replication_common - dsn_dist_cmd - dsn_runtime - dsn_utils - sasl2 - gssapi_krb5 - krb5 - ) + pegasus_base + pegasus_client_static + dsn_client + dsn_replication_common + dsn_dist_cmd + dsn_runtime + dsn_utils + sasl2 + gssapi_krb5 + krb5 + prometheus-cpp-core + prometheus-cpp-pull) + set(MY_BINPLACES "${CMAKE_CURRENT_SOURCE_DIR}/config.ini") set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/test/pressure_test/CMakeLists.txt b/src/test/pressure_test/CMakeLists.txt index 42e29b7366..a971aa1000 100644 --- a/src/test/pressure_test/CMakeLists.txt +++ b/src/test/pressure_test/CMakeLists.txt @@ -28,12 +28,13 @@ set(MY_PROJ_SRC "") set(MY_SRC_SEARCH_MODE "GLOB") set(MY_PROJ_LIBS - pegasus_client_static - dsn_utils - sasl2 - gssapi_krb5 - krb5 - ) + pegasus_client_static + dsn_utils + sasl2 + gssapi_krb5 + krb5 + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BINPLACES "${CMAKE_CURRENT_SOURCE_DIR}/config-pressure.ini") diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 337ac2591b..a326455003 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -37,7 +37,9 @@ set(MY_PROJ_LIBS lz4 zstd snappy - absl::strings) + absl::strings + prometheus-cpp-core + prometheus-cpp-pull) # Extra files that will be installed set(MY_BINPLACES "") diff --git a/src/utils/long_adder_bench/CMakeLists.txt b/src/utils/long_adder_bench/CMakeLists.txt index 71568c61ae..1e2e645eac 100644 --- a/src/utils/long_adder_bench/CMakeLists.txt +++ b/src/utils/long_adder_bench/CMakeLists.txt @@ -33,7 +33,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/utils/metrics.cpp b/src/utils/metrics.cpp index 1677584bed..b439332900 100644 --- a/src/utils/metrics.cpp +++ b/src/utils/metrics.cpp @@ -26,6 +26,9 @@ #include #include +#include +#include + #include "http/http_method.h" #include "http/http_status_code.h" #include "runtime/api_layer1.h" @@ -205,6 +208,106 @@ void metric_entity::take_snapshot(metric_json_writer &writer, const metric_filte writer.EndObject(); } +void metric_entity::take_snapshot(const std::shared_ptr &prometheus_registry, + const metric_filters &filters) const +{ + // TODO(yingchun): deplicate, refactor it. + if (!filters.match_entity_type(_prototype->name())) { + return; + } + + if (!filters.match_entity_id(_id)) { + return; + } + + attr_map my_attrs; + metric_map target_metrics; + + { + utils::auto_read_lock l(_lock); + + if (!filters.match_entity_attrs(_attrs)) { + return; + } + + filters.extract_entity_metrics(_metrics, target_metrics); + if (target_metrics.empty()) { + // None of metrics is chosen, there is no need to take snapshot for + // this entity. + return; + } + + my_attrs = _attrs; + } + //================================================================= + + // At least one metric of this entity has been chosen, thus take snapshot and encode + // this entity as json format. + for (const auto & [ mtx_pt, mtx ] : target_metrics) { + switch (mtx_pt->type()) { + case metric_type::kGauge: { + auto &family = prometheus::BuildGauge() + .Name(mtx_pt->name().data()) + .Help(fmt::format( + "{}, {}", mtx_pt->description(), enum_to_string(mtx_pt->unit()))) + .Labels({{kMetricEntityTypeField, _prototype->name()}}) + .Register(*prometheus_registry); + for (const auto &attr : my_attrs) { + family.Add({{attr.first, attr.second}}); + } + auto &metric = family.Add({{kMetricEntityIdField, _id}}); + mtx->take_snapshot(&metric); + break; + } + case metric_type::kCounter: { + auto &family = prometheus::BuildCounter() + .Name(mtx_pt->name().data()) + .Help(fmt::format( + "{}, {}", mtx_pt->description(), enum_to_string(mtx_pt->unit()))) + .Labels({{kMetricEntityTypeField, _prototype->name()}}) + .Register(*prometheus_registry); + for (const auto &attr : my_attrs) { + family.Add({{attr.first, attr.second}}); + } + auto &metric = family.Add({{kMetricEntityIdField, _id}}); + mtx->take_snapshot(&metric); + break; + } + case metric_type::kVolatileCounter: { + auto &family = prometheus::BuildCounter() + .Name(mtx_pt->name().data()) + .Help(fmt::format( + "{}, {}", mtx_pt->description(), enum_to_string(mtx_pt->unit()))) + .Labels({{kMetricEntityTypeField, _prototype->name()}}) + .Register(*prometheus_registry); + for (const auto &attr : my_attrs) { + family.Add({{attr.first, attr.second}}); + } + auto &metric = family.Add({{kMetricEntityIdField, _id}}); + mtx->take_snapshot(&metric); + break; + } + case metric_type::kPercentile: { + // auto &family = prometheus::BuildSummary() + // .Name(mtx_pt->name().data()) + // .Help(fmt::format("{}, {}", mtx_pt->description(), + // enum_to_string(mtx_pt->unit()))) + // .Labels({{kMetricEntityTypeField, _prototype->name()}}) + // .Register(*prometheus_registry); + // for (const auto &attr: my_attrs) { + // family.Add({{attr.first, attr.second}}); + // } + // auto &metric = family.Add({{kMetricEntityIdField, _id}}); + // mtx->take_snapshot(&metric, filters); + // break; + } + default: + LOG_FATAL("unknown metric type: {}", static_cast(mtx_pt->type())); + break; + } + } +} + bool metric_entity::is_stale() const { // Since this entity itself is still being accessed, its reference count should be 1 @@ -278,7 +381,8 @@ const std::string metrics_http_service::kMetricsQuerySubPath("metrics"); const std::string metrics_http_service::kMetricsQueryPath('/' + metrics_http_service::kMetricsQuerySubPath); -metrics_http_service::metrics_http_service(metric_registry *registry) : _registry(registry) +metrics_http_service::metrics_http_service(metric_registry *registry) + : _registry(registry), _prom_exposer("127.0.0.1:8080") { register_handler(kMetricsQuerySubPath, std::bind(&metrics_http_service::get_metrics_handler, @@ -289,6 +393,7 @@ metrics_http_service::metrics_http_service(metric_registry *registry) : _registr "..][&attributes=attr1,value1,attr2,value2,...][&metrics=metric1,metric2,...][" "&detail=true|false]" "Query the node metrics."); + _prom_exposer.RegisterCollectable(_prom_registry); } namespace { @@ -335,10 +440,14 @@ void metrics_http_service::get_metrics_handler(const http_request &req, http_res } metric_filters filters; + // Default in JSON format, otherwise in Prometheus format. + bool prometheus_format = false; bool with_metric_fields = false; bool detail = false; for (const auto &field : req.query_args) { - if (field.first == "with_metric_fields") { + if (field.first == "prometheus") { + prometheus_format = true; + } else if (field.first == "with_metric_fields") { parse_as(field.second, filters.with_metric_fields); with_metric_fields = true; } else if (field.first == "types") { @@ -377,11 +486,17 @@ void metrics_http_service::get_metrics_handler(const http_request &req, http_res filters.with_metric_fields = kBriefMetricFields; } - resp.body = take_snapshot_as_json(_registry, filters); + if (prometheus_format) { + take_snapshot_as_prometheus(_registry, _prom_registry, filters); + } else { + resp.body = take_snapshot_as_json(_registry, filters); + } resp.status_code = http_status_code::kOk; } -metric_registry::metric_registry() : _http_service(this) +metric_registry::metric_registry() : + _prom_registry(std::make_shared()), + _http_service(this) { // We should ensure that metric_registry is destructed before shared_io_service is destructed. // Once shared_io_service is destructed before metric_registry is destructed, @@ -456,11 +571,9 @@ metric_entity_ptr metric_registry::find_or_create_entity(const metric_entity_pro const std::string &id, const metric_entity::attr_map &attrs) { - utils::auto_write_lock l(_lock); - - entity_map::const_iterator iter = _entities.find(id); - metric_entity_ptr entity; + utils::auto_write_lock l(_lock); + const auto &iter = _entities.find(id); if (iter == _entities.end()) { entity = new metric_entity(prototype, id, attrs); _entities[id] = entity; @@ -498,6 +611,16 @@ void encode_cluster(dsn::metric_json_writer &writer) ENCODE_OBJ_VAL(!utils::is_empty(FLAGS_cluster_name), FLAGS_cluster_name); } +void encode_cluster(const std::shared_ptr &prometheus_registry) +{ + prometheus::BuildInfo() + .Name(kMetricClusterField) + .Help("Cluster name") + .Labels({{kMetricClusterField, + utils::is_empty(FLAGS_cluster_name) ? "unknown" : FLAGS_cluster_name}}) + .Register(*prometheus_registry); +} + void encode_role(dsn::metric_json_writer &writer) { writer.Key(dsn::kMetricRoleField.c_str()); @@ -506,12 +629,33 @@ void encode_role(dsn::metric_json_writer &writer) ENCODE_OBJ_VAL(node != nullptr, node->get_service_app_info().full_name); } +void encode_role(const std::shared_ptr &prometheus_registry) +{ + const auto *const node = dsn::task::get_current_node2(); + prometheus::BuildInfo() + .Name(kMetricRoleField) + .Help("Role name") + .Labels({{kMetricRoleField, node ? node->get_service_app_info().full_name : "unknown"}}) + .Register(*prometheus_registry); +} + void encode_host(dsn::metric_json_writer &writer) { writer.Key(dsn::kMetricHostField.c_str()); char hostname[1024]; - ENCODE_OBJ_VAL(gethostname(hostname, sizeof(hostname)) == 0, hostname); + ENCODE_OBJ_VAL(::gethostname(hostname, sizeof(hostname)) == 0, hostname); +} + +void encode_host(const std::shared_ptr &prometheus_registry) +{ + char hostname[1024]; + prometheus::BuildInfo() + .Name(kMetricHostField) + .Help("Host name") + .Labels({{kMetricHostField, + ::gethostname(hostname, sizeof(hostname)) == 0 ? hostname : "unknown"}}) + .Register(*prometheus_registry); } void encode_port(dsn::metric_json_writer &writer) @@ -522,6 +666,17 @@ void encode_port(dsn::metric_json_writer &writer) ENCODE_OBJ_VAL(rpc != nullptr, rpc->primary_host_port().port()); } +void encode_port(const std::shared_ptr &prometheus_registry) +{ + const auto *const rpc = dsn::task::get_current_rpc2(); + prometheus::BuildInfo() + .Name(kMetricPortField) + .Help("Service RPC port") + .Labels( + {{kMetricPortField, rpc ? std::to_string(rpc->primary_host_port().port()) : "unknown"}}) + .Register(*prometheus_registry); +} + void encode_timestamp_ns(dsn::metric_json_writer &writer) { writer.Key(dsn::kMetricTimestampNsField.c_str()); @@ -529,6 +684,16 @@ void encode_timestamp_ns(dsn::metric_json_writer &writer) ENCODE_OBJ_VAL(true, dsn_now_ns()); } +void encode_timestamp_ns(const std::shared_ptr &prometheus_registry) +{ + const auto *const rpc = dsn::task::get_current_rpc2(); + auto &ts = prometheus::BuildGauge() + .Name(kMetricTimestampNsField) + .Help("Current timestamp in nanoseconds") + .Register(*prometheus_registry); + ts.Add({}).Set(dsn_now_ns()); +} + #undef ENCODE_OBJ_VAL } // anonymous namespace @@ -551,6 +716,17 @@ void metric_registry::encode_entities(metric_json_writer &writer, writer.EndArray(); } +void metric_registry::encode_entities( + const std::shared_ptr &prometheus_registry, + const metric_filters &filters) const +{ + utils::auto_read_lock l(_lock); + + for (const auto &entity : _entities) { + entity.second->take_snapshot(prometheus_registry, filters); + } +} + void metric_registry::take_snapshot(metric_json_writer &writer, const metric_filters &filters) const { writer.StartObject(); @@ -563,6 +739,18 @@ void metric_registry::take_snapshot(metric_json_writer &writer, const metric_fil writer.EndObject(); } +void metric_registry::take_snapshot( + const std::shared_ptr &prometheus_registry, + const metric_filters &filters) const +{ + encode_cluster(prometheus_registry); + encode_role(prometheus_registry); + encode_host(prometheus_registry); + encode_port(prometheus_registry); + encode_timestamp_ns(prometheus_registry); + encode_entities(prometheus_registry, filters); +} + metric_registry::collected_entities_info metric_registry::collect_stale_entities() const { collected_entities_info collected_info; diff --git a/src/utils/metrics.h b/src/utils/metrics.h index e8a9cdc6a3..66764dc473 100644 --- a/src/utils/metrics.h +++ b/src/utils/metrics.h @@ -40,6 +40,12 @@ #include #include +#include +#include +#include +#include +#include + #include "absl/strings/string_view.h" #include "common/json_helper.h" #include "http/http_server.h" @@ -343,7 +349,8 @@ namespace dsn { class metric; // IWYU pragma: keep class metric_entity_prototype; // IWYU pragma: keep class metric_prototype; // IWYU pragma: keep -struct metric_filters; // IWYU pragma: keep +class metric_registry; +struct metric_filters; // IWYU pragma: keep using metric_ptr = ref_ptr; @@ -361,6 +368,7 @@ const std::string kMetricPortField = "port"; const std::string kMetricTimestampNsField = "timestamp_ns"; const std::string kMetricEntitiesField = "entities"; +// prometheus::Family class metric_entity : public ref_counter { public: @@ -380,6 +388,8 @@ class metric_entity : public ref_counter ref_ptr find_or_create(const metric_prototype *prototype, Args &&... args); void take_snapshot(metric_json_writer &writer, const metric_filters &filters) const; + void take_snapshot(const std::shared_ptr &prometheus_registry, + const metric_filters &filters) const; private: friend class metric_registry; @@ -570,8 +580,6 @@ class metric_entity_prototype DISALLOW_COPY_AND_ASSIGN(metric_entity_prototype); }; -class metric_registry; // IWYU pragma: keep - class metrics_http_service : public http_server_base { public: @@ -593,6 +601,9 @@ class metrics_http_service : public http_server_base metric_registry *_registry; + prometheus::Exposer _prom_exposer; + std::shared_ptr _prom_registry; + DISALLOW_COPY_AND_ASSIGN(metrics_http_service); }; @@ -644,6 +655,7 @@ class metric_timer DISALLOW_COPY_AND_ASSIGN(metric_timer); }; +// prometheus::Registry class metric_registry : public utils::singleton { public: @@ -689,6 +701,9 @@ class metric_registry : public utils::singleton void take_snapshot(metric_json_writer &writer, const metric_filters &filters) const; + void take_snapshot(const std::shared_ptr &prometheus_registry, + const metric_filters &filters) const; + private: friend class metric_entity_prototype; friend class utils::singleton; @@ -710,6 +725,8 @@ class metric_registry : public utils::singleton const metric_entity::attr_map &attrs); void encode_entities(metric_json_writer &writer, const metric_filters &filters) const; + void encode_entities(const std::shared_ptr &prometheus_registry, + const metric_filters &filters) const; // These functions are used to retire stale entities. // @@ -737,6 +754,9 @@ class metric_registry : public utils::singleton mutable utils::rw_lock_nr _lock; entity_map _entities; + + std::shared_ptr _prom_registry; + metrics_http_service _http_service; std::unique_ptr _timer; @@ -744,6 +764,14 @@ class metric_registry : public utils::singleton DISALLOW_COPY_AND_ASSIGN(metric_registry); }; +inline void +take_snapshot_as_prometheus(metric_registry *registry, + const std::shared_ptr &prometheus_registry, + const metric_filters &filters) +{ + registry->take_snapshot(prometheus_registry, filters); +} + // metric_type is needed while metrics are collected to monitoring systems. Generally // each monitoring system has its own types of metrics: firstly we should know which // type our metric belongs to; then we can know how to "translate" it to the specific @@ -914,7 +942,7 @@ ref_ptr metric_entity::find_or_create(const metric_prototype *protot utils::auto_write_lock l(_lock); - metric_map::const_iterator iter = _metrics.find(prototype); + const auto &iter = _metrics.find(prototype); if (iter != _metrics.end()) { auto raw_ptr = down_cast(iter->second.get()); return raw_ptr; @@ -948,6 +976,12 @@ class metric : public ref_counter // Take snapshot of each metric to collect current values as json format with fields chosen // by `filters`. virtual void take_snapshot(metric_json_writer &writer, const metric_filters &filters) = 0; + virtual void take_snapshot(prometheus::Gauge *gauge) { CHECK_TRUE(false); } + virtual void take_snapshot(prometheus::Counter *counter) { CHECK_TRUE(false); } + virtual void take_snapshot(prometheus::Summary *summary, const metric_filters &filters) + { + CHECK_TRUE(false); + } protected: explicit metric(const metric_prototype *prototype); @@ -1040,6 +1074,7 @@ class closeable_metric : public metric DISALLOW_COPY_AND_ASSIGN(closeable_metric); }; +// prometheus::Gauge // A gauge is a metric that represents a single numerical value that can arbitrarily go up and // down. Usually there are 2 scenarios for a guage. // @@ -1075,6 +1110,7 @@ class gauge : public metric writer.EndObject(); } + void take_snapshot(prometheus::Gauge *gauge) override { gauge->Set(value()); } void set(const value_type &val) { _value.store(val, std::memory_order_relaxed); } @@ -1131,6 +1167,7 @@ using gauge_ptr = ref_ptr>; template using gauge_prototype = metric_prototype_with>; +// prometheus::Counter // A counter in essence is a 64-bit integer that increases monotonically. It should be noted that // the counter does not support to decrease. If decrease is needed, please consider to use the // gauge instead. @@ -1192,6 +1229,11 @@ class counter : public metric writer.EndObject(); } + void take_snapshot(prometheus::Counter *counter) override + { + counter->Reset(); + counter->Increment(value()); + } // NOTICE: x MUST be a non-negative integer. void increment_by(int64_t x) @@ -1313,6 +1355,7 @@ inline size_t kth_percentile_to_nth_index(size_t size, kth_percentile_type type) return kth_percentile_to_nth_index(size, static_cast(type)); } +// prometheus::Summary // The percentile is a metric type that samples observations. The size of samples has an upper // bound. Once the maximum size is reached, the earliest observations will be overwritten. // @@ -1386,6 +1429,16 @@ class percentile : public closeable_metric writer.EndObject(); } + void take_snapshot(prometheus::Summary *summary, const metric_filters &filters) override + { + for (size_t i = 0; i < static_cast(kth_percentile_type::COUNT); ++i) { + if (!_kth_percentile_bitset.test(i)) { + continue; + } + + // encode(family, kAllKthPercentiles[i].name, value(i), filters); + } + } bool timer_enabled() const { return !!_timer; } diff --git a/src/utils/test/CMakeLists.txt b/src/utils/test/CMakeLists.txt index 8502cabb76..c420368caf 100644 --- a/src/utils/test/CMakeLists.txt +++ b/src/utils/test/CMakeLists.txt @@ -38,7 +38,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/utils/test/nth_element_bench/CMakeLists.txt b/src/utils/test/nth_element_bench/CMakeLists.txt index 3aae31e4a6..9b3835247c 100644 --- a/src/utils/test/nth_element_bench/CMakeLists.txt +++ b/src/utils/test/nth_element_bench/CMakeLists.txt @@ -33,7 +33,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/src/zookeeper/test/CMakeLists.txt b/src/zookeeper/test/CMakeLists.txt index 7dabd1faf5..77264b523a 100644 --- a/src/zookeeper/test/CMakeLists.txt +++ b/src/zookeeper/test/CMakeLists.txt @@ -42,7 +42,9 @@ set(MY_PROJ_LIBS rocksdb lz4 zstd - snappy) + snappy + prometheus-cpp-core + prometheus-cpp-pull) set(MY_BOOST_LIBS Boost::system Boost::filesystem) diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 26a8ae0893..64b257d3b9 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -282,6 +282,7 @@ ExternalProject_Add(prometheus-cpp URL_MD5 cdb515e802aa9aaaf1f6dde1271a20a2 DEPENDS curl CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${TP_OUTPUT} + -DBUILD_SHARED_LIBS=ON -DENABLE_TESTING=OFF -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}