diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/monlib/dynamic_counters/counters.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/monlib/dynamic_counters/counters.cpp')
-rw-r--r-- | library/cpp/monlib/dynamic_counters/counters.cpp | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/library/cpp/monlib/dynamic_counters/counters.cpp b/library/cpp/monlib/dynamic_counters/counters.cpp new file mode 100644 index 0000000000..3635d87d0d --- /dev/null +++ b/library/cpp/monlib/dynamic_counters/counters.cpp @@ -0,0 +1,308 @@ +#include "counters.h" + +#include <library/cpp/monlib/service/pages/templates.h> + +#include <util/generic/cast.h> + +using namespace NMonitoring; + +namespace { + TDynamicCounters* AsDynamicCounters(const TIntrusivePtr<TCountableBase>& ptr) { + return dynamic_cast<TDynamicCounters*>(ptr.Get()); + } + + TCounterForPtr* AsCounter(const TIntrusivePtr<TCountableBase>& ptr) { + return dynamic_cast<TCounterForPtr*>(ptr.Get()); + } + + TExpiringCounter* AsExpiringCounter(const TIntrusivePtr<TCountableBase>& ptr) { + return dynamic_cast<TExpiringCounter*>(ptr.Get()); + } + + TExpiringHistogramCounter* AsExpiringHistogramCounter(const TIntrusivePtr<TCountableBase>& ptr) { + return dynamic_cast<TExpiringHistogramCounter*>(ptr.Get()); + } + + THistogramCounter* AsHistogram(const TIntrusivePtr<TCountableBase>& ptr) { + return dynamic_cast<THistogramCounter*>(ptr.Get()); + } + + TIntrusivePtr<TCounterForPtr> AsCounterRef(const TIntrusivePtr<TCountableBase>& ptr) { + return VerifyDynamicCast<TCounterForPtr*>(ptr.Get()); + } + + TIntrusivePtr<TDynamicCounters> AsGroupRef(const TIntrusivePtr<TCountableBase>& ptr) { + return VerifyDynamicCast<TDynamicCounters*>(ptr.Get()); + } + + THistogramPtr AsHistogramRef(const TIntrusivePtr<TCountableBase>& ptr) { + return VerifyDynamicCast<THistogramCounter*>(ptr.Get()); + } + + bool IsExpiringCounter(const TIntrusivePtr<TCountableBase>& ptr) { + return AsExpiringCounter(ptr) != nullptr || AsExpiringHistogramCounter(ptr) != nullptr; + } +} + +static constexpr TStringBuf INDENT = " "; + +TDynamicCounters::TDynamicCounters(EVisibility vis) +{ + Visibility_ = vis; +} + +TDynamicCounters::~TDynamicCounters() { +} + +TDynamicCounters::TCounterPtr TDynamicCounters::GetExpiringCounter(const TString& value, bool derivative, EVisibility vis) { + return GetExpiringNamedCounter("sensor", value, derivative, vis); +} + +TDynamicCounters::TCounterPtr TDynamicCounters::GetExpiringNamedCounter(const TString& name, const TString& value, bool derivative, EVisibility vis) { + return AsCounterRef(GetNamedCounterImpl<true, TExpiringCounter>(name, value, derivative, vis)); +} + +TDynamicCounters::TCounterPtr TDynamicCounters::GetCounter(const TString& value, bool derivative, EVisibility vis) { + return GetNamedCounter("sensor", value, derivative, vis); +} + +TDynamicCounters::TCounterPtr TDynamicCounters::GetNamedCounter(const TString& name, const TString& value, bool derivative, EVisibility vis) { + return AsCounterRef(GetNamedCounterImpl<false, TCounterForPtr>(name, value, derivative, vis)); +} + +THistogramPtr TDynamicCounters::GetHistogram(const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) { + return GetNamedHistogram("sensor", value, std::move(collector), derivative, vis); +} + +THistogramPtr TDynamicCounters::GetNamedHistogram(const TString& name, const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) { + return AsHistogramRef(GetNamedCounterImpl<false, THistogramCounter>(name, value, std::move(collector), derivative, vis)); +} + +THistogramPtr TDynamicCounters::GetExpiringHistogram(const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) { + return GetExpiringNamedHistogram("sensor", value, std::move(collector), derivative, vis); +} + +THistogramPtr TDynamicCounters::GetExpiringNamedHistogram(const TString& name, const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) { + return AsHistogramRef(GetNamedCounterImpl<true, TExpiringHistogramCounter>(name, value, std::move(collector), derivative, vis)); +} + +TDynamicCounters::TCounterPtr TDynamicCounters::FindCounter(const TString& value) const { + return FindNamedCounter("sensor", value); +} + +TDynamicCounters::TCounterPtr TDynamicCounters::FindNamedCounter(const TString& name, const TString& value) const { + return AsCounterRef(FindNamedCounterImpl<TCounterForPtr>(name, value)); +} + +THistogramPtr TDynamicCounters::FindHistogram(const TString& value) const { + return FindNamedHistogram("sensor", value); +} + +THistogramPtr TDynamicCounters::FindNamedHistogram(const TString& name,const TString& value) const { + return AsHistogramRef(FindNamedCounterImpl<THistogramCounter>(name, value)); +} + +void TDynamicCounters::RemoveCounter(const TString &value) { + RemoveNamedCounter("sensor", value); +} + +void TDynamicCounters::RemoveNamedCounter(const TString& name, const TString &value) { + auto g = LockForUpdate("RemoveNamedCounter", name, value); + if (const auto it = Counters.find({name, value}); it != Counters.end() && AsCounter(it->second)) { + Counters.erase(it); + } +} + +TIntrusivePtr<TDynamicCounters> TDynamicCounters::GetSubgroup(const TString& name, const TString& value) { + auto res = FindSubgroup(name, value); + if (!res) { + auto g = LockForUpdate("GetSubgroup", name, value); + const TChildId key(name, value); + if (const auto it = Counters.lower_bound(key); it != Counters.end() && it->first == key) { + res = AsGroupRef(it->second); + } else { + res = MakeIntrusive<TDynamicCounters>(this); + Counters.emplace_hint(it, key, res); + } + } + return res; +} + +TIntrusivePtr<TDynamicCounters> TDynamicCounters::FindSubgroup(const TString& name, const TString& value) const { + TReadGuard g(Lock); + const auto it = Counters.find({name, value}); + return it != Counters.end() ? AsDynamicCounters(it->second) : nullptr; +} + +void TDynamicCounters::RemoveSubgroup(const TString& name, const TString& value) { + auto g = LockForUpdate("RemoveSubgroup", name, value); + if (const auto it = Counters.find({name, value}); it != Counters.end() && AsDynamicCounters(it->second)) { + Counters.erase(it); + } +} + +void TDynamicCounters::ReplaceSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) { + auto g = LockForUpdate("ReplaceSubgroup", name, value); + const auto it = Counters.find({name, value}); + Y_VERIFY(it != Counters.end() && AsDynamicCounters(it->second)); + it->second = std::move(subgroup); +} + +void TDynamicCounters::MergeWithSubgroup(const TString& name, const TString& value) { + auto g = LockForUpdate("MergeWithSubgroup", name, value); + auto it = Counters.find({name, value}); + Y_VERIFY(it != Counters.end()); + TIntrusivePtr<TDynamicCounters> subgroup = AsDynamicCounters(it->second); + Y_VERIFY(subgroup); + Counters.erase(it); + Counters.merge(subgroup->Resign()); + AtomicAdd(ExpiringCount, AtomicSwap(&subgroup->ExpiringCount, 0)); +} + +void TDynamicCounters::ResetCounters(bool derivOnly) { + TReadGuard g(Lock); + for (auto& [key, value] : Counters) { + if (auto counter = AsCounter(value)) { + if (!derivOnly || counter->ForDerivative()) { + *counter = 0; + } + } else if (auto subgroup = AsDynamicCounters(value)) { + subgroup->ResetCounters(derivOnly); + } + } +} + +void TDynamicCounters::RegisterCountable(const TString& name, const TString& value, TCountablePtr countable) { + Y_VERIFY(countable); + auto g = LockForUpdate("RegisterCountable", name, value); + const bool inserted = Counters.emplace(TChildId(name, value), std::move(countable)).second; + Y_VERIFY(inserted); +} + +void TDynamicCounters::RegisterSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) { + RegisterCountable(name, value, subgroup); +} + +void TDynamicCounters::OutputHtml(IOutputStream& os) const { + HTML(os) { + PRE() { + OutputPlainText(os); + } + } +} + +void TDynamicCounters::EnumerateSubgroups(const std::function<void(const TString& name, const TString& value)>& output) const { + TReadGuard g(Lock); + for (const auto& [key, value] : Counters) { + if (AsDynamicCounters(value)) { + output(key.LabelName, key.LabelValue); + } + } +} + +void TDynamicCounters::OutputPlainText(IOutputStream& os, const TString& indent) const { + auto snap = ReadSnapshot(); + // mark private records in plain text output + auto outputVisibilityMarker = [] (EVisibility vis) { + return vis == EVisibility::Private ? "\t[PRIVATE]" : ""; + }; + + for (const auto& [key, value] : snap) { + if (const auto counter = AsCounter(value)) { + os << indent + << key.LabelName << '=' << key.LabelValue + << ": " << counter->Val() + << outputVisibilityMarker(counter->Visibility()) + << '\n'; + } else if (const auto histogram = AsHistogram(value)) { + os << indent + << key.LabelName << '=' << key.LabelValue + << ":" + << outputVisibilityMarker(histogram->Visibility()) + << "\n"; + + auto snapshot = histogram->Snapshot(); + for (ui32 i = 0, count = snapshot->Count(); i < count; i++) { + os << indent << INDENT << TStringBuf("bin="); + TBucketBound bound = snapshot->UpperBound(i); + if (bound == Max<TBucketBound>()) { + os << TStringBuf("inf"); + } else { + os << bound; + } + os << ": " << snapshot->Value(i) << '\n'; + } + } + } + + for (const auto& [key, value] : snap) { + if (const auto subgroup = AsDynamicCounters(value)) { + os << "\n"; + os << indent << key.LabelName << "=" << key.LabelValue << ":\n"; + subgroup->OutputPlainText(os, indent + INDENT); + } + } +} + +void TDynamicCounters::Accept(const TString& labelName, const TString& labelValue, ICountableConsumer& consumer) const { + if (!IsVisible(Visibility(), consumer.Visibility())) { + return; + } + + consumer.OnGroupBegin(labelName, labelValue, this); + for (auto& [key, value] : ReadSnapshot()) { + value->Accept(key.LabelName, key.LabelValue, consumer); + } + consumer.OnGroupEnd(labelName, labelValue, this); +} + +void TDynamicCounters::RemoveExpired() const { + if (AtomicGet(ExpiringCount) == 0) { + return; + } + + TWriteGuard g(Lock); + TAtomicBase count = 0; + + for (auto it = Counters.begin(); it != Counters.end();) { + if (IsExpiringCounter(it->second) && it->second->RefCount() == 1) { + it = Counters.erase(it); + ++count; + } else { + ++it; + } + } + + AtomicSub(ExpiringCount, count); +} + +template <bool expiring, class TCounterType, class... TArgs> +TDynamicCounters::TCountablePtr TDynamicCounters::GetNamedCounterImpl(const TString& name, const TString& value, TArgs&&... args) { + { + TReadGuard g(Lock); + auto it = Counters.find({name, value}); + if (it != Counters.end()) { + return it->second; + } + } + + auto g = LockForUpdate("GetNamedCounterImpl", name, value); + const TChildId key(name, value); + auto it = Counters.lower_bound(key); + if (it == Counters.end() || it->first != key) { + auto value = MakeIntrusive<TCounterType>(std::forward<TArgs>(args)...); + it = Counters.emplace_hint(it, key, value); + if constexpr (expiring) { + AtomicIncrement(ExpiringCount); + } + } + return it->second; +} + +template <class TCounterType> +TDynamicCounters::TCountablePtr TDynamicCounters::FindNamedCounterImpl(const TString& name, const TString& value) const { + TReadGuard g(Lock); + auto it = Counters.find({name, value}); + return it != Counters.end() ? it->second : nullptr; +} + |