]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: Add labeled perf counters 48657/head
authorAli Maredia <amaredia@redhat.com>
Tue, 19 Jul 2022 21:39:02 +0000 (17:39 -0400)
committerAli Maredia <amaredia@redhat.com>
Thu, 23 Feb 2023 17:05:36 +0000 (12:05 -0500)
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 <amaredia@redhat.com>
21 files changed:
PendingReleaseNotes
doc/dev/perf_counters.rst
src/common/ceph_context.cc
src/common/perf_counters.cc
src/common/perf_counters.h
src/common/perf_counters_collection.cc
src/common/perf_counters_collection.h
src/crimson/CMakeLists.txt
src/crimson/admin/osd_admin.cc
src/crimson/common/perf_counters_collection.cc
src/crimson/common/perf_counters_collection.h
src/kv/RocksDBStore.cc
src/libcephsqlite.cc
src/librbd/cache/pwl/AbstractWriteLog.cc
src/os/bluestore/BlueFS.cc
src/os/bluestore/BlueStore.h
src/os/kstore/KStore.h
src/test/fio/fio_ceph_messenger.cc
src/test/fio/fio_ceph_objectstore.cc
src/test/perf_counters.cc
src/tools/ceph_objectstore_tool.cc

index 97e47148abb82a8a550ef2e0819f4b691946c6c2..386f792bf5756f208ac28f1f6ca5684fc4588b74 100644 (file)
   `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
 
index 747b4680bb73d43dcb00e1efdc6f2a9c35ea2ac9..b71939282eb5557865dba71836f206e437c2eccc 100644 (file)
@@ -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.
index fe71ea4ccc49e8569851c0dda9d1061608df4b30..d26f24511d22e22062f224beb9fb133c486ca3de 100644 (file)
@@ -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 <name>: perf reset all or one perfcounter name");
   _admin_socket->register_command("config show", _admin_hook, "dump current config settings");
index 420ff928c06cad1ed37c029a2c343a1ebe26e65b..134c8efe78984f2a3cb5ec8af642c5a9e1475b3d 100644 (file)
@@ -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();
 }
 
index c5f69aa7ce31abcb911c86d29f586f951f79faf3..942edf6d7e544ec61aea820676da9216ef1b60bd 100644 (file)
@@ -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<uint64_t, uint64_t> 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_any_d> 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;
 
index d9af8a945bbe0738890d3ae183bd63aa5e17ccc6..f03980eba2d48bc3d14a6869d7a3fa60de429572 100644 (file)
@@ -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,
index e4bd2cda3b0f1c25a741ccb7bccecb458bc3fa4c..4608a8243dba3666b04e4794337b62657c3338d3 100644 (file)
@@ -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,
index 68e1b64beb9db2deb083e22b18ab1d69684a5ac5..563c20921bdff72a38871183f12d74e611cae307 100644 (file)
@@ -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
index 2bcfb39922f8e70f1b8135e25ec142798b07705c..0436e5184df8c20624949c10898e9e49aca4bb25 100644 (file)
@@ -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<tell_result_t>(std::move(f));
   }
 };
index 08501395e7e366cec92eb34c6e61d35c2d54d7ea..254d85278f648fe05f12682c73027cb30cd8ee57 100644 (file)
@@ -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;
index fac33bce7ee9f4de5a5065c76c47d9f04fe391a5..ae0c8670cb7d5c100c542aabe709c0303e88b0cd 100644 (file)
@@ -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 = "");
 };
index a3ecf3a5a1f7dc0806dccccf1c2cf7c53ee12ed5..dfac6575c13ae2a180df160b005d414a72097977 100644 (file)
@@ -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) {
index eafadcd8922bd7f70a796d4385c47d4b890082d6..f533780c548bd99bda9555b8902c995872a1f3cb 100644 (file)
@@ -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;
index a59a59d1ca03d7d90a767eb9fbcc2eb1fcd37b72..1e784f6b56696c8093aa4995acb92d1091591a66 100644 (file)
@@ -301,7 +301,7 @@ void AbstractWriteLog<I>::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);
index 274ab0a5c9da2d259172ea5bd3040084c309bd6a..fc0e906e9c2730e79a8e0dd19c2a68f7beb67caf 100644 (file)
@@ -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();
 }
 
index 3fd970254036b0ed821a72fee0401980f32903d0..a0e8f324c0829480be43d379c2a71b8e7aca4180 100644 (file)
@@ -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();
   }
 
index d7d95acdfbde5bcdc8801ab899910eb7770a4c2e..9e3c7acd73b428880a6330445879436acd54325b 100644 (file)
@@ -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 {
index 8c962af5df72b92ccb9dd547767206238ae5d4b8..2e18c7c633035a3e3efd8102bf2eb3a24a1afd36 100644 (file)
@@ -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;
index fe9c793ab129f2cc14e8dcd0c9b633b118160a88..ade043f0cd166bad3f7ed02b42c5ae90be516e97 100644 (file)
@@ -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);
index a4dfe48d1e7b7a3418a6cc97fea7fafa4177034b..31b10fff1679ab7d3144d4f6f1f95c8f5a7844a1 100644 (file)
@@ -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();
+}
index 082a4119fcb556755a4aab69110891822e83c04b..01c8722b405a18c03bd5b532b3756e2181f40913 100644 (file)
@@ -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;