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`.");
70 static_assert(!std::is_arithmetic_v<Metric>,
71 "Type is not atomic, use std::atomic<T> instead");
74 template <
typename... Args>
75 explicit MetricWrapper(std::in_place_t,
const Args&... args)
77 if constexpr (
sizeof...(Args) == 0) {
78 InitializeAtomic(data_);
82 formats::
json::ValueBuilder DeprecatedJsonDump()
override {
83 if constexpr (!kHasWriterSupport<Metric>) {
84 return DumpMetric(data_);
89 void DumpToWriter(Writer& writer)
override {
90 if constexpr (kHasWriterSupport<Metric>) {
95 bool HasWriterSupport()
const noexcept override {
96 return kHasWriterSupport<Metric>;
99 void Reset()
override {
100 if constexpr (meta::kIsDetected<HasResetMetric, Metric>) {
105 Metric& Get() {
return data_; }
111using MetricFactory = std::function<std::unique_ptr<MetricWrapperBase>()>;
113template <
typename Metric,
typename... Args>
115MetricFactory MakeMetricFactory(Args&&... args) {
116 if constexpr (
sizeof...(Args) == 0) {
117 static_assert(std::is_default_constructible_v<Metric>,
118 "Metric type is not default-constructible. You can pass "
119 "additional args to MetricTag to forward them to Metric.");
121 static_assert(std::is_constructible_v<Metric,
const Args&...>,
122 "Metric type is not constructible from the given args");
124 (
true && ... && std::is_copy_constructible_v<std::decay_t<Args>>),
125 "Metric args must be copy-constructible");
129 return std::make_unique<MetricWrapper<Metric>>(std::in_place, args...);
133struct MetricKey
final {
137 bool operator==(
const MetricKey& other)
const noexcept {
138 return idx == other.idx && path == other.path;
142struct MetricKeyHash
final {
143 std::size_t operator()(
const MetricKey& key)
const noexcept;
147 std::unordered_map<MetricKey, std::unique_ptr<MetricWrapperBase>,
150void RegisterMetricInfo(
const MetricKey& key, MetricFactory factory);
152template <
typename Metric>
153Metric& GetMetric(MetricMap& metrics,
const MetricKey& key) {
154 return dynamic_cast<impl::MetricWrapper<Metric>&>(*metrics.at(key)).Get();