aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/monlib/dynamic_counters/counters.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/monlib/dynamic_counters/counters.cpp
downloadydb-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.cpp308
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;
+}
+