From 56e2a1006f975829c0f00db31c745f32da24676b Mon Sep 17 00:00:00 2001 From: Ali Maredia Date: Tue, 19 Jul 2022 17:39:02 -0400 Subject: [PATCH] common: Add labeled perf counters Add the ability to dump labeled perf counters for a daemon. Labeled perf counters are stored in a CephContext's PerfCountersCollection. Labeled and unlabeled perf counters are dumped to the admin socket via `counters dump` command. The schema for labeled and unlabeled perf counters are dumped to the admin socket via `counters schema` command. This commit includes docs and additional unit tests Signed-off-by: Ali Maredia --- PendingReleaseNotes | 6 + doc/dev/perf_counters.rst | 44 +++ src/common/ceph_context.cc | 16 +- src/common/perf_counters.cc | 32 +- src/common/perf_counters.h | 14 +- src/common/perf_counters_collection.cc | 3 +- src/common/perf_counters_collection.h | 2 +- src/crimson/CMakeLists.txt | 1 + src/crimson/admin/osd_admin.cc | 2 +- .../common/perf_counters_collection.cc | 3 +- src/crimson/common/perf_counters_collection.h | 2 +- src/kv/RocksDBStore.cc | 2 +- src/libcephsqlite.cc | 4 +- src/librbd/cache/pwl/AbstractWriteLog.cc | 2 +- src/os/bluestore/BlueFS.cc | 2 +- src/os/bluestore/BlueStore.h | 2 +- src/os/kstore/KStore.h | 2 +- src/test/fio/fio_ceph_messenger.cc | 2 +- src/test/fio/fio_ceph_objectstore.cc | 2 +- src/test/perf_counters.cc | 368 ++++++++++++++++++ src/tools/ceph_objectstore_tool.cc | 2 +- 21 files changed, 485 insertions(+), 28 deletions(-) diff --git a/PendingReleaseNotes b/PendingReleaseNotes index 97e47148abb82..386f792bf5756 100644 --- a/PendingReleaseNotes +++ b/PendingReleaseNotes @@ -104,6 +104,12 @@ `client_max_retries_on_remount_failure` and move it from mds.yaml.in to mds-client.yaml.in because this option was only used by MDS client from its birth. +* The `perf dump` and `perf schema` commands are deprecated in favor of new + `counter dump` and `counter schema` commands. These new commands add support + for labeled perf counters and also emit existing unlabeled perf counters. Some + unlabeled perf counters may become labeled in future releases + and as such will no longer be emitted by the `perf dump` and `perf schema` + commands. >=17.2.1 diff --git a/doc/dev/perf_counters.rst b/doc/dev/perf_counters.rst index 747b4680bb73d..b71939282eb55 100644 --- a/doc/dev/perf_counters.rst +++ b/doc/dev/perf_counters.rst @@ -200,3 +200,47 @@ The actual dump is similar to the schema, except that average values are grouped } } +Labeled Perf Counters +--------------------- + +A Ceph daemon has the ability to emit a set of perf counter instances with varying labels. These counters are intended for visualizing specific metrics in 3rd party tools like Prometheus and Grafana. + +For example, the below counters show the number of put requests for different users on different buckets:: + + { + "rgw": { + "labels": { + "Bucket: "bkt1", + "User: "user1", + }, + "counters": { + "put": 1, + }, + }, + "rgw": { + "labels": { + }, + "counters": { + "put": 4, + }, + }, + "rgw": { + "labels": { + "Bucket: "bkt1", + "User: "user2", + }, + "counters": { + "put": 3, + }, + } + } + +All labeled and unlabeled perf counters can be viewed with ``ceph daemon {daemon id} counter dump``. + +All labeled and unlabeled perf counter's schema can be viewed with ``ceph daemon {daemon id} counter schema``. + +In the above example the second counter without labels is a counter that would also be shown in ``ceph daemon {daemon id} perf dump``. + +Since the ``counter dump`` and ``counter schema`` commands can be used to view both types of counters it is not recommended to use the ``perf dump`` and ``perf schema`` commands which are retained for backwards compatibility and continue to emit only non-labeled counters. + +Some perf counters that are emitted via ``perf dump`` and ``perf schema`` may become labeled in future releases and as such will no longer be emitted by ``perf dump`` and ``perf schema`` respectively. diff --git a/src/common/ceph_context.cc b/src/common/ceph_context.cc index fe71ea4ccc49e..d26f24511d22e 100644 --- a/src/common/ceph_context.cc +++ b/src/common/ceph_context.cc @@ -538,11 +538,17 @@ int CephContext::_do_command( std::string counter; cmd_getval(cmdmap, "logger", logger); cmd_getval(cmdmap, "counter", counter); - _perf_counters_collection->dump_formatted(f, false, logger, counter); + _perf_counters_collection->dump_formatted(f, false, false, logger, counter); } else if (command == "perfcounters_schema" || command == "2" || command == "perf schema") { - _perf_counters_collection->dump_formatted(f, true); + _perf_counters_collection->dump_formatted(f, true, false); + } + else if (command == "counter dump") { + _perf_counters_collection->dump_formatted(f, false, true); + } + else if (command == "counter schema") { + _perf_counters_collection->dump_formatted(f, true, true); } else if (command == "perf histogram dump") { std::string logger; @@ -745,11 +751,13 @@ CephContext::CephContext(uint32_t module_type_, _admin_socket->register_command("leak_some_memory", _admin_hook, ""); _admin_socket->register_command("perfcounters_dump", _admin_hook, ""); _admin_socket->register_command("1", _admin_hook, ""); - _admin_socket->register_command("perf dump name=logger,type=CephString,req=false name=counter,type=CephString,req=false", _admin_hook, "dump perfcounters value"); + _admin_socket->register_command("perf dump name=logger,type=CephString,req=false name=counter,type=CephString,req=false", _admin_hook, "dump non-labeled counters and their values"); _admin_socket->register_command("perfcounters_schema", _admin_hook, ""); _admin_socket->register_command("perf histogram dump name=logger,type=CephString,req=false name=counter,type=CephString,req=false", _admin_hook, "dump perf histogram values"); _admin_socket->register_command("2", _admin_hook, ""); - _admin_socket->register_command("perf schema", _admin_hook, "dump perfcounters schema"); + _admin_socket->register_command("perf schema", _admin_hook, "dump non-labeled counters schemas"); + _admin_socket->register_command("counter dump", _admin_hook, "dump all labeled and non-labeled counters and their values"); + _admin_socket->register_command("counter schema", _admin_hook, "dump all labeled and non-labeled counters schemas"); _admin_socket->register_command("perf histogram schema", _admin_hook, "dump perf histogram schema"); _admin_socket->register_command("perf reset name=var,type=CephString", _admin_hook, "perf reset : perf reset all or one perfcounter name"); _admin_socket->register_command("config show", _admin_hook, "dump current config settings"); diff --git a/src/common/perf_counters.cc b/src/common/perf_counters.cc index 420ff928c06ca..134c8efe78984 100644 --- a/src/common/perf_counters.cc +++ b/src/common/perf_counters.cc @@ -14,6 +14,7 @@ */ #include "common/perf_counters.h" +#include "common/perf_counters_key.h" #include "common/dout.h" #include "common/valgrind.h" #include "include/common_fwd.h" @@ -129,6 +130,7 @@ void PerfCountersCollectionImpl::dump_formatted_generic( Formatter *f, bool schema, bool histograms, + bool dump_labeled, const std::string &logger, const std::string &counter) const { @@ -138,7 +140,7 @@ void PerfCountersCollectionImpl::dump_formatted_generic( l != m_loggers.end(); ++l) { // Optionally filter on logger name, pass through counter filter if (logger.empty() || (*l)->get_name() == logger) { - (*l)->dump_formatted_generic(f, schema, histograms, counter); + (*l)->dump_formatted_generic(f, schema, histograms, dump_labeled, counter); } } f->close_section(); @@ -354,9 +356,30 @@ void PerfCounters::reset() } void PerfCounters::dump_formatted_generic(Formatter *f, bool schema, - bool histograms, const std::string &counter) const + bool histograms, bool dump_labeled, const std::string &counter) const { - f->open_object_section(m_name.c_str()); + if (dump_labeled) { + std::string_view perf_counter_name = ceph::perf_counters::key_name(m_name); + f->open_object_section(perf_counter_name); + + f->open_object_section("labels"); + for (auto label : ceph::perf_counters::key_labels(m_name)) { + // don't dump labels with empty label names + if (!label.first.empty()) { + f->dump_string(label.first, label.second); + } + } + f->close_section(); // labels + f->open_object_section("counters"); + } else { + auto labels = ceph::perf_counters::key_labels(m_name); + // do not dump counters when counter instance is labeled and dump_labeled is not set + if (labels.begin() != labels.end()) { + return; + } + + f->open_object_section(m_name.c_str()); + } for (perf_counter_data_vec_t::const_iterator d = m_data.begin(); d != m_data.end(); ++d) { @@ -464,6 +487,9 @@ void PerfCounters::dump_formatted_generic(Formatter *f, bool schema, } } } + if (dump_labeled) { + f->close_section(); // counters + } f->close_section(); } diff --git a/src/common/perf_counters.h b/src/common/perf_counters.h index c5f69aa7ce31a..942edf6d7e544 100644 --- a/src/common/perf_counters.h +++ b/src/common/perf_counters.h @@ -246,13 +246,13 @@ public: void hinc(int idx, int64_t x, int64_t y); void reset(); - void dump_formatted(ceph::Formatter *f, bool schema, + void dump_formatted(ceph::Formatter *f, bool schema, bool dump_labeled, const std::string &counter = "") const { - dump_formatted_generic(f, schema, false, counter); + dump_formatted_generic(f, schema, false, dump_labeled, counter); } void dump_formatted_histograms(ceph::Formatter *f, bool schema, const std::string &counter = "") const { - dump_formatted_generic(f, schema, true, counter); + dump_formatted_generic(f, schema, true, false, counter); } std::pair get_tavg_ns(int idx) const; @@ -278,6 +278,7 @@ private: PerfCounters(const PerfCounters &rhs); PerfCounters& operator=(const PerfCounters &rhs); void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms, + bool dump_labeled, const std::string &counter = "") const; typedef std::vector perf_counter_data_vec_t; @@ -323,16 +324,16 @@ public: void clear(); bool reset(const std::string &name); - void dump_formatted(ceph::Formatter *f, bool schema, + void dump_formatted(ceph::Formatter *f, bool schema, bool dump_labeled, const std::string &logger = "", const std::string &counter = "") const { - dump_formatted_generic(f, schema, false, logger, counter); + dump_formatted_generic(f, schema, false, dump_labeled, logger, counter); } void dump_formatted_histograms(ceph::Formatter *f, bool schema, const std::string &logger = "", const std::string &counter = "") const { - dump_formatted_generic(f, schema, true, logger, counter); + dump_formatted_generic(f, schema, true, false, logger, counter); } // A reference to a perf_counter_data_any_d, with an accompanying @@ -351,6 +352,7 @@ public: private: void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms, + bool dump_labeled, const std::string &logger = "", const std::string &counter = "") const; diff --git a/src/common/perf_counters_collection.cc b/src/common/perf_counters_collection.cc index d9af8a945bbe0..f03980eba2d48 100644 --- a/src/common/perf_counters_collection.cc +++ b/src/common/perf_counters_collection.cc @@ -34,11 +34,12 @@ bool PerfCountersCollection::reset(const std::string &name) return perf_impl.reset(name); } void PerfCountersCollection::dump_formatted(ceph::Formatter *f, bool schema, + bool dump_labeled, const std::string &logger, const std::string &counter) { std::lock_guard lck(m_lock); - perf_impl.dump_formatted(f,schema,logger,counter); + perf_impl.dump_formatted(f, schema, dump_labeled, logger, counter); } void PerfCountersCollection::dump_formatted_histograms(ceph::Formatter *f, bool schema, const std::string &logger, diff --git a/src/common/perf_counters_collection.h b/src/common/perf_counters_collection.h index e4bd2cda3b0f1..4608a8243dba3 100644 --- a/src/common/perf_counters_collection.h +++ b/src/common/perf_counters_collection.h @@ -20,7 +20,7 @@ public: void clear(); bool reset(const std::string &name); - void dump_formatted(ceph::Formatter *f, bool schema, + void dump_formatted(ceph::Formatter *f, bool schema, bool dump_labeled, const std::string &logger = "", const std::string &counter = ""); void dump_formatted_histograms(ceph::Formatter *f, bool schema, diff --git a/src/crimson/CMakeLists.txt b/src/crimson/CMakeLists.txt index 68e1b64beb9db..563c20921bdff 100644 --- a/src/crimson/CMakeLists.txt +++ b/src/crimson/CMakeLists.txt @@ -63,6 +63,7 @@ add_library(crimson-common STATIC ${PROJECT_SOURCE_DIR}/src/common/mempool.cc ${PROJECT_SOURCE_DIR}/src/common/options.cc ${PROJECT_SOURCE_DIR}/src/common/perf_counters.cc + ${PROJECT_SOURCE_DIR}/src/common/perf_counters_key.cc ${PROJECT_SOURCE_DIR}/src/common/perf_histogram.cc ${PROJECT_SOURCE_DIR}/src/common/page.cc ${PROJECT_SOURCE_DIR}/src/common/pick_address.cc diff --git a/src/crimson/admin/osd_admin.cc b/src/crimson/admin/osd_admin.cc index 2bcfb39922f8e..0436e5184df8c 100644 --- a/src/crimson/admin/osd_admin.cc +++ b/src/crimson/admin/osd_admin.cc @@ -178,7 +178,7 @@ public: cmd_getval(cmdmap, "logger", logger); cmd_getval(cmdmap, "counter", counter); - crimson::common::local_perf_coll().dump_formatted(f.get(), false, logger, counter); + crimson::common::local_perf_coll().dump_formatted(f.get(), false, false, logger, counter); return seastar::make_ready_future(std::move(f)); } }; diff --git a/src/crimson/common/perf_counters_collection.cc b/src/crimson/common/perf_counters_collection.cc index 08501395e7e36..254d85278f648 100644 --- a/src/crimson/common/perf_counters_collection.cc +++ b/src/crimson/common/perf_counters_collection.cc @@ -20,10 +20,11 @@ PerfCountersCollectionImpl* PerfCountersCollection:: get_perf_collection() } void PerfCountersCollection::dump_formatted(ceph::Formatter *f, bool schema, + bool dump_labeled, const std::string &logger, const std::string &counter) { - perf_collection->dump_formatted(f, schema, logger, counter); + perf_collection->dump_formatted(f, schema, dump_labeled, logger, counter); } PerfCountersCollection::ShardedPerfCountersCollection PerfCountersCollection::sharded_perf_coll; diff --git a/src/crimson/common/perf_counters_collection.h b/src/crimson/common/perf_counters_collection.h index fac33bce7ee9f..ae0c8670cb7d5 100644 --- a/src/crimson/common/perf_counters_collection.h +++ b/src/crimson/common/perf_counters_collection.h @@ -23,7 +23,7 @@ public: PerfCountersCollection(); ~PerfCountersCollection(); PerfCountersCollectionImpl* get_perf_collection(); - void dump_formatted(ceph::Formatter *f, bool schema, + void dump_formatted(ceph::Formatter *f, bool schema, bool dump_labeled, const std::string &logger = "", const std::string &counter = ""); }; diff --git a/src/kv/RocksDBStore.cc b/src/kv/RocksDBStore.cc index a3ecf3a5a1f7d..dfac6575c13ae 100644 --- a/src/kv/RocksDBStore.cc +++ b/src/kv/RocksDBStore.cc @@ -1448,7 +1448,7 @@ void RocksDBStore::get_statistics(Formatter *f) f->close_section(); } f->open_object_section("rocksdbstore_perf_counters"); - logger->dump_formatted(f,0); + logger->dump_formatted(f, false, false); f->close_section(); } if (cct->_conf->rocksdb_collect_memory_stats) { diff --git a/src/libcephsqlite.cc b/src/libcephsqlite.cc index eafadcd8922bd..f533780c548bd 100644 --- a/src/libcephsqlite.cc +++ b/src/libcephsqlite.cc @@ -741,8 +741,8 @@ static void f_perf(sqlite3_context* ctx, int argc, sqlite3_value** argv) auto&& appd = getdata(vfs); JSONFormatter f(false); f.open_object_section("ceph_perf"); - appd.logger->dump_formatted(&f, false); - appd.striper_logger->dump_formatted(&f, false); + appd.logger->dump_formatted(&f, false, false); + appd.striper_logger->dump_formatted(&f, false, false); f.close_section(); { CachedStackStringStream css; diff --git a/src/librbd/cache/pwl/AbstractWriteLog.cc b/src/librbd/cache/pwl/AbstractWriteLog.cc index a59a59d1ca03d..1e784f6b56696 100644 --- a/src/librbd/cache/pwl/AbstractWriteLog.cc +++ b/src/librbd/cache/pwl/AbstractWriteLog.cc @@ -301,7 +301,7 @@ void AbstractWriteLog::log_perf() { ss << "\"image\": \"" << m_image_ctx.name << "\","; bl.append(ss); bl.append("\"stats\": "); - m_image_ctx.cct->get_perfcounters_collection()->dump_formatted(f, 0); + m_image_ctx.cct->get_perfcounters_collection()->dump_formatted(f, false, false); f->flush(bl); bl.append(",\n\"histograms\": "); m_image_ctx.cct->get_perfcounters_collection()->dump_formatted_histograms(f, 0); diff --git a/src/os/bluestore/BlueFS.cc b/src/os/bluestore/BlueFS.cc index 274ab0a5c9da2..fc0e906e9c273 100644 --- a/src/os/bluestore/BlueFS.cc +++ b/src/os/bluestore/BlueFS.cc @@ -533,7 +533,7 @@ uint64_t BlueFS::get_free(unsigned id) void BlueFS::dump_perf_counters(Formatter *f) { f->open_object_section("bluefs_perf_counters"); - logger->dump_formatted(f,0); + logger->dump_formatted(f, false, false); f->close_section(); } diff --git a/src/os/bluestore/BlueStore.h b/src/os/bluestore/BlueStore.h index 3fd970254036b..a0e8f324c0829 100644 --- a/src/os/bluestore/BlueStore.h +++ b/src/os/bluestore/BlueStore.h @@ -2969,7 +2969,7 @@ public: int flush_cache(std::ostream *os = NULL) override; void dump_perf_counters(ceph::Formatter *f) override { f->open_object_section("perf_counters"); - logger->dump_formatted(f, false); + logger->dump_formatted(f, false, false); f->close_section(); } diff --git a/src/os/kstore/KStore.h b/src/os/kstore/KStore.h index d7d95acdfbde5..9e3c7acd73b42 100644 --- a/src/os/kstore/KStore.h +++ b/src/os/kstore/KStore.h @@ -436,7 +436,7 @@ public: } void dump_perf_counters(ceph::Formatter *f) override { f->open_object_section("perf_counters"); - logger->dump_formatted(f, false); + logger->dump_formatted(f, false, false); f->close_section(); } void get_db_statistics(ceph::Formatter *f) override { diff --git a/src/test/fio/fio_ceph_messenger.cc b/src/test/fio/fio_ceph_messenger.cc index 8c962af5df72b..2e18c7c633035 100644 --- a/src/test/fio/fio_ceph_messenger.cc +++ b/src/test/fio/fio_ceph_messenger.cc @@ -132,7 +132,7 @@ static void put_ceph_context(void) Formatter* f; f = Formatter::create("json-pretty"); - g_ceph_context->get_perfcounters_collection()->dump_formatted(f, false); + g_ceph_context->get_perfcounters_collection()->dump_formatted(f, false, false); ostr << ">>>>>>>>>>>>> PERFCOUNTERS BEGIN <<<<<<<<<<<<" << std::endl; f->flush(ostr); ostr << ">>>>>>>>>>>>> PERFCOUNTERS END <<<<<<<<<<<<" << std::endl; diff --git a/src/test/fio/fio_ceph_objectstore.cc b/src/test/fio/fio_ceph_objectstore.cc index fe9c793ab129f..ade043f0cd166 100644 --- a/src/test/fio/fio_ceph_objectstore.cc +++ b/src/test/fio/fio_ceph_objectstore.cc @@ -338,7 +338,7 @@ struct Engine { Formatter* f = Formatter::create( "json-pretty", "json-pretty", "json-pretty"); f->open_object_section("perf_output"); - cct->get_perfcounters_collection()->dump_formatted(f, false); + cct->get_perfcounters_collection()->dump_formatted(f, false, false); if (g_conf()->rocksdb_perf) { f->open_object_section("rocksdb_perf"); os->get_db_statistics(f); diff --git a/src/test/perf_counters.cc b/src/test/perf_counters.cc index a4dfe48d1e7b7..31b10fff1679a 100644 --- a/src/test/perf_counters.cc +++ b/src/test/perf_counters.cc @@ -16,6 +16,7 @@ // now, this include has to come before the others. +#include "common/perf_counters_key.h" #include "common/perf_counters_collection.h" #include "common/admin_socket_client.h" #include "common/ceph_context.h" @@ -182,6 +183,7 @@ TEST(PerfCounters, MultiplePerfCounters) { "{\"avgcount\":0,\"sum\":0.000000000,\"avgtime\":0.000000000}},\"test_perfcounter_2\":{\"foo\":0,\"bar\":0.000000000}}"), msg); coll->remove(fake_pf2); + delete fake_pf2; ASSERT_EQ("", client.do_request("{ \"prefix\": \"perf dump\", \"format\": \"json\" }", &msg)); ASSERT_EQ(sd("{\"test_perfcounter_1\":{\"element1\":13,\"element2\":0.000000000," "\"element3\":{\"avgcount\":0,\"sum\":0.000000000,\"avgtime\":0.000000000}}}"), msg); @@ -255,3 +257,369 @@ TEST(PerfCounters, read_avg) { t2.join(); t1.join(); } + +static PerfCounters* setup_test_perfcounter4(std::string name, CephContext *cct) +{ + PerfCountersBuilder bld(cct, name, + TEST_PERFCOUNTERS2_ELEMENT_FIRST, TEST_PERFCOUNTERS2_ELEMENT_LAST); + bld.add_u64(TEST_PERFCOUNTERS2_ELEMENT_FOO, "foo"); + bld.add_time(TEST_PERFCOUNTERS2_ELEMENT_BAR, "bar"); + + PerfCounters* counters = bld.create_perf_counters(); + cct->get_perfcounters_collection()->add(counters); + return counters; +} + +TEST(PerfCounters, TestLabeledCountersOnly) { + constexpr std::string_view empty_dump_format_raw = R"({} +)"; + std::string counter_key1 = ceph::perf_counters::key_create("name1", {{"label1", "val1"}}); + std::string counter_key2 = ceph::perf_counters::key_create("name2", {{"label2", "val2"}}); + + PerfCounters* counters1 = setup_test_perfcounter4(counter_key1, g_ceph_context); + PerfCounters* counters2 = setup_test_perfcounter4(counter_key2, g_ceph_context); + + counters1->inc(TEST_PERFCOUNTERS2_ELEMENT_FOO, 3); + counters1->dec(TEST_PERFCOUNTERS2_ELEMENT_FOO, 1); + counters2->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 4); + + AdminSocketClient client(get_rand_socket_path()); + std::string message; + ASSERT_EQ("", client.do_request(R"({ "prefix": "counter dump", "format": "raw" })", &message)); + ASSERT_EQ(R"({ + "name1": { + "labels": { + "label1": "val1" + }, + "counters": { + "foo": 2, + "bar": 0.000000000 + } + }, + "name2": { + "labels": { + "label2": "val2" + }, + "counters": { + "foo": 4, + "bar": 0.000000000 + } + } +} +)", message); + + // make sure labeled counters are not in normal perf dump + ASSERT_EQ("", client.do_request(R"({ "prefix": "perf dump", "format": "raw" })", &message)); + ASSERT_EQ(empty_dump_format_raw, message); + + ASSERT_EQ("", client.do_request(R"({ "prefix": "counter schema", "format": "raw" })", &message)); + ASSERT_EQ(R"({ + "name1": { + "labels": { + "label1": "val1" + }, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + }, + "name2": { + "labels": { + "label2": "val2" + }, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + } +} +)", message); + + // make sure labeled counters are not in normal perf schema + ASSERT_EQ("", client.do_request(R"({ "prefix": "perf schema", "format": "raw" })", &message)); + ASSERT_EQ(empty_dump_format_raw, message); + + g_ceph_context->get_perfcounters_collection()->clear(); +} + +TEST(PerfCounters, TestLabelStrings) { + AdminSocketClient client(get_rand_socket_path()); + std::string message; + + // test empty val in a label pair will get the label pair added but empty key will not + std::string counter_key1 = ceph::perf_counters::key_create("good_ctrs", {{"label3", "val4"}, {"label1", ""}}); + PerfCounters* counters1 = setup_test_perfcounter4(counter_key1, g_ceph_context); + + std::string counter_key2 = ceph::perf_counters::key_create("bad_ctrs", {{"", "val4"}, {"label1", "val1"}}); + PerfCounters* counters2 = setup_test_perfcounter4(counter_key2, g_ceph_context); + + counters1->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 2); + counters2->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 4); + + // test empty keys in each of the label pairs will get only the labels section added + std::string counter_key3 = ceph::perf_counters::key_create("bad_ctrs2", {{"", "val2"}, {"", "val33"}}); + PerfCounters* counters3 = setup_test_perfcounter4(counter_key3, g_ceph_context); + counters3->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 6); + + // a key with a somehow odd number of entries after the the key name will omit final unfinished label pair + std::string counter_key4 = "too_many_delimiters"; + counter_key4 += '\0'; + counter_key4 += "label1"; + counter_key4 += '\0'; + counter_key4 += "val1"; + counter_key4 += '\0'; + counter_key4 += "label2"; + counter_key4 += '\0'; + PerfCounters* counters4 = setup_test_perfcounter4(counter_key4, g_ceph_context); + counters4->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 8); + + // test unlabeled perf counters are in the counter dump with labels and counters sections + std::string counter_key5 = "only_key"; + PerfCounters* no_label_counters = setup_test_perfcounter4(counter_key5, g_ceph_context); + no_label_counters->set(TEST_PERFCOUNTERS2_ELEMENT_FOO, 4); + + ASSERT_EQ("", client.do_request(R"({ "prefix": "counter dump", "format": "raw" })", &message)); + ASSERT_EQ(R"({ + "bad_ctrs": { + "labels": { + "label1": "val1" + }, + "counters": { + "foo": 4, + "bar": 0.000000000 + } + }, + "bad_ctrs2": { + "labels": {}, + "counters": { + "foo": 6, + "bar": 0.000000000 + } + }, + "good_ctrs": { + "labels": { + "label1": "", + "label3": "val4" + }, + "counters": { + "foo": 2, + "bar": 0.000000000 + } + }, + "only_key": { + "labels": {}, + "counters": { + "foo": 4, + "bar": 0.000000000 + } + }, + "too_many_delimiters": { + "labels": { + "label1": "val1" + }, + "counters": { + "foo": 8, + "bar": 0.000000000 + } + } +} +)", message); + + // test unlabeled perf counters are in the schema dump with labels and counters sections + ASSERT_EQ("", client.do_request(R"({ "prefix": "counter schema", "format": "raw" })", &message)); + ASSERT_EQ(R"({ + "bad_ctrs": { + "labels": { + "label1": "val1" + }, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + }, + "bad_ctrs2": { + "labels": {}, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + }, + "good_ctrs": { + "labels": { + "label1": "", + "label3": "val4" + }, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + }, + "only_key": { + "labels": {}, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + }, + "too_many_delimiters": { + "labels": { + "label1": "val1" + }, + "counters": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } + } +} +)", message); + + // test unlabeled perf counters are in the perf dump without the labels and counters section + ASSERT_EQ("", client.do_request(R"({ "prefix": "perf dump", "format": "raw" })", &message)); + ASSERT_EQ(R"({ + "only_key": { + "foo": 4, + "bar": 0.000000000 + } +} +)", message); + + // test unlabeled perf counters are in the perf schema without the labels and counters section + ASSERT_EQ("", client.do_request(R"({ "prefix": "perf schema", "format": "raw" })", &message)); + ASSERT_EQ(R"({ + "only_key": { + "foo": { + "type": 2, + "metric_type": "gauge", + "value_type": "integer", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + }, + "bar": { + "type": 1, + "metric_type": "gauge", + "value_type": "real", + "description": "", + "nick": "", + "priority": 0, + "units": "none" + } + } +} +)", message); + + g_ceph_context->get_perfcounters_collection()->clear(); +} diff --git a/src/tools/ceph_objectstore_tool.cc b/src/tools/ceph_objectstore_tool.cc index 082a4119fcb55..01c8722b405a1 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -4523,7 +4523,7 @@ out: if (debug) { ostringstream ostr; Formatter* f = Formatter::create("json-pretty", "json-pretty", "json-pretty"); - cct->get_perfcounters_collection()->dump_formatted(f, false); + cct->get_perfcounters_collection()->dump_formatted(f, false, false); ostr << "ceph-objectstore-tool "; f->flush(ostr); delete f; -- 2.39.5