counters.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include "counters.h"
  2. #include <library/cpp/monlib/service/pages/templates.h>
  3. #include <util/generic/cast.h>
  4. using namespace NMonitoring;
  5. namespace {
  6. TDynamicCounters* AsDynamicCounters(const TIntrusivePtr<TCountableBase>& ptr) {
  7. return dynamic_cast<TDynamicCounters*>(ptr.Get());
  8. }
  9. TCounterForPtr* AsCounter(const TIntrusivePtr<TCountableBase>& ptr) {
  10. return dynamic_cast<TCounterForPtr*>(ptr.Get());
  11. }
  12. TExpiringCounter* AsExpiringCounter(const TIntrusivePtr<TCountableBase>& ptr) {
  13. return dynamic_cast<TExpiringCounter*>(ptr.Get());
  14. }
  15. TExpiringHistogramCounter* AsExpiringHistogramCounter(const TIntrusivePtr<TCountableBase>& ptr) {
  16. return dynamic_cast<TExpiringHistogramCounter*>(ptr.Get());
  17. }
  18. THistogramCounter* AsHistogram(const TIntrusivePtr<TCountableBase>& ptr) {
  19. return dynamic_cast<THistogramCounter*>(ptr.Get());
  20. }
  21. TIntrusivePtr<TCounterForPtr> AsCounterRef(const TIntrusivePtr<TCountableBase>& ptr) {
  22. return VerifyDynamicCast<TCounterForPtr*>(ptr.Get());
  23. }
  24. TIntrusivePtr<TDynamicCounters> AsGroupRef(const TIntrusivePtr<TCountableBase>& ptr) {
  25. return VerifyDynamicCast<TDynamicCounters*>(ptr.Get());
  26. }
  27. THistogramPtr AsHistogramRef(const TIntrusivePtr<TCountableBase>& ptr) {
  28. return VerifyDynamicCast<THistogramCounter*>(ptr.Get());
  29. }
  30. bool IsExpiringCounter(const TIntrusivePtr<TCountableBase>& ptr) {
  31. return AsExpiringCounter(ptr) != nullptr || AsExpiringHistogramCounter(ptr) != nullptr;
  32. }
  33. }
  34. static constexpr TStringBuf INDENT = " ";
  35. TDynamicCounters::TDynamicCounters(EVisibility vis)
  36. {
  37. Visibility_ = vis;
  38. }
  39. TDynamicCounters::~TDynamicCounters() {
  40. }
  41. TDynamicCounters::TCounterPtr TDynamicCounters::GetExpiringCounter(const TString& value, bool derivative, EVisibility vis) {
  42. return GetExpiringNamedCounter("sensor", value, derivative, vis);
  43. }
  44. TDynamicCounters::TCounterPtr TDynamicCounters::GetExpiringNamedCounter(const TString& name, const TString& value, bool derivative, EVisibility vis) {
  45. return AsCounterRef(GetNamedCounterImpl<true, TExpiringCounter>(name, value, derivative, vis));
  46. }
  47. TDynamicCounters::TCounterPtr TDynamicCounters::GetCounter(const TString& value, bool derivative, EVisibility vis) {
  48. return GetNamedCounter("sensor", value, derivative, vis);
  49. }
  50. TDynamicCounters::TCounterPtr TDynamicCounters::GetNamedCounter(const TString& name, const TString& value, bool derivative, EVisibility vis) {
  51. return AsCounterRef(GetNamedCounterImpl<false, TCounterForPtr>(name, value, derivative, vis));
  52. }
  53. THistogramPtr TDynamicCounters::GetHistogram(const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
  54. return GetNamedHistogram("sensor", value, std::move(collector), derivative, vis);
  55. }
  56. THistogramPtr TDynamicCounters::GetNamedHistogram(const TString& name, const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
  57. return AsHistogramRef(GetNamedCounterImpl<false, THistogramCounter>(name, value, std::move(collector), derivative, vis));
  58. }
  59. THistogramPtr TDynamicCounters::GetExpiringHistogram(const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
  60. return GetExpiringNamedHistogram("sensor", value, std::move(collector), derivative, vis);
  61. }
  62. THistogramPtr TDynamicCounters::GetExpiringNamedHistogram(const TString& name, const TString& value, IHistogramCollectorPtr collector, bool derivative, EVisibility vis) {
  63. return AsHistogramRef(GetNamedCounterImpl<true, TExpiringHistogramCounter>(name, value, std::move(collector), derivative, vis));
  64. }
  65. TDynamicCounters::TCounterPtr TDynamicCounters::FindCounter(const TString& value) const {
  66. return FindNamedCounter("sensor", value);
  67. }
  68. TDynamicCounters::TCounterPtr TDynamicCounters::FindNamedCounter(const TString& name, const TString& value) const {
  69. return AsCounterRef(FindNamedCounterImpl<TCounterForPtr>(name, value));
  70. }
  71. THistogramPtr TDynamicCounters::FindHistogram(const TString& value) const {
  72. return FindNamedHistogram("sensor", value);
  73. }
  74. THistogramPtr TDynamicCounters::FindNamedHistogram(const TString& name,const TString& value) const {
  75. return AsHistogramRef(FindNamedCounterImpl<THistogramCounter>(name, value));
  76. }
  77. void TDynamicCounters::RemoveCounter(const TString &value) {
  78. RemoveNamedCounter("sensor", value);
  79. }
  80. bool TDynamicCounters::RemoveNamedCounter(const TString& name, const TString &value) {
  81. auto g = LockForUpdate("RemoveNamedCounter", name, value);
  82. if (const auto it = Counters.find({name, value}); it != Counters.end() && AsCounter(it->second)) {
  83. Counters.erase(it);
  84. }
  85. return Counters.empty();
  86. }
  87. void TDynamicCounters::RemoveSubgroupChain(const std::vector<std::pair<TString, TString>>& chain) {
  88. std::vector<TIntrusivePtr<TDynamicCounters>> basePointers;
  89. basePointers.push_back(this);
  90. for (size_t i = 0; i < chain.size() - 1; ++i) {
  91. const auto& [name, value] = chain[i];
  92. auto& base = basePointers.back();
  93. basePointers.push_back(base->GetSubgroup(name, value));
  94. Y_ABORT_UNLESS(basePointers.back());
  95. }
  96. for (size_t i = chain.size(); i-- && basePointers[i]->RemoveSubgroup(chain[i].first, chain[i].second); ) {}
  97. }
  98. TIntrusivePtr<TDynamicCounters> TDynamicCounters::GetSubgroup(const TString& name, const TString& value) {
  99. auto res = FindSubgroup(name, value);
  100. if (!res) {
  101. auto g = LockForUpdate("GetSubgroup", name, value);
  102. const TChildId key(name, value);
  103. if (const auto it = Counters.lower_bound(key); it != Counters.end() && it->first == key) {
  104. res = AsGroupRef(it->second);
  105. } else {
  106. res = MakeIntrusive<TDynamicCounters>(this);
  107. Counters.emplace_hint(it, key, res);
  108. }
  109. }
  110. return res;
  111. }
  112. TIntrusivePtr<TDynamicCounters> TDynamicCounters::FindSubgroup(const TString& name, const TString& value) const {
  113. TReadGuard g(Lock);
  114. const auto it = Counters.find({name, value});
  115. return it != Counters.end() ? AsDynamicCounters(it->second) : nullptr;
  116. }
  117. bool TDynamicCounters::RemoveSubgroup(const TString& name, const TString& value) {
  118. auto g = LockForUpdate("RemoveSubgroup", name, value);
  119. if (const auto it = Counters.find({name, value}); it != Counters.end() && AsDynamicCounters(it->second)) {
  120. Counters.erase(it);
  121. }
  122. return Counters.empty();
  123. }
  124. void TDynamicCounters::ReplaceSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) {
  125. auto g = LockForUpdate("ReplaceSubgroup", name, value);
  126. const auto it = Counters.find({name, value});
  127. Y_ABORT_UNLESS(it != Counters.end() && AsDynamicCounters(it->second));
  128. it->second = std::move(subgroup);
  129. }
  130. void TDynamicCounters::MergeWithSubgroup(const TString& name, const TString& value) {
  131. auto g = LockForUpdate("MergeWithSubgroup", name, value);
  132. auto it = Counters.find({name, value});
  133. Y_ABORT_UNLESS(it != Counters.end());
  134. TIntrusivePtr<TDynamicCounters> subgroup = AsDynamicCounters(it->second);
  135. Y_ABORT_UNLESS(subgroup);
  136. Counters.erase(it);
  137. Counters.merge(subgroup->Resign());
  138. AtomicAdd(ExpiringCount, AtomicSwap(&subgroup->ExpiringCount, 0));
  139. }
  140. void TDynamicCounters::ResetCounters(bool derivOnly) {
  141. TReadGuard g(Lock);
  142. for (auto& [key, value] : Counters) {
  143. if (auto counter = AsCounter(value)) {
  144. if (!derivOnly || counter->ForDerivative()) {
  145. *counter = 0;
  146. }
  147. } else if (auto subgroup = AsDynamicCounters(value)) {
  148. subgroup->ResetCounters(derivOnly);
  149. }
  150. }
  151. }
  152. void TDynamicCounters::RegisterCountable(const TString& name, const TString& value, TCountablePtr countable) {
  153. Y_ABORT_UNLESS(countable);
  154. auto g = LockForUpdate("RegisterCountable", name, value);
  155. const bool inserted = Counters.emplace(TChildId(name, value), std::move(countable)).second;
  156. Y_ABORT_UNLESS(inserted);
  157. }
  158. void TDynamicCounters::RegisterSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) {
  159. RegisterCountable(name, value, subgroup);
  160. }
  161. void TDynamicCounters::OutputHtml(IOutputStream& os) const {
  162. HTML(os) {
  163. PRE() {
  164. OutputPlainText(os);
  165. }
  166. }
  167. }
  168. void TDynamicCounters::EnumerateSubgroups(const std::function<void(const TString& name, const TString& value)>& output) const {
  169. TReadGuard g(Lock);
  170. for (const auto& [key, value] : Counters) {
  171. if (AsDynamicCounters(value)) {
  172. output(key.LabelName, key.LabelValue);
  173. }
  174. }
  175. }
  176. void TDynamicCounters::OutputPlainText(IOutputStream& os, const TString& indent) const {
  177. auto snap = ReadSnapshot();
  178. // mark private records in plain text output
  179. auto outputVisibilityMarker = [] (EVisibility vis) {
  180. return vis == EVisibility::Private ? "\t[PRIVATE]" : "";
  181. };
  182. for (const auto& [key, value] : snap) {
  183. if (const auto counter = AsCounter(value)) {
  184. os << indent
  185. << key.LabelName << '=' << key.LabelValue
  186. << ": " << counter->Val()
  187. << outputVisibilityMarker(counter->Visibility())
  188. << '\n';
  189. } else if (const auto histogram = AsHistogram(value)) {
  190. os << indent
  191. << key.LabelName << '=' << key.LabelValue
  192. << ":"
  193. << outputVisibilityMarker(histogram->Visibility())
  194. << "\n";
  195. auto snapshot = histogram->Snapshot();
  196. for (ui32 i = 0, count = snapshot->Count(); i < count; i++) {
  197. os << indent << INDENT << TStringBuf("bin=");
  198. TBucketBound bound = snapshot->UpperBound(i);
  199. if (bound == Max<TBucketBound>()) {
  200. os << TStringBuf("inf");
  201. } else {
  202. os << bound;
  203. }
  204. os << ": " << snapshot->Value(i) << '\n';
  205. }
  206. }
  207. }
  208. for (const auto& [key, value] : snap) {
  209. if (const auto subgroup = AsDynamicCounters(value)) {
  210. os << "\n";
  211. os << indent << key.LabelName << "=" << key.LabelValue << ":\n";
  212. subgroup->OutputPlainText(os, indent + INDENT);
  213. }
  214. }
  215. }
  216. void TDynamicCounters::Accept(const TString& labelName, const TString& labelValue, ICountableConsumer& consumer) const {
  217. if (!IsVisible(Visibility(), consumer.Visibility())) {
  218. return;
  219. }
  220. consumer.OnGroupBegin(labelName, labelValue, this);
  221. for (auto& [key, value] : ReadSnapshot()) {
  222. value->Accept(key.LabelName, key.LabelValue, consumer);
  223. }
  224. consumer.OnGroupEnd(labelName, labelValue, this);
  225. }
  226. void TDynamicCounters::RemoveExpired() const {
  227. if (AtomicGet(ExpiringCount) == 0) {
  228. return;
  229. }
  230. TWriteGuard g(Lock);
  231. TAtomicBase count = 0;
  232. for (auto it = Counters.begin(); it != Counters.end();) {
  233. if (IsExpiringCounter(it->second) && it->second->RefCount() == 1) {
  234. it = Counters.erase(it);
  235. ++count;
  236. } else {
  237. ++it;
  238. }
  239. }
  240. AtomicSub(ExpiringCount, count);
  241. }
  242. template <bool expiring, class TCounterType, class... TArgs>
  243. TDynamicCounters::TCountablePtr TDynamicCounters::GetNamedCounterImpl(const TString& name, const TString& value, TArgs&&... args) {
  244. {
  245. TReadGuard g(Lock);
  246. auto it = Counters.find({name, value});
  247. if (it != Counters.end()) {
  248. return it->second;
  249. }
  250. }
  251. auto g = LockForUpdate("GetNamedCounterImpl", name, value);
  252. const TChildId key(name, value);
  253. auto it = Counters.lower_bound(key);
  254. if (it == Counters.end() || it->first != key) {
  255. auto value = MakeIntrusive<TCounterType>(std::forward<TArgs>(args)...);
  256. it = Counters.emplace_hint(it, key, value);
  257. if constexpr (expiring) {
  258. AtomicIncrement(ExpiringCount);
  259. }
  260. }
  261. return it->second;
  262. }
  263. template <class TCounterType>
  264. TDynamicCounters::TCountablePtr TDynamicCounters::FindNamedCounterImpl(const TString& name, const TString& value) const {
  265. TReadGuard g(Lock);
  266. auto it = Counters.find({name, value});
  267. return it != Counters.end() ? it->second : nullptr;
  268. }