counters.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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. void 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. }
  86. TIntrusivePtr<TDynamicCounters> TDynamicCounters::GetSubgroup(const TString& name, const TString& value) {
  87. auto res = FindSubgroup(name, value);
  88. if (!res) {
  89. auto g = LockForUpdate("GetSubgroup", name, value);
  90. const TChildId key(name, value);
  91. if (const auto it = Counters.lower_bound(key); it != Counters.end() && it->first == key) {
  92. res = AsGroupRef(it->second);
  93. } else {
  94. res = MakeIntrusive<TDynamicCounters>(this);
  95. Counters.emplace_hint(it, key, res);
  96. }
  97. }
  98. return res;
  99. }
  100. TIntrusivePtr<TDynamicCounters> TDynamicCounters::FindSubgroup(const TString& name, const TString& value) const {
  101. TReadGuard g(Lock);
  102. const auto it = Counters.find({name, value});
  103. return it != Counters.end() ? AsDynamicCounters(it->second) : nullptr;
  104. }
  105. void TDynamicCounters::RemoveSubgroup(const TString& name, const TString& value) {
  106. auto g = LockForUpdate("RemoveSubgroup", name, value);
  107. if (const auto it = Counters.find({name, value}); it != Counters.end() && AsDynamicCounters(it->second)) {
  108. Counters.erase(it);
  109. }
  110. }
  111. void TDynamicCounters::ReplaceSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) {
  112. auto g = LockForUpdate("ReplaceSubgroup", name, value);
  113. const auto it = Counters.find({name, value});
  114. Y_VERIFY(it != Counters.end() && AsDynamicCounters(it->second));
  115. it->second = std::move(subgroup);
  116. }
  117. void TDynamicCounters::MergeWithSubgroup(const TString& name, const TString& value) {
  118. auto g = LockForUpdate("MergeWithSubgroup", name, value);
  119. auto it = Counters.find({name, value});
  120. Y_VERIFY(it != Counters.end());
  121. TIntrusivePtr<TDynamicCounters> subgroup = AsDynamicCounters(it->second);
  122. Y_VERIFY(subgroup);
  123. Counters.erase(it);
  124. Counters.merge(subgroup->Resign());
  125. AtomicAdd(ExpiringCount, AtomicSwap(&subgroup->ExpiringCount, 0));
  126. }
  127. void TDynamicCounters::ResetCounters(bool derivOnly) {
  128. TReadGuard g(Lock);
  129. for (auto& [key, value] : Counters) {
  130. if (auto counter = AsCounter(value)) {
  131. if (!derivOnly || counter->ForDerivative()) {
  132. *counter = 0;
  133. }
  134. } else if (auto subgroup = AsDynamicCounters(value)) {
  135. subgroup->ResetCounters(derivOnly);
  136. }
  137. }
  138. }
  139. void TDynamicCounters::RegisterCountable(const TString& name, const TString& value, TCountablePtr countable) {
  140. Y_VERIFY(countable);
  141. auto g = LockForUpdate("RegisterCountable", name, value);
  142. const bool inserted = Counters.emplace(TChildId(name, value), std::move(countable)).second;
  143. Y_VERIFY(inserted);
  144. }
  145. void TDynamicCounters::RegisterSubgroup(const TString& name, const TString& value, TIntrusivePtr<TDynamicCounters> subgroup) {
  146. RegisterCountable(name, value, subgroup);
  147. }
  148. void TDynamicCounters::OutputHtml(IOutputStream& os) const {
  149. HTML(os) {
  150. PRE() {
  151. OutputPlainText(os);
  152. }
  153. }
  154. }
  155. void TDynamicCounters::EnumerateSubgroups(const std::function<void(const TString& name, const TString& value)>& output) const {
  156. TReadGuard g(Lock);
  157. for (const auto& [key, value] : Counters) {
  158. if (AsDynamicCounters(value)) {
  159. output(key.LabelName, key.LabelValue);
  160. }
  161. }
  162. }
  163. void TDynamicCounters::OutputPlainText(IOutputStream& os, const TString& indent) const {
  164. auto snap = ReadSnapshot();
  165. // mark private records in plain text output
  166. auto outputVisibilityMarker = [] (EVisibility vis) {
  167. return vis == EVisibility::Private ? "\t[PRIVATE]" : "";
  168. };
  169. for (const auto& [key, value] : snap) {
  170. if (const auto counter = AsCounter(value)) {
  171. os << indent
  172. << key.LabelName << '=' << key.LabelValue
  173. << ": " << counter->Val()
  174. << outputVisibilityMarker(counter->Visibility())
  175. << '\n';
  176. } else if (const auto histogram = AsHistogram(value)) {
  177. os << indent
  178. << key.LabelName << '=' << key.LabelValue
  179. << ":"
  180. << outputVisibilityMarker(histogram->Visibility())
  181. << "\n";
  182. auto snapshot = histogram->Snapshot();
  183. for (ui32 i = 0, count = snapshot->Count(); i < count; i++) {
  184. os << indent << INDENT << TStringBuf("bin=");
  185. TBucketBound bound = snapshot->UpperBound(i);
  186. if (bound == Max<TBucketBound>()) {
  187. os << TStringBuf("inf");
  188. } else {
  189. os << bound;
  190. }
  191. os << ": " << snapshot->Value(i) << '\n';
  192. }
  193. }
  194. }
  195. for (const auto& [key, value] : snap) {
  196. if (const auto subgroup = AsDynamicCounters(value)) {
  197. os << "\n";
  198. os << indent << key.LabelName << "=" << key.LabelValue << ":\n";
  199. subgroup->OutputPlainText(os, indent + INDENT);
  200. }
  201. }
  202. }
  203. void TDynamicCounters::Accept(const TString& labelName, const TString& labelValue, ICountableConsumer& consumer) const {
  204. if (!IsVisible(Visibility(), consumer.Visibility())) {
  205. return;
  206. }
  207. consumer.OnGroupBegin(labelName, labelValue, this);
  208. for (auto& [key, value] : ReadSnapshot()) {
  209. value->Accept(key.LabelName, key.LabelValue, consumer);
  210. }
  211. consumer.OnGroupEnd(labelName, labelValue, this);
  212. }
  213. void TDynamicCounters::RemoveExpired() const {
  214. if (AtomicGet(ExpiringCount) == 0) {
  215. return;
  216. }
  217. TWriteGuard g(Lock);
  218. TAtomicBase count = 0;
  219. for (auto it = Counters.begin(); it != Counters.end();) {
  220. if (IsExpiringCounter(it->second) && it->second->RefCount() == 1) {
  221. it = Counters.erase(it);
  222. ++count;
  223. } else {
  224. ++it;
  225. }
  226. }
  227. AtomicSub(ExpiringCount, count);
  228. }
  229. template <bool expiring, class TCounterType, class... TArgs>
  230. TDynamicCounters::TCountablePtr TDynamicCounters::GetNamedCounterImpl(const TString& name, const TString& value, TArgs&&... args) {
  231. {
  232. TReadGuard g(Lock);
  233. auto it = Counters.find({name, value});
  234. if (it != Counters.end()) {
  235. return it->second;
  236. }
  237. }
  238. auto g = LockForUpdate("GetNamedCounterImpl", name, value);
  239. const TChildId key(name, value);
  240. auto it = Counters.lower_bound(key);
  241. if (it == Counters.end() || it->first != key) {
  242. auto value = MakeIntrusive<TCounterType>(std::forward<TArgs>(args)...);
  243. it = Counters.emplace_hint(it, key, value);
  244. if constexpr (expiring) {
  245. AtomicIncrement(ExpiringCount);
  246. }
  247. }
  248. return it->second;
  249. }
  250. template <class TCounterType>
  251. TDynamicCounters::TCountablePtr TDynamicCounters::FindNamedCounterImpl(const TString& name, const TString& value) const {
  252. TReadGuard g(Lock);
  253. auto it = Counters.find({name, value});
  254. return it != Counters.end() ? it->second : nullptr;
  255. }