// The Construct // // Copyright (C) The Construct Developers, Authors & Contributors // Copyright (C) 2016-2020 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #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 template class. To keep things /// simple, the abstract instance holds a typeinfo provided by the derived /// instance. User can then downcast the item to a derived template. /// /// There are two levels in the class hierarchy under the abstract root /// item. 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 { IRCD_EXCEPTION(ircd::error, error) IRCD_EXCEPTION(error, not_found) IRCD_PANICKING(error, invalid) // Abstract item template struct item; template<> struct item; // Category item template struct ptr_item; template struct int_item; // Pointer-to-value items template<> struct item; template<> struct item; template<> struct item; // Value-carrying items template<> struct item; template<> struct item; template<> struct item; extern const size_t NAME_MAX_LEN; extern std::vector *> items; string_view string(const mutable_buffer &, const item &); std::ostream &operator<<(std::ostream &, const 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 { std::type_index type {typeid(void)}; json::strung feature; json::string name; public: // Access features string_view operator[](const string_view &key) const noexcept; virtual bool operator!() const = 0; item() = default; item(const std::type_index &, const json::members &); item(item &&) = delete; item(const item &) = delete; virtual ~item() noexcept; }; /// Abstract pointer item template struct ircd::stats::ptr_item :item { T *val {nullptr}; public: bool operator!() const override { return !val || *val == T{0}; } operator const T &() const { assert(val); return *val; } operator T &() { assert(val); return *val; } ptr_item &operator=(const T &val) & { static_cast(*this) = val; return *this; } ptr_item(T *const &val, const json::members &feature) :item{typeid(T *), feature} ,val{val} {} ptr_item() = default; }; /// Abstract value item template struct ircd::stats::int_item :ptr_item { T val {0}; public: operator const T &() const noexcept { return val; } operator T &() noexcept { return val; } int_item &operator=(const T &val) & { static_cast(*this) = val; return *this; } int_item(const json::members &feature) :ptr_item{std::addressof(this->val), feature} ,val{0} {} int_item() = default; }; template<> struct ircd::stats::item :ptr_item { using ptr_item::ptr_item; using ptr_item::operator=; }; template<> struct ircd::stats::item :int_item { using int_item::int_item; using int_item::operator=; }; template<> struct ircd::stats::item :ptr_item { using ptr_item::ptr_item; using ptr_item::operator=; }; template<> struct ircd::stats::item :int_item { using int_item::int_item; using int_item::operator=; }; template<> struct ircd::stats::item :ptr_item { using ptr_item::ptr_item; using ptr_item::operator=; }; template<> struct ircd::stats::item :int_item { using int_item::int_item; using int_item::operator=; };