metric_registry_ut.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. #include "metric_registry.h"
  2. #include <library/cpp/monlib/encode/protobuf/protobuf.h>
  3. #include <library/cpp/monlib/encode/json/json.h>
  4. #include <library/cpp/resource/resource.h>
  5. #include <library/cpp/testing/unittest/registar.h>
  6. #include <util/stream/str.h>
  7. using namespace NMonitoring;
  8. template<>
  9. void Out<NMonitoring::NProto::TSingleSample::ValueCase>(IOutputStream& os, NMonitoring::NProto::TSingleSample::ValueCase val) {
  10. switch (val) {
  11. case NMonitoring::NProto::TSingleSample::ValueCase::kInt64:
  12. os << "Int64";
  13. break;
  14. case NMonitoring::NProto::TSingleSample::ValueCase::kUint64:
  15. os << "Uint64";
  16. break;
  17. case NMonitoring::NProto::TSingleSample::ValueCase::kHistogram:
  18. os << "Histogram";
  19. break;
  20. case NMonitoring::NProto::TSingleSample::ValueCase::kFloat64:
  21. os << "Float64";
  22. break;
  23. case NMonitoring::NProto::TSingleSample::ValueCase::kSummaryDouble:
  24. os << "DSummary";
  25. break;
  26. case NMonitoring::NProto::TSingleSample::ValueCase::kLogHistogram:
  27. os << "LogHistogram";
  28. break;
  29. case NMonitoring::NProto::TSingleSample::ValueCase::VALUE_NOT_SET:
  30. os << "NOT SET";
  31. break;
  32. }
  33. }
  34. Y_UNIT_TEST_SUITE(TMetricRegistryTest) {
  35. Y_UNIT_TEST(Gauge) {
  36. TMetricRegistry registry(TLabels{{"common", "label"}});
  37. TGauge* g = registry.Gauge({{"my", "gauge"}});
  38. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6);
  39. g->Set(12.34);
  40. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 12.34, 1E-6);
  41. double val;
  42. val = g->Add(1.2);
  43. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 13.54, 1E-6);
  44. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
  45. val = g->Add(-3.47);
  46. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 10.07, 1E-6);
  47. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
  48. }
  49. Y_UNIT_TEST(LazyGauge) {
  50. TMetricRegistry registry(TLabels{{"common", "label"}});
  51. double val = 0.0;
  52. TLazyGauge* g = registry.LazyGauge({{"my", "lazyGauge"}}, [&val](){return val;});
  53. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 0.0, 1E-6);
  54. val = 12.34;
  55. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 12.34, 1E-6);
  56. val += 1.2;
  57. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 13.54, 1E-6);
  58. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
  59. val += -3.47;
  60. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), 10.07, 1E-6);
  61. UNIT_ASSERT_DOUBLES_EQUAL(g->Get(), val, 1E-6);
  62. }
  63. Y_UNIT_TEST(IntGauge) {
  64. TMetricRegistry registry(TLabels{{"common", "label"}});
  65. TIntGauge* g = registry.IntGauge({{"my", "gauge"}});
  66. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
  67. i64 val;
  68. val = g->Inc();
  69. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 1);
  70. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  71. val = g->Dec();
  72. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
  73. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  74. val = g->Add(1);
  75. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 1);
  76. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  77. val = g->Add(2);
  78. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 3);
  79. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  80. val = g->Add(-5);
  81. UNIT_ASSERT_VALUES_EQUAL(g->Get(), -2);
  82. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  83. }
  84. Y_UNIT_TEST(LazyIntGauge) {
  85. TMetricRegistry registry(TLabels{{"common", "label"}});
  86. i64 val = 0;
  87. TLazyIntGauge* g = registry.LazyIntGauge({{"my", "gauge"}}, [&val](){return val;});
  88. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
  89. val += 1;
  90. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 1);
  91. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  92. val -= 1;
  93. UNIT_ASSERT_VALUES_EQUAL(g->Get(), 0);
  94. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  95. val = 42;
  96. UNIT_ASSERT_VALUES_EQUAL(g->Get(), val);
  97. }
  98. Y_UNIT_TEST(Counter) {
  99. TMetricRegistry registry(TLabels{{"common", "label"}});
  100. TCounter* c = registry.Counter({{"my", "counter"}});
  101. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 0);
  102. UNIT_ASSERT_VALUES_EQUAL(c->Inc(), 1);
  103. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 1);
  104. UNIT_ASSERT_VALUES_EQUAL(c->Add(10), 11);
  105. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 11);
  106. }
  107. Y_UNIT_TEST(LazyCounter) {
  108. TMetricRegistry registry(TLabels{{"common", "label"}});
  109. ui64 val = 0;
  110. TLazyCounter* c = registry.LazyCounter({{"my", "counter"}}, [&val](){return val;});
  111. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 0);
  112. val = 42;
  113. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 42);
  114. }
  115. Y_UNIT_TEST(LazyRate) {
  116. TMetricRegistry registry(TLabels{{"common", "label"}});
  117. ui64 val = 0;
  118. TLazyRate* r = registry.LazyRate({{"my", "rate"}}, [&val](){return val;});
  119. UNIT_ASSERT_VALUES_EQUAL(r->Get(), 0);
  120. val = 42;
  121. UNIT_ASSERT_VALUES_EQUAL(r->Get(), 42);
  122. }
  123. Y_UNIT_TEST(DoubleCounter) {
  124. TMetricRegistry registry(TLabels{{"common", "label"}});
  125. TCounter* c = registry.Counter({{"my", "counter"}});
  126. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 0);
  127. c->Add(10);
  128. c = registry.Counter({{"my", "counter"}});
  129. UNIT_ASSERT_VALUES_EQUAL(c->Get(), 10);
  130. }
  131. Y_UNIT_TEST(Sample) {
  132. TMetricRegistry registry(TLabels{{"common", "label"}});
  133. TGauge* g = registry.Gauge({{"my", "gauge"}});
  134. g->Set(12.34);
  135. TCounter* c = registry.Counter({{"my", "counter"}});
  136. c->Add(10);
  137. NProto::TSingleSamplesList samples;
  138. auto encoder = EncoderProtobuf(&samples);
  139. auto now = TInstant::Now();
  140. registry.Accept(now, encoder.Get());
  141. UNIT_ASSERT_VALUES_EQUAL(samples.SamplesSize(), 2);
  142. UNIT_ASSERT_VALUES_EQUAL(samples.CommonLabelsSize(), 1);
  143. {
  144. const NProto::TLabel& label = samples.GetCommonLabels(0);
  145. UNIT_ASSERT_STRINGS_EQUAL(label.GetName(), "common");
  146. UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "label");
  147. }
  148. for (const NProto::TSingleSample& sample : samples.GetSamples()) {
  149. UNIT_ASSERT_VALUES_EQUAL(sample.LabelsSize(), 1);
  150. UNIT_ASSERT_VALUES_EQUAL(sample.GetTime(), now.MilliSeconds());
  151. if (sample.GetMetricType() == NProto::GAUGE) {
  152. UNIT_ASSERT_VALUES_EQUAL(sample.GetValueCase(), NProto::TSingleSample::kFloat64);
  153. UNIT_ASSERT_DOUBLES_EQUAL(sample.GetFloat64(), 12.34, 1E-6);
  154. const NProto::TLabel& label = sample.GetLabels(0);
  155. UNIT_ASSERT_STRINGS_EQUAL(label.GetName(), "my");
  156. UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "gauge");
  157. } else if (sample.GetMetricType() == NProto::COUNTER) {
  158. UNIT_ASSERT_VALUES_EQUAL(sample.GetValueCase(), NProto::TSingleSample::kUint64);
  159. UNIT_ASSERT_VALUES_EQUAL(sample.GetUint64(), 10);
  160. const NProto::TLabel& label = sample.GetLabels(0);
  161. UNIT_ASSERT_STRINGS_EQUAL(label.GetName(), "my");
  162. UNIT_ASSERT_STRINGS_EQUAL(label.GetValue(), "counter");
  163. } else {
  164. UNIT_FAIL("unexpected sample type");
  165. }
  166. }
  167. }
  168. Y_UNIT_TEST(Histograms) {
  169. TMetricRegistry registry(TLabels{{"common", "label"}});
  170. THistogram* h1 = registry.HistogramCounter(
  171. {{"sensor", "readTimeMillis"}},
  172. ExponentialHistogram(5, 2));
  173. THistogram* h2 = registry.HistogramRate(
  174. {{"sensor", "writeTimeMillis"}},
  175. ExplicitHistogram({1, 5, 15, 20, 25}));
  176. for (i64 i = 0; i < 100; i++) {
  177. h1->Record(i);
  178. h2->Record(i);
  179. }
  180. TStringStream ss;
  181. {
  182. auto encoder = EncoderJson(&ss, 2);
  183. registry.Accept(TInstant::Zero(), encoder.Get());
  184. }
  185. ss << '\n';
  186. UNIT_ASSERT_NO_DIFF(ss.Str(), NResource::Find("/histograms.json"));
  187. }
  188. Y_UNIT_TEST(StreamingEncoderTest) {
  189. const TString expected {
  190. "{\"commonLabels\":{\"common\":\"label\"},"
  191. "\"sensors\":[{\"kind\":\"GAUGE\",\"labels\":{\"my\":\"gauge\"},\"value\":12.34}]}"
  192. };
  193. TMetricRegistry registry(TLabels{{"common", "label"}});
  194. TGauge* g = registry.Gauge({{"my", "gauge"}});
  195. g->Set(12.34);
  196. TStringStream os;
  197. auto encoder = EncoderJson(&os);
  198. registry.Accept(TInstant::Zero(), encoder.Get());
  199. UNIT_ASSERT_STRINGS_EQUAL(os.Str(), expected);
  200. }
  201. Y_UNIT_TEST(CreatingSameMetricWithDifferentTypesShouldThrow) {
  202. TMetricRegistry registry;
  203. registry.Gauge({{"foo", "bar"}});
  204. UNIT_ASSERT_EXCEPTION(registry.Counter({{"foo", "bar"}}), yexception);
  205. registry.HistogramCounter({{"bar", "baz"}}, nullptr);
  206. UNIT_ASSERT_EXCEPTION(registry.HistogramRate({{"bar", "baz"}}, nullptr), yexception);
  207. }
  208. Y_UNIT_TEST(EncodeRegistryWithCommonLabels) {
  209. TMetricRegistry registry(TLabels{{"common", "label"}});
  210. TGauge* g = registry.Gauge({{"my", "gauge"}});
  211. g->Set(12.34);
  212. // Append() adds common labels to each metric, allowing to combine
  213. // several metric registries in one resulting blob
  214. {
  215. TStringStream os;
  216. auto encoder = EncoderJson(&os);
  217. encoder->OnStreamBegin();
  218. registry.Append(TInstant::Zero(), encoder.Get());
  219. encoder->OnStreamEnd();
  220. UNIT_ASSERT_STRINGS_EQUAL(
  221. os.Str(),
  222. "{\"sensors\":[{\"kind\":\"GAUGE\",\"labels\":{\"common\":\"label\",\"my\":\"gauge\"},\"value\":12.34}]}");
  223. }
  224. // Accept() adds common labels to the beginning of the blob
  225. {
  226. TStringStream os;
  227. auto encoder = EncoderJson(&os);
  228. registry.Accept(TInstant::Zero(), encoder.Get());
  229. UNIT_ASSERT_STRINGS_EQUAL(
  230. os.Str(),
  231. "{\"commonLabels\":{\"common\":\"label\"},"
  232. "\"sensors\":[{\"kind\":\"GAUGE\",\"labels\":{\"my\":\"gauge\"},\"value\":12.34}]}");
  233. }
  234. }
  235. Y_UNIT_TEST(MetricsRegistryClear) {
  236. TMetricRegistry registry;
  237. registry.Gauge({{"some", "label"}})->Add(1);
  238. NProto::TSingleSamplesList samples;
  239. auto encoder = EncoderProtobuf(&samples);
  240. registry.Accept(TInstant::Now(), encoder.Get());
  241. UNIT_ASSERT(samples.SamplesSize() == 1);
  242. samples = {};
  243. registry.Clear();
  244. registry.Accept(TInstant::Now(), encoder.Get());
  245. UNIT_ASSERT(samples.SamplesSize() == 0);
  246. }
  247. }