mirror of
https://github.com/XRPLF/clio.git
synced 2026-06-04 17:26:49 +00:00
271 lines
6.6 KiB
C++
271 lines
6.6 KiB
C++
#pragma once
|
|
|
|
#include "util/Assert.hpp"
|
|
#include "util/config/ConfigDefinition.hpp"
|
|
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
#include <boost/json.hpp>
|
|
#include <boost/json/conversion.hpp>
|
|
#include <boost/json/value.hpp>
|
|
#include <boost/uuid/uuid.hpp>
|
|
#include <boost/uuid/uuid_io.hpp>
|
|
|
|
#include <atomic>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <utility>
|
|
|
|
namespace util {
|
|
namespace impl {
|
|
|
|
/**
|
|
* @brief A `null` tag generator - does nothing.
|
|
*/
|
|
struct NullTagGenerator final {};
|
|
|
|
/**
|
|
* @brief This strategy uses an `atomic_uint64_t` to remain lock free.
|
|
*/
|
|
struct UIntTagGenerator final {
|
|
using TagType = std::atomic_uint64_t;
|
|
|
|
static TagType
|
|
next();
|
|
};
|
|
|
|
/**
|
|
* @brief This strategy uses `boost::uuids::uuid` with a static random generator and a mutex.
|
|
*/
|
|
struct UUIDTagGenerator final {
|
|
using TagType = boost::uuids::uuid;
|
|
|
|
static TagType
|
|
next();
|
|
};
|
|
|
|
} // namespace impl
|
|
|
|
/**
|
|
* @brief Represents any tag decorator.
|
|
*/
|
|
class BaseTagDecorator {
|
|
public:
|
|
virtual ~BaseTagDecorator() = default;
|
|
|
|
/**
|
|
* @brief Decorates a std::ostream.
|
|
*
|
|
* @param os The stream to decorate
|
|
*/
|
|
virtual void
|
|
decorate(std::ostream& os) const = 0;
|
|
|
|
/**
|
|
* @brief Support for decorating streams (boost log, cout, etc.).
|
|
*
|
|
* @param os The stream
|
|
* @param decorator The decorator
|
|
* @return The same stream that we were given
|
|
*/
|
|
friend std::ostream&
|
|
operator<<(std::ostream& os, BaseTagDecorator const& decorator)
|
|
{
|
|
decorator.decorate(os);
|
|
return os;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the string representation of the tag.
|
|
*
|
|
* @return The string representation of the tag
|
|
*/
|
|
[[nodiscard]] std::string
|
|
toString() const
|
|
{
|
|
std::ostringstream oss;
|
|
decorate(oss);
|
|
return std::move(oss).str();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A decorator that decorates a string (log line) with a unique tag.
|
|
*
|
|
* @tparam Generator The strategy used to generate the tag.
|
|
*/
|
|
template <typename Generator>
|
|
class TagDecorator final : public BaseTagDecorator {
|
|
using ParentType = std::optional<std::reference_wrapper<BaseTagDecorator const>>;
|
|
using TagType = typename Generator::TagType;
|
|
|
|
ParentType parent_ = std::nullopt;
|
|
TagType tag_ = Generator::next();
|
|
|
|
public:
|
|
/**
|
|
* @brief Create a new tag decorator with an optional parent.
|
|
*
|
|
* If the `parent` is specified it will be streamed out as a chain when this decorator will
|
|
* decorate an ostream.
|
|
*
|
|
* Note that if `parent` is specified it is your responsibility that the decorator referred to
|
|
* by `parent` outlives this decorator.
|
|
*
|
|
* @param parent An optional parent tag decorator
|
|
*/
|
|
explicit TagDecorator(ParentType parent = std::nullopt) : parent_{parent}
|
|
{
|
|
}
|
|
|
|
/**
|
|
* @brief Implementation of the decoration. Chaining tags when parent is available.
|
|
*
|
|
* @param os The stream to output into
|
|
*/
|
|
void
|
|
decorate(std::ostream& os) const override
|
|
{
|
|
os << "[";
|
|
|
|
if (parent_.has_value())
|
|
parent_->get().decorate(os);
|
|
|
|
os << tag_ << "] ";
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Specialization for a nop/null decorator.
|
|
*
|
|
* This generates a pass-through decorate member function which can be optimized away by the
|
|
* compiler.
|
|
*/
|
|
template <>
|
|
class TagDecorator<impl::NullTagGenerator> final : public BaseTagDecorator {
|
|
public:
|
|
/**
|
|
* @brief Nop implementation for the decorator.
|
|
*
|
|
* @param os The stream
|
|
*/
|
|
void
|
|
decorate([[maybe_unused]] std::ostream& os) const override
|
|
{
|
|
// nop
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A factory for TagDecorator instantiation.
|
|
*/
|
|
class TagDecoratorFactory final {
|
|
using ParentType = std::optional<std::reference_wrapper<BaseTagDecorator const>>;
|
|
|
|
/**
|
|
* @brief Represents the type of tag decorator.
|
|
*/
|
|
enum class Type {
|
|
NONE, /**< No decoration and no tag */
|
|
UUID, /**< Tag based on `boost::uuids::uuid`, thread-safe via mutex */
|
|
UINT /**< atomic_uint64_t tag, thread-safe, lock-free */
|
|
};
|
|
|
|
Type type_; /*< The type of TagDecorator this factory produces */
|
|
ParentType parent_ = std::nullopt; /*< The parent tag decorator to bind */
|
|
|
|
static Type
|
|
getLogTagType(std::string_view style)
|
|
{
|
|
if (boost::iequals(style, "int") || boost::iequals(style, "uint"))
|
|
return TagDecoratorFactory::Type::UINT;
|
|
|
|
if (boost::iequals(style, "null") || boost::iequals(style, "none"))
|
|
return TagDecoratorFactory::Type::NONE;
|
|
|
|
if (boost::iequals(style, "uuid"))
|
|
return TagDecoratorFactory::Type::UUID;
|
|
|
|
ASSERT(false, "log.tag_style does not have valid value");
|
|
std::unreachable();
|
|
}
|
|
|
|
public:
|
|
~TagDecoratorFactory() = default;
|
|
|
|
/**
|
|
* @brief Instantiates a tag decorator factory from `clio` configuration.
|
|
*
|
|
* @param config The configuration as a json object
|
|
*/
|
|
explicit TagDecoratorFactory(util::config::ClioConfigDefinition const& config)
|
|
: type_{getLogTagType(config.get<std::string>("log.tag_style"))}
|
|
{
|
|
}
|
|
|
|
private:
|
|
TagDecoratorFactory(Type type, ParentType parent) noexcept : type_{type}, parent_{parent}
|
|
{
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* @brief Instantiates the TagDecorator specified by `type_` with parent bound from `parent_`.
|
|
*
|
|
* @return An instance of the requested decorator
|
|
*/
|
|
[[nodiscard]] std::unique_ptr<BaseTagDecorator>
|
|
make() const;
|
|
|
|
/**
|
|
* @brief Creates a new tag decorator factory with a bound parent tag decorator.
|
|
*
|
|
* @param parent The parent tag decorator to use
|
|
* @return A new instance of the tag decorator factory
|
|
*/
|
|
[[nodiscard]] TagDecoratorFactory
|
|
with(ParentType parent) const noexcept;
|
|
};
|
|
|
|
/**
|
|
* @brief A base class that allows attaching a tag decorator to a subclass.
|
|
*/
|
|
class Taggable {
|
|
using DecoratorType = std::unique_ptr<BaseTagDecorator>;
|
|
DecoratorType tagDecorator_;
|
|
|
|
protected:
|
|
/**
|
|
* @brief New Taggable from a specified factory.
|
|
*
|
|
* @param tagFactory The factory to use
|
|
*/
|
|
explicit Taggable(util::TagDecoratorFactory const& tagFactory)
|
|
: tagDecorator_{tagFactory.make()}
|
|
{
|
|
}
|
|
|
|
public:
|
|
virtual ~Taggable() = default;
|
|
Taggable(Taggable&&) = default;
|
|
|
|
Taggable&
|
|
operator=(Taggable&&) = default;
|
|
|
|
/**
|
|
* @brief Getter for tag decorator.
|
|
*
|
|
* @return Reference to the tag decorator
|
|
*/
|
|
[[nodiscard]] BaseTagDecorator const&
|
|
tag() const
|
|
{
|
|
return *tagDecorator_;
|
|
}
|
|
};
|
|
|
|
} // namespace util
|