11#include <unordered_map>
13#include <userver/formats/json/value.hpp>
14#include <userver/formats/json/value_builder.hpp>
15#include <userver/utils/meta_light.hpp>
16#include <userver/utils/statistics/writer.hpp>
18USERVER_NAMESPACE_BEGIN
20namespace utils::statistics::impl {
22template <
typename Metric>
23formats::
json::ValueBuilder DumpMetric(
const std::atomic<Metric>& m) {
24 static_assert(std::atomic<Metric>::is_always_lock_free,
"std::atomic misuse");
28template <
typename Metric>
29void ResetMetric(std::atomic<Metric>& m) {
30 static_assert(std::atomic<Metric>::is_always_lock_free,
"std::atomic misuse");
34template <
typename Metric>
35using HasDumpMetric =
decltype(DumpMetric(std::declval<Metric&>()));
37template <
typename Metric>
38using HasResetMetric =
decltype(ResetMetric(std::declval<Metric&>()));
42void InitializeAtomic(T& ) {}
45void InitializeAtomic(std::atomic<T>& value) {
46 value.store(T(), std::memory_order_relaxed);
49class MetricWrapperBase {
51 MetricWrapperBase& operator=(MetricWrapperBase&&) =
delete;
52 virtual ~MetricWrapperBase();
54 virtual formats::
json::ValueBuilder DeprecatedJsonDump() = 0;
56 virtual void DumpToWriter(
utils::statistics::Writer& writer) = 0;
58 virtual bool HasWriterSupport()
const noexcept = 0;
60 virtual void Reset() = 0;
63template <
typename Metric>
64class MetricWrapper
final :
public MetricWrapperBase {
66 meta::kIsDetected<HasDumpMetric, Metric> || kHasWriterSupport<Metric>,
67 "Provide a `void DumpMetric(utils::statistics::Writer&, const Metric&)`"
68 "function in the namespace of `Metric`."
71 static_assert(!std::is_arithmetic_v<Metric>,
"Type is not atomic, use std::atomic<T> instead");
74 template <
typename... Args>
75 explicit MetricWrapper(std::in_place_t,
const Args&... args) : data_(args...) {
76 if constexpr (
sizeof...(Args) == 0) {
77 InitializeAtomic(data_);
81 formats::
json::ValueBuilder DeprecatedJsonDump()
override {
82 if constexpr (!kHasWriterSupport<Metric>) {
83 return DumpMetric(data_);
88 void DumpToWriter(Writer& writer)
override {
89 if constexpr (kHasWriterSupport<Metric>) {
94 bool HasWriterSupport()
const noexcept override {
return kHasWriterSupport<Metric>; }
96 void Reset()
override {
97 if constexpr (meta::kIsDetected<HasResetMetric, Metric>) {
102 Metric& Get() {
return data_; }
108using MetricFactory = std::function<std::unique_ptr<MetricWrapperBase>()>;
110template <
typename Metric,
typename... Args>
112MetricFactory MakeMetricFactory(Args&&... args) {
113 if constexpr (
sizeof...(Args) == 0) {
115 std::is_default_constructible_v<Metric>,
116 "Metric type is not default-constructible. You can pass "
117 "additional args to MetricTag to forward them to Metric."
121 std::is_constructible_v<Metric,
const Args&...>,
"Metric type is not constructible from the given args"
124 (
true && ... && std::is_copy_constructible_v<std::decay_t<Args>>),
"Metric args must be copy-constructible"
128 return [args...] {
return std::make_unique<MetricWrapper<Metric>>(std::in_place, args...); };
131struct MetricKey
final {
135 bool operator==(
const MetricKey& other)
const noexcept {
return idx == other.idx && path == other.path; }
138struct MetricKeyHash
final {
139 std::size_t operator()(
const MetricKey& key)
const noexcept;
142using MetricMap = std::unordered_map<MetricKey, std::unique_ptr<MetricWrapperBase>, MetricKeyHash>;
144void RegisterMetricInfo(
const MetricKey& key, MetricFactory factory);
146template <
typename Metric>
147Metric& GetMetric(MetricMap& metrics,
const MetricKey& key) {
148 return dynamic_cast<impl::MetricWrapper<Metric>&>(*metrics.at(key)).Get();