mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 15:33:54 +01:00
ircd::stats: Refactor subsystem template hierarchy and approach. (#31)
This commit is contained in:
parent
e2654ddaed
commit
c0d2fe20bb
3 changed files with 366 additions and 134 deletions
|
@ -48,10 +48,10 @@ struct ircd::net::socket
|
|||
|
||||
static uint64_t count; // monotonic
|
||||
static uint64_t instances; // current socket count
|
||||
static stats::item total_bytes_in;
|
||||
static stats::item total_bytes_out;
|
||||
static stats::item total_calls_in;
|
||||
static stats::item total_calls_out;
|
||||
static stats::item<uint64_t> total_bytes_in;
|
||||
static stats::item<uint64_t> total_bytes_out;
|
||||
static stats::item<uint64_t> total_calls_in;
|
||||
static stats::item<uint64_t> total_calls_out;
|
||||
|
||||
uint64_t id {++count};
|
||||
ip::tcp::socket sd;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Matrix Construct
|
||||
// The Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -11,142 +11,211 @@
|
|||
#pragma once
|
||||
#define HAVE_IRCD_STATS_H
|
||||
|
||||
/// Statistics & Metrics
|
||||
///
|
||||
/// This is a central collection of registered items each representing a
|
||||
/// counter or metric of some kind. To collect items of various types we orient
|
||||
/// the collection around an abstract item<void> template class. To keep things
|
||||
/// simple, the abstract instance holds a typeinfo provided by the derived
|
||||
/// instance. User can then downcast the item<void> to a derived template.
|
||||
///
|
||||
/// There are two levels in the class hierarchy under the abstract root
|
||||
/// item<void>. The next level is a pointer-to-value such that the item
|
||||
/// registers the location of an existing value. This is useful for
|
||||
/// incorporating external values in existing structures into this collection
|
||||
/// non-intrusively; for example in third-party libraries etc.
|
||||
///
|
||||
/// The next derived level after this is where the item instance itself
|
||||
/// roots (contains) the value and its parent class at the pointer-level points
|
||||
/// down to the derived class. This is a convenience for developers so that
|
||||
/// extern values don't have to be created separately for every stats item.
|
||||
/// Note that when this subsystem works abstractly with items, it considers the
|
||||
/// pointer-level templates to be the principal level of derivation; in other
|
||||
/// words there is no reason to downcast to a value-level template when working
|
||||
/// with this system, and every value-level template must have a matching
|
||||
/// pointer-level parent.
|
||||
namespace ircd::stats
|
||||
{
|
||||
struct item;
|
||||
using value_type = int128_t;
|
||||
|
||||
IRCD_EXCEPTION(ircd::error, error)
|
||||
IRCD_EXCEPTION(error, not_found)
|
||||
|
||||
extern std::map<string_view, item *> items;
|
||||
// Abstract item
|
||||
template<class T = void> struct item;
|
||||
template<> struct item<void>;
|
||||
|
||||
const value_type &get(const item &);
|
||||
value_type &get(item &);
|
||||
// Pointer-to-value items
|
||||
template<> struct item<uint64_t *>;
|
||||
template<> struct item<uint32_t *>;
|
||||
template<> struct item<uint16_t *>;
|
||||
|
||||
value_type &inc(item &, const value_type & = 1);
|
||||
value_type &dec(item &, const value_type & = 1);
|
||||
value_type &set(item &, const value_type & = 0);
|
||||
// Value-carrying items
|
||||
template<> struct item<uint64_t>;
|
||||
template<> struct item<uint32_t>;
|
||||
template<> struct item<uint16_t>;
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const item &);
|
||||
extern const size_t NAME_MAX_LEN;
|
||||
extern std::map<string_view, item<void> *> items;
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const item<void> &);
|
||||
}
|
||||
|
||||
struct ircd::stats::item
|
||||
/// Abstract stats item.
|
||||
///
|
||||
/// This object contains type information about its derived class. There is no
|
||||
/// known use for constructing this on its own without a derived item.
|
||||
///
|
||||
/// Feature information must contain a 'name' string. It is advised that this
|
||||
/// is appropriately namespaced i.e "ircd.net.socket.xxx" and when third-party
|
||||
/// values are gathered i.e "rocksdb.xxx." such that the entire map of items
|
||||
/// can be serialized into a single JSON object tree.
|
||||
///
|
||||
/// Feature information can also contain a 'desc' string describing more about
|
||||
/// the value to administrators and developers.
|
||||
template<>
|
||||
struct ircd::stats::item<void>
|
||||
{
|
||||
static const size_t NAME_MAX_LEN;
|
||||
|
||||
json::strung feature_;
|
||||
json::object feature;
|
||||
string_view name;
|
||||
value_type val;
|
||||
std::type_index type {typeid(void)};
|
||||
json::strung feature;
|
||||
|
||||
public:
|
||||
explicit operator const value_type &() const;
|
||||
explicit operator value_type &();
|
||||
bool operator!() const;
|
||||
// Access features
|
||||
string_view operator[](const string_view &key) const noexcept;
|
||||
|
||||
item &operator+=(const value_type &) &;
|
||||
item &operator-=(const value_type &) &;
|
||||
item &operator=(const value_type &) &;
|
||||
item &operator++();
|
||||
item &operator--();
|
||||
|
||||
item(const json::members &);
|
||||
item() = default;
|
||||
item(const std::type_index &, const json::members &);
|
||||
item(item &&) = delete;
|
||||
item(const item &) = delete;
|
||||
~item() noexcept;
|
||||
virtual ~item() noexcept;
|
||||
};
|
||||
|
||||
inline ircd::stats::item &
|
||||
ircd::stats::item::operator--()
|
||||
template<>
|
||||
struct ircd::stats::item<uint64_t *>
|
||||
:item<void>
|
||||
{
|
||||
--val;
|
||||
return *this;
|
||||
uint64_t *val {nullptr};
|
||||
|
||||
public:
|
||||
operator const uint64_t &() const
|
||||
{
|
||||
assert(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
inline ircd::stats::item &
|
||||
ircd::stats::item::operator++()
|
||||
operator uint64_t &()
|
||||
{
|
||||
++val;
|
||||
return *this;
|
||||
assert(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
inline ircd::stats::item &
|
||||
ircd::stats::item::operator=(const value_type &v)
|
||||
&
|
||||
item(uint64_t *const &, const json::members &);
|
||||
item() = default;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ircd::stats::item<uint32_t *>
|
||||
:item<void>
|
||||
{
|
||||
set(*this, v);
|
||||
return *this;
|
||||
uint32_t *val {nullptr};
|
||||
|
||||
public:
|
||||
operator const uint32_t &() const
|
||||
{
|
||||
assert(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
inline ircd::stats::item &
|
||||
ircd::stats::item::operator-=(const value_type &v)
|
||||
&
|
||||
operator uint32_t &()
|
||||
{
|
||||
dec(*this, v);
|
||||
return *this;
|
||||
assert(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
inline ircd::stats::item &
|
||||
ircd::stats::item::operator+=(const value_type &v)
|
||||
&
|
||||
item(uint32_t *const &, const json::members &);
|
||||
item() = default;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ircd::stats::item<uint16_t *>
|
||||
:item<void>
|
||||
{
|
||||
inc(*this, v);
|
||||
return *this;
|
||||
uint16_t *val {nullptr};
|
||||
|
||||
public:
|
||||
operator const uint16_t &() const
|
||||
{
|
||||
assert(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
inline bool
|
||||
ircd::stats::item::operator!()
|
||||
const
|
||||
operator uint16_t &()
|
||||
{
|
||||
return !get(*this);
|
||||
assert(val);
|
||||
return *val;
|
||||
}
|
||||
|
||||
inline ircd::stats::item::operator
|
||||
value_type &()
|
||||
item(uint16_t *const &, const json::members &);
|
||||
item() = default;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ircd::stats::item<uint64_t>
|
||||
:item<uint64_t *>
|
||||
{
|
||||
return get(*this);
|
||||
uint64_t val {0};
|
||||
|
||||
public:
|
||||
operator const uint64_t &() const noexcept
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
inline ircd::stats::item::operator
|
||||
const value_type &()
|
||||
const
|
||||
operator uint64_t &() noexcept
|
||||
{
|
||||
return get(*this);
|
||||
return val;
|
||||
}
|
||||
|
||||
inline ircd::stats::value_type &
|
||||
ircd::stats::set(item &item,
|
||||
const value_type &v)
|
||||
item(const json::members &);
|
||||
item() = default;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ircd::stats::item<uint32_t>
|
||||
:item<uint32_t *>
|
||||
{
|
||||
item.val = v;
|
||||
return get(item);
|
||||
uint32_t val {0};
|
||||
|
||||
public:
|
||||
operator const uint32_t &() const noexcept
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
inline ircd::stats::value_type &
|
||||
ircd::stats::dec(item &item,
|
||||
const value_type &n)
|
||||
operator uint32_t &() noexcept
|
||||
{
|
||||
item.val -= n;
|
||||
return get(item);
|
||||
return val;
|
||||
}
|
||||
|
||||
inline ircd::stats::value_type &
|
||||
ircd::stats::inc(item &item,
|
||||
const value_type &n)
|
||||
item(const json::members &);
|
||||
item() = default;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ircd::stats::item<uint16_t>
|
||||
:item<uint16_t *>
|
||||
{
|
||||
item.val += n;
|
||||
return get(item);
|
||||
uint16_t val {0};
|
||||
|
||||
public:
|
||||
operator const uint16_t &() const noexcept
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
inline ircd::stats::value_type &
|
||||
ircd::stats::get(item &item)
|
||||
operator uint16_t &() noexcept
|
||||
{
|
||||
return item.val;
|
||||
return val;
|
||||
}
|
||||
|
||||
inline const ircd::stats::value_type &
|
||||
ircd::stats::get(const item &item)
|
||||
{
|
||||
return item.val;
|
||||
}
|
||||
item(const json::members &);
|
||||
item() = default;
|
||||
};
|
||||
|
|
207
ircd/stats.cc
207
ircd/stats.cc
|
@ -8,14 +8,51 @@
|
|||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
decltype(ircd::stats::NAME_MAX_LEN)
|
||||
ircd::stats::NAME_MAX_LEN
|
||||
{
|
||||
127
|
||||
};
|
||||
|
||||
decltype(ircd::stats::items)
|
||||
ircd::stats::items
|
||||
{};
|
||||
|
||||
std::ostream &
|
||||
ircd::stats::operator<<(std::ostream &s, const item &item)
|
||||
ircd::stats::operator<<(std::ostream &s,
|
||||
const item<void> &item_)
|
||||
{
|
||||
s << static_cast<long long>(item.val);
|
||||
if(item_.type == typeid(uint64_t *))
|
||||
{
|
||||
const auto &item
|
||||
{
|
||||
dynamic_cast<const stats::item<uint64_t *> &>(item_)
|
||||
};
|
||||
|
||||
assert(item.val);
|
||||
s << *item.val;
|
||||
}
|
||||
else if(item_.type == typeid(uint32_t *))
|
||||
{
|
||||
const auto &item
|
||||
{
|
||||
dynamic_cast<const stats::item<uint32_t *> &>(item_)
|
||||
};
|
||||
|
||||
assert(item.val);
|
||||
s << *item.val;
|
||||
}
|
||||
else if(item_.type == typeid(uint16_t *))
|
||||
{
|
||||
const auto &item
|
||||
{
|
||||
dynamic_cast<const stats::item<uint16_t *> &>(item_)
|
||||
};
|
||||
|
||||
assert(item.val);
|
||||
s << *item.val;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -23,34 +60,32 @@ ircd::stats::operator<<(std::ostream &s, const item &item)
|
|||
// item
|
||||
//
|
||||
|
||||
decltype(ircd::stats::item::NAME_MAX_LEN)
|
||||
ircd::stats::item::NAME_MAX_LEN
|
||||
{
|
||||
127
|
||||
};
|
||||
|
||||
//
|
||||
// item::item
|
||||
//
|
||||
|
||||
ircd::stats::item::item(const json::members &opts)
|
||||
:feature_
|
||||
ircd::stats::item<void>::item(const std::type_index &type,
|
||||
const json::members &opts)
|
||||
:type
|
||||
{
|
||||
opts
|
||||
type
|
||||
}
|
||||
,feature
|
||||
{
|
||||
feature_
|
||||
}
|
||||
,name
|
||||
{
|
||||
unquote(feature.at("name"))
|
||||
}
|
||||
,val
|
||||
{
|
||||
feature.get<long>("default", 0L)
|
||||
opts
|
||||
}
|
||||
{
|
||||
const json::string name
|
||||
{
|
||||
this->operator[]("name")
|
||||
};
|
||||
|
||||
if(!name)
|
||||
throw error
|
||||
{
|
||||
"Stats item must have a 'name' string feature"
|
||||
};
|
||||
|
||||
if(name.size() > NAME_MAX_LEN)
|
||||
throw error
|
||||
{
|
||||
|
@ -67,13 +102,141 @@ ircd::stats::item::item(const json::members &opts)
|
|||
};
|
||||
}
|
||||
|
||||
ircd::stats::item::~item()
|
||||
ircd::stats::item<void>::~item()
|
||||
noexcept
|
||||
{
|
||||
const json::string name
|
||||
{
|
||||
this->operator[]("name")
|
||||
};
|
||||
|
||||
if(name)
|
||||
{
|
||||
const auto it{items.find(name)};
|
||||
const auto it
|
||||
{
|
||||
items.find(name)
|
||||
};
|
||||
|
||||
assert(data(it->first) == data(name));
|
||||
items.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::stats::item<void>::operator[](const string_view &key)
|
||||
const noexcept
|
||||
{
|
||||
const json::object feature
|
||||
{
|
||||
this->feature
|
||||
};
|
||||
|
||||
return feature[key];
|
||||
}
|
||||
|
||||
//
|
||||
// pointer-to-value items
|
||||
//
|
||||
|
||||
//
|
||||
// item<uint64_t *>
|
||||
//
|
||||
|
||||
ircd::stats::item<uint64_t *>::item(uint64_t *const &val,
|
||||
const json::members &feature)
|
||||
:item<void>
|
||||
{
|
||||
typeid(uint64_t *), feature
|
||||
}
|
||||
,val
|
||||
{
|
||||
val
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// item<uint32_t *>
|
||||
//
|
||||
|
||||
ircd::stats::item<uint32_t *>::item(uint32_t *const &val,
|
||||
const json::members &feature)
|
||||
:item<void>
|
||||
{
|
||||
typeid(uint32_t *), feature
|
||||
}
|
||||
,val
|
||||
{
|
||||
val
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// item<uint16_t *>
|
||||
//
|
||||
|
||||
ircd::stats::item<uint16_t *>::item(uint16_t *const &val,
|
||||
const json::members &feature)
|
||||
:item<void>
|
||||
{
|
||||
typeid(uint16_t *), feature
|
||||
}
|
||||
,val
|
||||
{
|
||||
val
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// value-carrying items
|
||||
//
|
||||
|
||||
//
|
||||
// item<uint64_t>
|
||||
//
|
||||
|
||||
ircd::stats::item<uint64_t>::item(const json::members &feature)
|
||||
:item<uint64_t *>
|
||||
{
|
||||
std::addressof(this->val), feature
|
||||
}
|
||||
,val
|
||||
{
|
||||
0UL
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// item<uint32_t>
|
||||
//
|
||||
|
||||
ircd::stats::item<uint32_t>::item(const json::members &feature)
|
||||
:item<uint32_t *>
|
||||
{
|
||||
std::addressof(this->val), feature
|
||||
}
|
||||
,val
|
||||
{
|
||||
0U
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// item<uint16_t>
|
||||
//
|
||||
|
||||
ircd::stats::item<uint16_t>::item(const json::members &feature)
|
||||
:item<uint16_t *>
|
||||
{
|
||||
std::addressof(this->val), feature
|
||||
}
|
||||
,val
|
||||
{
|
||||
0U
|
||||
}
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue