json_encoder.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. #include "json.h"
  2. #include "typed_point.h"
  3. #include <library/cpp/monlib/encode/buffered/buffered_encoder_base.h>
  4. #include <library/cpp/monlib/encode/encoder_state.h>
  5. #include <library/cpp/monlib/metrics/metric.h>
  6. #include <library/cpp/monlib/metrics/metric_value.h>
  7. #include <library/cpp/monlib/metrics/labels.h>
  8. #include <library/cpp/json/writer/json.h>
  9. #include <util/charset/utf8.h>
  10. #include <util/generic/algorithm.h>
  11. namespace NMonitoring {
  12. namespace {
  13. enum class EJsonStyle {
  14. Solomon,
  15. Cloud
  16. };
  17. ///////////////////////////////////////////////////////////////////////
  18. // TJsonWriter
  19. ///////////////////////////////////////////////////////////////////////
  20. class TJsonWriter {
  21. public:
  22. TJsonWriter(IOutputStream* out, int indentation, EJsonStyle style, TStringBuf metricNameLabel)
  23. : Buf_(NJsonWriter::HEM_UNSAFE, out)
  24. , Style_(style)
  25. , MetricNameLabel_(metricNameLabel)
  26. , CurrentMetricName_()
  27. {
  28. Buf_.SetIndentSpaces(indentation);
  29. Buf_.SetWriteNanAsString();
  30. }
  31. void WriteTime(TInstant time) {
  32. if (time != TInstant::Zero()) {
  33. Buf_.WriteKey(TStringBuf("ts"));
  34. if (Style_ == EJsonStyle::Solomon) {
  35. Buf_.WriteULongLong(time.Seconds());
  36. } else {
  37. Buf_.WriteString(time.ToString());
  38. }
  39. }
  40. }
  41. void WriteValue(double value) {
  42. Buf_.WriteKey(TStringBuf("value"));
  43. Buf_.WriteDouble(value);
  44. }
  45. void WriteValue(i64 value) {
  46. Buf_.WriteKey(TStringBuf("value"));
  47. Buf_.WriteLongLong(value);
  48. }
  49. void WriteValue(ui64 value) {
  50. Buf_.WriteKey(TStringBuf("value"));
  51. Buf_.WriteULongLong(value);
  52. }
  53. void WriteValue(IHistogramSnapshot* s) {
  54. Y_ENSURE(Style_ == EJsonStyle::Solomon);
  55. Buf_.WriteKey(TStringBuf("hist"));
  56. Buf_.BeginObject();
  57. if (ui32 count = s->Count()) {
  58. bool hasInf = (s->UpperBound(count - 1) == Max<double>());
  59. if (hasInf) {
  60. count--;
  61. }
  62. Buf_.WriteKey(TStringBuf("bounds"));
  63. Buf_.BeginList();
  64. for (ui32 i = 0; i < count; i++) {
  65. Buf_.WriteDouble(s->UpperBound(i));
  66. }
  67. Buf_.EndList();
  68. Buf_.WriteKey(TStringBuf("buckets"));
  69. Buf_.BeginList();
  70. for (ui32 i = 0; i < count; i++) {
  71. Buf_.WriteULongLong(s->Value(i));
  72. }
  73. Buf_.EndList();
  74. if (hasInf) {
  75. Buf_.WriteKey(TStringBuf("inf"));
  76. Buf_.WriteULongLong(s->Value(count));
  77. }
  78. }
  79. Buf_.EndObject();
  80. }
  81. void WriteValue(ISummaryDoubleSnapshot* s) {
  82. Y_ENSURE(Style_ == EJsonStyle::Solomon);
  83. Buf_.WriteKey(TStringBuf("summary"));
  84. Buf_.BeginObject();
  85. Buf_.WriteKey(TStringBuf("sum"));
  86. Buf_.WriteDouble(s->GetSum());
  87. Buf_.WriteKey(TStringBuf("min"));
  88. Buf_.WriteDouble(s->GetMin());
  89. Buf_.WriteKey(TStringBuf("max"));
  90. Buf_.WriteDouble(s->GetMax());
  91. Buf_.WriteKey(TStringBuf("last"));
  92. Buf_.WriteDouble(s->GetLast());
  93. Buf_.WriteKey(TStringBuf("count"));
  94. Buf_.WriteULongLong(s->GetCount());
  95. Buf_.EndObject();
  96. }
  97. void WriteValue(TLogHistogramSnapshot* s) {
  98. Y_ENSURE(Style_ == EJsonStyle::Solomon);
  99. Buf_.WriteKey(TStringBuf("log_hist"));
  100. Buf_.BeginObject();
  101. Buf_.WriteKey(TStringBuf("base"));
  102. Buf_.WriteDouble(s->Base());
  103. Buf_.WriteKey(TStringBuf("zeros_count"));
  104. Buf_.WriteULongLong(s->ZerosCount());
  105. Buf_.WriteKey(TStringBuf("start_power"));
  106. Buf_.WriteInt(s->StartPower());
  107. Buf_.WriteKey(TStringBuf("buckets"));
  108. Buf_.BeginList();
  109. for (size_t i = 0; i < s->Count(); ++i) {
  110. Buf_.WriteDouble(s->Bucket(i));
  111. }
  112. Buf_.EndList();
  113. Buf_.EndObject();
  114. }
  115. void WriteValue(EMetricValueType type, TMetricValue value) {
  116. switch (type) {
  117. case EMetricValueType::DOUBLE:
  118. WriteValue(value.AsDouble());
  119. break;
  120. case EMetricValueType::INT64:
  121. WriteValue(value.AsInt64());
  122. break;
  123. case EMetricValueType::UINT64:
  124. WriteValue(value.AsUint64());
  125. break;
  126. case EMetricValueType::HISTOGRAM:
  127. WriteValue(value.AsHistogram());
  128. break;
  129. case EMetricValueType::SUMMARY:
  130. WriteValue(value.AsSummaryDouble());
  131. break;
  132. case EMetricValueType::LOGHISTOGRAM:
  133. WriteValue(value.AsLogHistogram());
  134. break;
  135. case EMetricValueType::UNKNOWN:
  136. ythrow yexception() << "unknown metric value type";
  137. }
  138. }
  139. void WriteLabel(TStringBuf name, TStringBuf value) {
  140. Y_ENSURE(IsUtf(name), "label name is not valid UTF-8 string");
  141. Y_ENSURE(IsUtf(value), "label value is not valid UTF-8 string");
  142. if (Style_ == EJsonStyle::Cloud && name == MetricNameLabel_) {
  143. CurrentMetricName_ = value;
  144. } else {
  145. Buf_.WriteKey(name);
  146. Buf_.WriteString(value);
  147. }
  148. }
  149. void WriteMetricType(EMetricType type) {
  150. if (Style_ == EJsonStyle::Cloud) {
  151. Buf_.WriteKey("type");
  152. Buf_.WriteString(MetricTypeToCloudStr(type));
  153. } else {
  154. Buf_.WriteKey("kind");
  155. Buf_.WriteString(MetricTypeToStr(type));
  156. }
  157. }
  158. void WriteName() {
  159. if (Style_ != EJsonStyle::Cloud) {
  160. return;
  161. }
  162. if (CurrentMetricName_.Empty()) {
  163. ythrow yexception() << "label '" << MetricNameLabel_ << "' is not defined";
  164. }
  165. Buf_.WriteKey("name");
  166. Buf_.WriteString(CurrentMetricName_);
  167. CurrentMetricName_.clear();
  168. }
  169. private:
  170. static TStringBuf MetricTypeToCloudStr(EMetricType type) {
  171. switch (type) {
  172. case EMetricType::GAUGE:
  173. return TStringBuf("DGAUGE");
  174. case EMetricType::COUNTER:
  175. return TStringBuf("COUNTER");
  176. case EMetricType::RATE:
  177. return TStringBuf("RATE");
  178. case EMetricType::IGAUGE:
  179. return TStringBuf("IGAUGE");
  180. default:
  181. ythrow yexception() << "metric type '" << type << "' is not supported by cloud json format";
  182. }
  183. }
  184. protected:
  185. NJsonWriter::TBuf Buf_;
  186. EJsonStyle Style_;
  187. TString MetricNameLabel_;
  188. TString CurrentMetricName_;
  189. };
  190. ///////////////////////////////////////////////////////////////////////
  191. // TEncoderJson
  192. ///////////////////////////////////////////////////////////////////////
  193. class TEncoderJson final: public IMetricEncoder, public TJsonWriter {
  194. public:
  195. TEncoderJson(IOutputStream* out, int indentation, EJsonStyle style, TStringBuf metricNameLabel)
  196. : TJsonWriter{out, indentation, style, metricNameLabel}
  197. {
  198. }
  199. ~TEncoderJson() override {
  200. Close();
  201. }
  202. private:
  203. void OnStreamBegin() override {
  204. State_.Expect(TEncoderState::EState::ROOT);
  205. Buf_.BeginObject();
  206. }
  207. void OnStreamEnd() override {
  208. State_.Expect(TEncoderState::EState::ROOT);
  209. if (!Buf_.KeyExpected()) {
  210. // not closed metrics array
  211. Buf_.EndList();
  212. }
  213. Buf_.EndObject();
  214. }
  215. void OnCommonTime(TInstant time) override {
  216. State_.Expect(TEncoderState::EState::ROOT);
  217. WriteTime(time);
  218. }
  219. void OnMetricBegin(EMetricType type) override {
  220. State_.Switch(TEncoderState::EState::ROOT, TEncoderState::EState::METRIC);
  221. if (Buf_.KeyExpected()) {
  222. // first metric, so open metrics array
  223. Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "sensors" : "metrics"));
  224. Buf_.BeginList();
  225. }
  226. Buf_.BeginObject();
  227. WriteMetricType(type);
  228. }
  229. void OnMetricEnd() override {
  230. State_.Switch(TEncoderState::EState::METRIC, TEncoderState::EState::ROOT);
  231. if (!Buf_.KeyExpected()) {
  232. // not closed timeseries array
  233. Buf_.EndList();
  234. }
  235. if (!TimeSeries_ && LastPoint_.HasValue()) {
  236. // we have seen only one point between OnMetricBegin() and
  237. // OnMetricEnd() calls
  238. WriteTime(LastPoint_.GetTime());
  239. WriteValue(LastPoint_.GetValueType(), LastPoint_.GetValue());
  240. }
  241. Buf_.EndObject();
  242. LastPoint_ = {};
  243. TimeSeries_ = false;
  244. }
  245. void OnLabelsBegin() override {
  246. if (!Buf_.KeyExpected()) {
  247. // not closed metrics or timeseries array if labels go after values
  248. Buf_.EndList();
  249. }
  250. if (State_ == TEncoderState::EState::ROOT) {
  251. State_ = TEncoderState::EState::COMMON_LABELS;
  252. Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "commonLabels" : "labels"));
  253. } else if (State_ == TEncoderState::EState::METRIC) {
  254. State_ = TEncoderState::EState::METRIC_LABELS;
  255. Buf_.WriteKey(TStringBuf("labels"));
  256. } else {
  257. State_.ThrowInvalid("expected METRIC or ROOT");
  258. }
  259. Buf_.BeginObject();
  260. EmptyLabels_ = true;
  261. }
  262. void OnLabelsEnd() override {
  263. if (State_ == TEncoderState::EState::METRIC_LABELS) {
  264. State_ = TEncoderState::EState::METRIC;
  265. } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
  266. State_ = TEncoderState::EState::ROOT;
  267. } else {
  268. State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
  269. }
  270. Y_ENSURE(!EmptyLabels_, "Labels cannot be empty");
  271. Buf_.EndObject();
  272. if (State_ == TEncoderState::EState::METRIC) {
  273. WriteName();
  274. }
  275. }
  276. void OnLabel(TStringBuf name, TStringBuf value) override {
  277. if (State_ == TEncoderState::EState::METRIC_LABELS || State_ == TEncoderState::EState::COMMON_LABELS) {
  278. WriteLabel(name, value);
  279. } else {
  280. State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
  281. }
  282. EmptyLabels_ = false;
  283. }
  284. void OnDouble(TInstant time, double value) override {
  285. State_.Expect(TEncoderState::EState::METRIC);
  286. Write<double>(time, value);
  287. }
  288. void OnInt64(TInstant time, i64 value) override {
  289. State_.Expect(TEncoderState::EState::METRIC);
  290. Write<i64>(time, value);
  291. }
  292. void OnUint64(TInstant time, ui64 value) override {
  293. State_.Expect(TEncoderState::EState::METRIC);
  294. Write<ui64>(time, value);
  295. }
  296. void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
  297. State_.Expect(TEncoderState::EState::METRIC);
  298. Write<IHistogramSnapshot*>(time, snapshot.Get());
  299. }
  300. void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
  301. State_.Expect(TEncoderState::EState::METRIC);
  302. Write<ISummaryDoubleSnapshot*>(time, snapshot.Get());
  303. }
  304. void OnLogHistogram(TInstant time, TLogHistogramSnapshotPtr snapshot) override {
  305. State_.Expect(TEncoderState::EState::METRIC);
  306. Write<TLogHistogramSnapshot*>(time, snapshot.Get());
  307. }
  308. template <typename T>
  309. void Write(TInstant time, T value) {
  310. State_.Expect(TEncoderState::EState::METRIC);
  311. if (!LastPoint_.HasValue()) {
  312. LastPoint_ = {time, value};
  313. } else {
  314. // second point
  315. // TODO: output types
  316. Y_ENSURE(LastPoint_.GetValueType() == TValueType<T>::Type,
  317. "mixed metric value types in one metric");
  318. if (!TimeSeries_) {
  319. Buf_.WriteKey(TStringBuf("timeseries"));
  320. Buf_.BeginList();
  321. Buf_.BeginObject();
  322. Y_ENSURE(LastPoint_.GetTime() != TInstant::Zero(),
  323. "time cannot be empty or zero in a timeseries point");
  324. WriteTime(LastPoint_.GetTime());
  325. WriteValue(LastPoint_.GetValueType(), LastPoint_.GetValue());
  326. Buf_.EndObject();
  327. TimeSeries_ = true;
  328. }
  329. if (TimeSeries_) {
  330. Buf_.BeginObject();
  331. Y_ENSURE(time != TInstant::Zero(),
  332. "time cannot be empty or zero in a timeseries point");
  333. WriteTime(time);
  334. WriteValue(value);
  335. Buf_.EndObject();
  336. }
  337. }
  338. }
  339. void Close() override {
  340. LastPoint_ = {};
  341. }
  342. private:
  343. TEncoderState State_;
  344. TTypedPoint LastPoint_;
  345. bool TimeSeries_ = false;
  346. bool EmptyLabels_ = false;
  347. };
  348. ///////////////////////////////////////////////////////////////////////
  349. // TBufferedJsonEncoder
  350. ///////////////////////////////////////////////////////////////////////
  351. class TBufferedJsonEncoder : public TBufferedEncoderBase, public TJsonWriter {
  352. public:
  353. TBufferedJsonEncoder(IOutputStream* out, int indentation, EJsonStyle style, TStringBuf metricNameLabel)
  354. : TJsonWriter{out, indentation, style, metricNameLabel}
  355. {
  356. MetricsMergingMode_ = EMetricsMergingMode::MERGE_METRICS;
  357. }
  358. ~TBufferedJsonEncoder() override {
  359. Close();
  360. }
  361. void OnLabelsBegin() override {
  362. TBufferedEncoderBase::OnLabelsBegin();
  363. EmptyLabels_ = true;
  364. }
  365. void OnLabel(TStringBuf name, TStringBuf value) override {
  366. TBufferedEncoderBase::OnLabel(name, value);
  367. EmptyLabels_ = false;
  368. }
  369. void OnLabel(ui32 name, ui32 value) override {
  370. TBufferedEncoderBase::OnLabel(name, value);
  371. EmptyLabels_ = false;
  372. }
  373. void OnLabelsEnd() override {
  374. TBufferedEncoderBase::OnLabelsEnd();
  375. Y_ENSURE(!EmptyLabels_, "Labels cannot be empty");
  376. }
  377. void Close() final {
  378. if (Closed_) {
  379. return;
  380. }
  381. Closed_ = true;
  382. LabelValuesPool_.Build();
  383. LabelNamesPool_.Build();
  384. Buf_.BeginObject();
  385. WriteTime(CommonTime_);
  386. if (CommonLabels_.size() > 0) {
  387. Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "commonLabels": "labels"));
  388. WriteLabels(CommonLabels_, true);
  389. }
  390. if (Metrics_.size() > 0) {
  391. Buf_.WriteKey(TStringBuf(Style_ == EJsonStyle::Solomon ? "sensors" : "metrics"));
  392. WriteMetrics();
  393. }
  394. Buf_.EndObject();
  395. }
  396. private:
  397. void WriteMetrics() {
  398. Buf_.BeginList();
  399. for (auto&& metric : Metrics_) {
  400. WriteMetric(metric);
  401. }
  402. Buf_.EndList();
  403. }
  404. void WriteMetric(TMetric& metric) {
  405. Buf_.BeginObject();
  406. WriteMetricType(metric.MetricType);
  407. Buf_.WriteKey(TStringBuf("labels"));
  408. WriteLabels(metric.Labels, false);
  409. metric.TimeSeries.SortByTs();
  410. if (metric.TimeSeries.Size() == 1) {
  411. const auto& point = metric.TimeSeries[0];
  412. WriteTime(point.GetTime());
  413. WriteValue(metric.TimeSeries.GetValueType(), point.GetValue());
  414. } else if (metric.TimeSeries.Size() > 1) {
  415. Buf_.WriteKey(TStringBuf("timeseries"));
  416. Buf_.BeginList();
  417. metric.TimeSeries.ForEach([this](TInstant time, EMetricValueType type, TMetricValue value) {
  418. Buf_.BeginObject();
  419. // make gcc 6.1 happy https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636
  420. this->WriteTime(time);
  421. this->WriteValue(type, value);
  422. Buf_.EndObject();
  423. });
  424. Buf_.EndList();
  425. }
  426. Buf_.EndObject();
  427. }
  428. void WriteLabels(const TPooledLabels& labels, bool isCommon) {
  429. Buf_.BeginObject();
  430. for (auto i = 0u; i < labels.size(); ++i) {
  431. TStringBuf name = LabelNamesPool_.Get(labels[i].Key->Index);
  432. TStringBuf value = LabelValuesPool_.Get(labels[i].Value->Index);
  433. WriteLabel(name, value);
  434. }
  435. Buf_.EndObject();
  436. if (!isCommon) {
  437. WriteName();
  438. }
  439. }
  440. private:
  441. bool Closed_{false};
  442. bool EmptyLabels_ = false;
  443. };
  444. }
  445. IMetricEncoderPtr EncoderJson(IOutputStream* out, int indentation) {
  446. return MakeHolder<TEncoderJson>(out, indentation, EJsonStyle::Solomon, "");
  447. }
  448. IMetricEncoderPtr BufferedEncoderJson(IOutputStream* out, int indentation) {
  449. return MakeHolder<TBufferedJsonEncoder>(out, indentation, EJsonStyle::Solomon, "");
  450. }
  451. IMetricEncoderPtr EncoderCloudJson(IOutputStream* out, int indentation, TStringBuf metricNameLabel) {
  452. return MakeHolder<TEncoderJson>(out, indentation, EJsonStyle::Cloud, metricNameLabel);
  453. }
  454. IMetricEncoderPtr BufferedEncoderCloudJson(IOutputStream* out, int indentation, TStringBuf metricNameLabel) {
  455. return MakeHolder<TBufferedJsonEncoder>(out, indentation, EJsonStyle::Cloud, metricNameLabel);
  456. }
  457. }