mirror of
https://github.com/ceph/ceph
synced 2025-03-11 02:39:05 +00:00
Merge pull request #48657 from alimaredia/wip-rgw-labeled-perf-counters-cache
Labeled Perf Counters Reviewed-by: Casey Bodley <cbodley@redhat.com> Reviewed-by: Ilya Dryomov <idryomov@gmail.com>
This commit is contained in:
commit
b487144ae5
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -84,6 +84,7 @@ set(common_srcs
|
||||
page.cc
|
||||
perf_counters.cc
|
||||
perf_counters_collection.cc
|
||||
perf_counters_key.cc
|
||||
perf_histogram.cc
|
||||
pick_address.cc
|
||||
random_string.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 <name>: perf reset all or one perfcounter name");
|
||||
_admin_socket->register_command("config show", _admin_hook, "dump current config settings");
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
224
src/common/perf_counters_key.cc
Normal file
224
src/common/perf_counters_key.cc
Normal file
@ -0,0 +1,224 @@
|
||||
#include "common/perf_counters_key.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
||||
namespace ceph::perf_counters {
|
||||
namespace detail {
|
||||
|
||||
// use a null character to delimit strings
|
||||
constexpr char DELIMITER = '\0';
|
||||
|
||||
|
||||
// write a delimited string to the output
|
||||
auto write(std::string_view str, std::output_iterator<char> auto out)
|
||||
{
|
||||
out = std::copy(str.begin(), str.end(), out);
|
||||
*(out++) = DELIMITER;
|
||||
return out;
|
||||
}
|
||||
|
||||
// return the encoded size of a label
|
||||
inline std::size_t label_size(const label_pair& l)
|
||||
{
|
||||
return l.first.size() + sizeof(DELIMITER)
|
||||
+ l.second.size() + sizeof(DELIMITER);
|
||||
}
|
||||
|
||||
// an output iterator that writes label_pairs to a flat buffer
|
||||
template <std::contiguous_iterator Iterator>
|
||||
class label_insert_iterator {
|
||||
using base_iterator = Iterator;
|
||||
|
||||
struct label_writer {
|
||||
base_iterator pos; // write position
|
||||
|
||||
label_writer& operator=(const label_pair& l) {
|
||||
pos = write(l.first, pos);
|
||||
pos = write(l.second, pos);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
label_writer label;
|
||||
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = label_writer;
|
||||
using reference = value_type&;
|
||||
|
||||
label_insert_iterator() = default;
|
||||
label_insert_iterator(base_iterator begin) : label{begin} {
|
||||
static_assert(std::output_iterator<label_insert_iterator, label_pair>);
|
||||
}
|
||||
|
||||
// increments are noops
|
||||
label_insert_iterator& operator++() { return *this; }
|
||||
label_insert_iterator operator++(int) { return *this; }
|
||||
|
||||
// can only dereference to assign
|
||||
reference operator*() { return label; }
|
||||
|
||||
// return the wrapped iterator position
|
||||
base_iterator base() { return label.pos; }
|
||||
};
|
||||
|
||||
// compare label_pairs by their key only
|
||||
bool label_key_less(const label_pair& lhs, const label_pair& rhs)
|
||||
{
|
||||
return lhs.first < rhs.first;
|
||||
}
|
||||
bool label_key_equal(const label_pair& lhs, const label_pair& rhs)
|
||||
{
|
||||
return lhs.first == rhs.first;
|
||||
}
|
||||
|
||||
std::string create(std::string_view counter_name,
|
||||
label_pair* begin, label_pair* end)
|
||||
{
|
||||
// sort the input labels and remove duplicate keys
|
||||
std::sort(begin, end, label_key_less);
|
||||
end = std::unique(begin, end, label_key_equal);
|
||||
|
||||
// calculate the total size and preallocate the buffer
|
||||
auto size = std::accumulate(begin, end,
|
||||
counter_name.size() + sizeof(DELIMITER),
|
||||
[] (std::size_t sum, const label_pair& l) {
|
||||
return sum + label_size(l);
|
||||
});
|
||||
std::string result;
|
||||
result.resize(size);
|
||||
|
||||
// copy out the counter name and labels
|
||||
auto out = result.begin();
|
||||
out = write(counter_name, out);
|
||||
std::copy(begin, end, label_insert_iterator{out});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string insert(const char* begin1, const char* end1,
|
||||
label_pair* begin2, label_pair* end2)
|
||||
{
|
||||
// sort the input labels and remove duplicate keys
|
||||
std::sort(begin2, end2, label_key_less);
|
||||
end2 = std::unique(begin2, end2, label_key_equal);
|
||||
|
||||
// find the first delimiter that marks the end of the counter name
|
||||
auto pos = std::find(begin1, end1, DELIMITER);
|
||||
|
||||
// calculate the total size and preallocate the buffer
|
||||
auto size = std::distance(begin1, end1);
|
||||
if (pos == end1) { // add a delimiter if the key doesn't have one
|
||||
size += sizeof(DELIMITER);
|
||||
}
|
||||
size = std::accumulate(begin2, end2, size,
|
||||
[] (std::size_t sum, const label_pair& l) {
|
||||
return sum + label_size(l);
|
||||
});
|
||||
std::string result;
|
||||
result.resize(size);
|
||||
|
||||
// copy the counter name without the delimiter
|
||||
auto out = std::copy(begin1, pos, result.begin());
|
||||
if (pos != end1) {
|
||||
++pos; // advance past the delimiter
|
||||
}
|
||||
*(out++) = DELIMITER;
|
||||
|
||||
// merge the two sorted input ranges, drop any duplicate keys, and write
|
||||
// them to output. the begin2 range is first so that new input labels can
|
||||
// replace existing duplicates
|
||||
auto end = std::set_union(begin2, end2,
|
||||
label_iterator{pos, end1},
|
||||
label_iterator{end1, end1},
|
||||
label_insert_iterator{out},
|
||||
label_key_less);
|
||||
// fix up the size in case set_union() removed any duplicates
|
||||
result.resize(std::distance(result.begin(), end.base()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string_view name(const char* begin, const char* end)
|
||||
{
|
||||
auto pos = std::find(begin, end, DELIMITER);
|
||||
return {begin, pos};
|
||||
}
|
||||
|
||||
std::string_view labels(const char* begin, const char* end)
|
||||
{
|
||||
auto pos = std::find(begin, end, DELIMITER);
|
||||
if (pos == end) {
|
||||
return {};
|
||||
}
|
||||
return {std::next(pos), end};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
std::string key_create(std::string_view counter_name)
|
||||
{
|
||||
label_pair* end = nullptr;
|
||||
return detail::create(counter_name, end, end);
|
||||
}
|
||||
|
||||
std::string_view key_name(std::string_view key)
|
||||
{
|
||||
return detail::name(key.begin(), key.end());
|
||||
}
|
||||
|
||||
label_range key_labels(std::string_view key)
|
||||
{
|
||||
return detail::labels(key.begin(), key.end());
|
||||
}
|
||||
|
||||
|
||||
label_iterator::label_iterator(base_iterator begin, base_iterator end)
|
||||
: state(make_state(begin, end))
|
||||
{
|
||||
static_assert(std::forward_iterator<label_iterator>);
|
||||
}
|
||||
|
||||
void label_iterator::advance(std::optional<iterator_state>& s)
|
||||
{
|
||||
auto d = std::find(s->pos, s->end, detail::DELIMITER);
|
||||
if (d == s->end) { // no delimiter for label key
|
||||
s = std::nullopt;
|
||||
return;
|
||||
}
|
||||
s->label.first = std::string_view{s->pos, d};
|
||||
s->pos = std::next(d);
|
||||
|
||||
d = std::find(s->pos, s->end, detail::DELIMITER);
|
||||
if (d == s->end) { // no delimiter for label name
|
||||
s = std::nullopt;
|
||||
return;
|
||||
}
|
||||
s->label.second = std::string_view{s->pos, d};
|
||||
s->pos = std::next(d);
|
||||
}
|
||||
|
||||
auto label_iterator::make_state(base_iterator begin, base_iterator end)
|
||||
-> std::optional<iterator_state>
|
||||
{
|
||||
std::optional state = iterator_state{begin, end};
|
||||
advance(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
label_iterator& label_iterator::operator++()
|
||||
{
|
||||
advance(state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
label_iterator label_iterator::operator++(int)
|
||||
{
|
||||
label_iterator tmp = *this;
|
||||
advance(state);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
} // namespace ceph::perf_counters
|
139
src/common/perf_counters_key.h
Normal file
139
src/common/perf_counters_key.h
Normal file
@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ceph::perf_counters {
|
||||
|
||||
/// A key/value pair representing a perf counter label
|
||||
using label_pair = std::pair<std::string_view, std::string_view>;
|
||||
|
||||
|
||||
/// \brief Construct a key for a perf counter and set of labels.
|
||||
///
|
||||
/// Returns a string of the form "counter_name\0key1\0val1\0key2\0val2\0",
|
||||
/// where label pairs are sorted by key with duplicates removed.
|
||||
///
|
||||
/// This string representation avoids extra memory allocations associated
|
||||
/// with map<string, string>. It also supports the hashing and comparison
|
||||
/// operators required for use as a key in unordered and ordered containers.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// std::string key = key_create("counter_name", {
|
||||
/// {"key1", "val1"}, {"key2", "val2"}
|
||||
/// });
|
||||
/// \endcode
|
||||
template <std::size_t Count>
|
||||
std::string key_create(std::string_view counter_name,
|
||||
label_pair (&&labels)[Count]);
|
||||
|
||||
/// \brief Construct a key for a perf counter without labels.
|
||||
/// \overload
|
||||
std::string key_create(std::string_view counter_name);
|
||||
|
||||
/// \brief Insert additional labels into an existing key.
|
||||
///
|
||||
/// This returns a new string without modifying the input. The returned
|
||||
/// string has labels in sorted order and no duplicate keys.
|
||||
template <std::size_t Count>
|
||||
std::string key_insert(std::string_view key,
|
||||
label_pair (&&labels)[Count]);
|
||||
|
||||
/// \brief Return the counter name for a given key.
|
||||
std::string_view key_name(std::string_view key);
|
||||
|
||||
|
||||
/// A forward iterator over label_pairs encoded in a key
|
||||
class label_iterator {
|
||||
public:
|
||||
using base_iterator = const char*;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = label_pair;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
|
||||
label_iterator() = default;
|
||||
label_iterator(base_iterator begin, base_iterator end);
|
||||
|
||||
label_iterator& operator++();
|
||||
label_iterator operator++(int);
|
||||
|
||||
reference operator*() const { return state->label; }
|
||||
pointer operator->() const { return &state->label; }
|
||||
|
||||
auto operator<=>(const label_iterator& rhs) const = default;
|
||||
|
||||
private:
|
||||
struct iterator_state {
|
||||
base_iterator pos; // end of current label
|
||||
base_iterator end; // end of buffer
|
||||
label_pair label; // current label
|
||||
|
||||
auto operator<=>(const iterator_state& rhs) const = default;
|
||||
};
|
||||
// an empty state represents a past-the-end iterator
|
||||
std::optional<iterator_state> state;
|
||||
|
||||
// find the next two delimiters and construct the label string views
|
||||
static void advance(std::optional<iterator_state>& s);
|
||||
|
||||
// try to parse the first label pair
|
||||
static auto make_state(base_iterator begin, base_iterator end)
|
||||
-> std::optional<iterator_state>;
|
||||
};
|
||||
|
||||
/// A sorted range of label_pairs
|
||||
class label_range {
|
||||
std::string_view buffer;
|
||||
public:
|
||||
using iterator = label_iterator;
|
||||
using const_iterator = label_iterator;
|
||||
|
||||
label_range(std::string_view buffer) : buffer(buffer) {}
|
||||
|
||||
const_iterator begin() const { return {buffer.begin(), buffer.end()}; }
|
||||
const_iterator cbegin() const { return {buffer.begin(), buffer.end()}; }
|
||||
|
||||
const_iterator end() const { return {}; }
|
||||
const_iterator cend() const { return {}; }
|
||||
};
|
||||
|
||||
/// \brief Return the sorted range of label_pairs for a given key.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// for (label_pair label : key_labels(key)) {
|
||||
/// std::cout << label.first << ":" << label.second << std::endl;
|
||||
/// }
|
||||
/// \endcode
|
||||
label_range key_labels(std::string_view key);
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
std::string create(std::string_view counter_name,
|
||||
label_pair* begin, label_pair* end);
|
||||
|
||||
std::string insert(const char* begin1, const char* end1,
|
||||
label_pair* begin2, label_pair* end2);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <std::size_t Count>
|
||||
std::string key_create(std::string_view counter_name,
|
||||
label_pair (&&labels)[Count])
|
||||
{
|
||||
return detail::create(counter_name, std::begin(labels), std::end(labels));
|
||||
}
|
||||
|
||||
template <std::size_t Count>
|
||||
std::string key_insert(std::string_view key,
|
||||
label_pair (&&labels)[Count])
|
||||
{
|
||||
return detail::insert(key.begin(), key.end(),
|
||||
std::begin(labels), std::end(labels));
|
||||
}
|
||||
|
||||
} // namespace ceph::perf_counters
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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 = "");
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
2
src/librbd/cache/pwl/AbstractWriteLog.cc
vendored
2
src/librbd/cache/pwl/AbstractWriteLog.cc
vendored
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -294,6 +294,11 @@ add_executable(unittest_perf_histogram
|
||||
add_ceph_unittest(unittest_perf_histogram)
|
||||
target_link_libraries(unittest_perf_histogram ceph-common)
|
||||
|
||||
# unittest_perf_cache_key
|
||||
add_executable(unittest_perf_counters_key test_perf_counters_key.cc)
|
||||
add_ceph_unittest(unittest_perf_counters_key)
|
||||
target_link_libraries(unittest_perf_counters_key ceph-common)
|
||||
|
||||
# unittest_global_doublefree
|
||||
if(WITH_CEPHFS)
|
||||
add_executable(unittest_global_doublefree
|
||||
|
129
src/test/common/test_perf_counters_key.cc
Normal file
129
src/test/common/test_perf_counters_key.cc
Normal file
@ -0,0 +1,129 @@
|
||||
#include "common/perf_counters_key.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace ceph::perf_counters {
|
||||
|
||||
TEST(PerfCounters, key_create)
|
||||
{
|
||||
EXPECT_EQ(key_create(""),
|
||||
std::string_view("\0", 1));
|
||||
|
||||
EXPECT_EQ(key_create("perf"),
|
||||
std::string_view("perf\0", 5));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"",""}}),
|
||||
std::string_view("perf\0\0\0", 7));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"","a"}, {"",""}}),
|
||||
std::string_view("perf\0\0a\0", 8));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"a","b"}}),
|
||||
std::string_view("perf\0a\0b\0", 9));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"y","z"}, {"a","b"}}),
|
||||
std::string_view("perf\0a\0b\0y\0z\0", 13));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"a","b"}, {"a","c"}}),
|
||||
std::string_view("perf\0a\0b\0", 9));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"a","z"}, {"a","b"}}),
|
||||
std::string_view("perf\0a\0z\0", 9));
|
||||
|
||||
EXPECT_EQ(key_create("perf", {{"d",""}, {"c",""}, {"b",""}, {"a",""}}),
|
||||
std::string_view("perf\0a\0\0b\0\0c\0\0d\0\0", 17));
|
||||
}
|
||||
|
||||
TEST(PerfCounters, key_insert)
|
||||
{
|
||||
EXPECT_EQ(key_insert("", {{"",""}}),
|
||||
std::string_view("\0\0\0", 3));
|
||||
|
||||
EXPECT_EQ(key_insert("", {{"",""}, {"",""}}),
|
||||
std::string_view("\0\0\0", 3));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"\0\0\0", 3}, {{"",""}}),
|
||||
std::string_view("\0\0\0", 3));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"\0", 1}, {{"",""}}),
|
||||
std::string_view("\0\0\0", 3));
|
||||
|
||||
EXPECT_EQ(key_insert("", {{"a","b"}}),
|
||||
std::string_view("\0a\0b\0", 5));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"\0", 1}, {{"a","b"}}),
|
||||
std::string_view("\0a\0b\0", 5));
|
||||
|
||||
EXPECT_EQ(key_insert("a", {{"",""}}),
|
||||
std::string_view("a\0\0\0", 4));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"a\0", 2}, {{"",""}}),
|
||||
std::string_view("a\0\0\0", 4));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"p\0", 2}, {{"a","b"}}),
|
||||
std::string_view("p\0a\0b\0", 6));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"p\0a\0a\0", 6}, {{"a","b"}}),
|
||||
std::string_view("p\0a\0b\0", 6));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"p\0a\0z\0", 6}, {{"a","b"}}),
|
||||
std::string_view("p\0a\0b\0", 6));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"p\0z\0z\0", 6}, {{"a","b"}}),
|
||||
std::string_view("p\0a\0b\0z\0z\0", 10));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"p\0b\0b\0", 6},
|
||||
{{"a","a"}, {"c","c"}}),
|
||||
std::string_view("p\0a\0a\0b\0b\0c\0c\0", 14));
|
||||
|
||||
EXPECT_EQ(key_insert(std::string_view{"p\0a\0a\0b\0b\0c\0c\0", 14},
|
||||
{{"z","z"}, {"b","z"}}),
|
||||
std::string_view("p\0a\0a\0b\0z\0c\0c\0z\0z\0", 18));
|
||||
}
|
||||
|
||||
TEST(PerfCounters, key_name)
|
||||
{
|
||||
EXPECT_EQ(key_name(""),
|
||||
"");
|
||||
EXPECT_EQ(key_name({"\0", 1}),
|
||||
"");
|
||||
EXPECT_EQ(key_name({"perf\0", 5}),
|
||||
"perf");
|
||||
EXPECT_EQ(key_name({"perf\0\0\0", 7}),
|
||||
"perf");
|
||||
}
|
||||
|
||||
TEST(PerfCounters, key_labels)
|
||||
{
|
||||
{
|
||||
auto labels = key_labels("");
|
||||
EXPECT_EQ(labels.begin(), labels.end());
|
||||
}
|
||||
{
|
||||
auto labels = key_labels({"\0", 1});
|
||||
EXPECT_EQ(labels.begin(), labels.end());
|
||||
}
|
||||
{
|
||||
auto labels = key_labels({"perf\0", 5});
|
||||
EXPECT_EQ(labels.begin(), labels.end());
|
||||
}
|
||||
{
|
||||
auto labels = key_labels({"\0\0\0", 3});
|
||||
ASSERT_EQ(1, std::distance(labels.begin(), labels.end()));
|
||||
EXPECT_EQ(label_pair("", ""), *labels.begin());
|
||||
}
|
||||
{
|
||||
auto labels = key_labels({"\0a\0b\0", 5});
|
||||
ASSERT_EQ(1, std::distance(labels.begin(), labels.end()));
|
||||
EXPECT_EQ(label_pair("a", "b"), *labels.begin());
|
||||
EXPECT_EQ(std::next(labels.begin()), labels.end());
|
||||
}
|
||||
{
|
||||
auto labels = key_labels({"\0a\0b\0c\0d\0", 9});
|
||||
ASSERT_EQ(2, std::distance(labels.begin(), labels.end()));
|
||||
EXPECT_EQ(label_pair("a", "b"), *labels.begin());
|
||||
EXPECT_EQ(label_pair("c", "d"), *std::next(labels.begin()));
|
||||
EXPECT_EQ(std::next(labels.begin(), 2), labels.end());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ceph::perf_counters
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user