aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/monlib/encode/text/text_encoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/cpp/monlib/encode/text/text_encoder.cpp')
-rw-r--r--library/cpp/monlib/encode/text/text_encoder.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/library/cpp/monlib/encode/text/text_encoder.cpp b/library/cpp/monlib/encode/text/text_encoder.cpp
new file mode 100644
index 0000000000..10336261f0
--- /dev/null
+++ b/library/cpp/monlib/encode/text/text_encoder.cpp
@@ -0,0 +1,226 @@
+#include "text.h"
+
+#include <library/cpp/monlib/encode/encoder_state.h>
+#include <library/cpp/monlib/metrics/labels.h>
+#include <library/cpp/monlib/metrics/metric_value.h>
+
+#include <util/datetime/base.h>
+#include <util/stream/format.h>
+
+namespace NMonitoring {
+ namespace {
+ class TEncoderText final: public IMetricEncoder {
+ public:
+ TEncoderText(IOutputStream* out, bool humanReadableTs)
+ : Out_(out)
+ , HumanReadableTs_(humanReadableTs)
+ {
+ }
+
+ private:
+ void OnStreamBegin() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ }
+
+ void OnStreamEnd() override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ }
+
+ void OnCommonTime(TInstant time) override {
+ State_.Expect(TEncoderState::EState::ROOT);
+ CommonTime_ = time;
+ if (time != TInstant::Zero()) {
+ Out_->Write(TStringBuf("common time: "));
+ WriteTime(time);
+ Out_->Write('\n');
+ }
+ }
+
+ void OnMetricBegin(EMetricType type) override {
+ State_.Switch(TEncoderState::EState::ROOT, TEncoderState::EState::METRIC);
+ ClearLastMetricState();
+ MetricType_ = type;
+ }
+
+ void OnMetricEnd() override {
+ State_.Switch(TEncoderState::EState::METRIC, TEncoderState::EState::ROOT);
+ WriteMetric();
+ }
+
+ void OnLabelsBegin() override {
+ if (State_ == TEncoderState::EState::METRIC) {
+ State_ = TEncoderState::EState::METRIC_LABELS;
+ } else if (State_ == TEncoderState::EState::ROOT) {
+ State_ = TEncoderState::EState::COMMON_LABELS;
+ } else {
+ State_.ThrowInvalid("expected METRIC or ROOT");
+ }
+ }
+
+ void OnLabelsEnd() override {
+ if (State_ == TEncoderState::EState::METRIC_LABELS) {
+ State_ = TEncoderState::EState::METRIC;
+ } else if (State_ == TEncoderState::EState::COMMON_LABELS) {
+ State_ = TEncoderState::EState::ROOT;
+ Out_->Write(TStringBuf("common labels: "));
+ WriteLabels();
+ Out_->Write('\n');
+ } else {
+ State_.ThrowInvalid("expected LABELS or COMMON_LABELS");
+ }
+ }
+
+ void OnLabel(TStringBuf name, TStringBuf value) override {
+ Labels_.Add(name, value);
+ }
+
+ void OnDouble(TInstant time, double value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, value);
+ }
+
+ void OnInt64(TInstant time, i64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, value);
+ }
+
+ void OnUint64(TInstant time, ui64 value) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, value);
+ }
+
+ void OnHistogram(TInstant time, IHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, snapshot.Get());
+ }
+
+ void OnSummaryDouble(TInstant time, ISummaryDoubleSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(time, snapshot.Get());
+ }
+
+ void OnLogHistogram(TInstant ts, TLogHistogramSnapshotPtr snapshot) override {
+ State_.Expect(TEncoderState::EState::METRIC);
+ TimeSeries_.Add(ts, snapshot.Get());
+ }
+
+ void Close() override {
+ }
+
+ void WriteTime(TInstant time) {
+ if (HumanReadableTs_) {
+ char buf[64];
+ auto len = FormatDate8601(buf, sizeof(buf), time.TimeT());
+ Out_->Write(buf, len);
+ } else {
+ (*Out_) << time.Seconds();
+ }
+ }
+
+ void WriteValue(EMetricValueType type, TMetricValue value) {
+ switch (type) {
+ case EMetricValueType::DOUBLE:
+ (*Out_) << value.AsDouble();
+ break;
+ case EMetricValueType::INT64:
+ (*Out_) << value.AsInt64();
+ break;
+ case EMetricValueType::UINT64:
+ (*Out_) << value.AsUint64();
+ break;
+ case EMetricValueType::HISTOGRAM:
+ (*Out_) << *value.AsHistogram();
+ break;
+ case EMetricValueType::SUMMARY:
+ (*Out_) << *value.AsSummaryDouble();
+ break;
+ case EMetricValueType::LOGHISTOGRAM:
+ (*Out_) << *value.AsLogHistogram();
+ break;
+ case EMetricValueType::UNKNOWN:
+ ythrow yexception() << "unknown metric value type";
+ }
+ }
+
+ void WriteLabels() {
+ auto& out = *Out_;
+ const auto size = Labels_.Size();
+ size_t i = 0;
+
+ out << '{';
+ for (auto&& l : Labels_) {
+ out << l.Name() << TStringBuf("='") << l.Value() << '\'';
+
+ ++i;
+ if (i < size) {
+ out << TStringBuf(", ");
+ }
+ };
+
+ out << '}';
+ }
+
+ void WriteMetric() {
+ // (1) type
+ TStringBuf typeStr = MetricTypeToStr(MetricType_);
+ (*Out_) << LeftPad(typeStr, MaxMetricTypeNameLength) << ' ';
+
+ // (2) name and labels
+ auto name = Labels_.Extract(TStringBuf("sensor"));
+ if (name) {
+ if (name->Value().find(' ') != TString::npos) {
+ (*Out_) << '"' << name->Value() << '"';
+ } else {
+ (*Out_) << name->Value();
+ }
+ }
+ WriteLabels();
+
+ // (3) values
+ if (!TimeSeries_.Empty()) {
+ TimeSeries_.SortByTs();
+ Out_->Write(TStringBuf(" ["));
+ for (size_t i = 0; i < TimeSeries_.Size(); i++) {
+ if (i > 0) {
+ Out_->Write(TStringBuf(", "));
+ }
+
+ const auto& point = TimeSeries_[i];
+ if (point.GetTime() == CommonTime_ || point.GetTime() == TInstant::Zero()) {
+ WriteValue(TimeSeries_.GetValueType(), point.GetValue());
+ } else {
+ Out_->Write('(');
+ WriteTime(point.GetTime());
+ Out_->Write(TStringBuf(", "));
+ WriteValue(TimeSeries_.GetValueType(), point.GetValue());
+ Out_->Write(')');
+ }
+ }
+ Out_->Write(']');
+ }
+ Out_->Write('\n');
+ }
+
+ void ClearLastMetricState() {
+ MetricType_ = EMetricType::UNKNOWN;
+ Labels_.Clear();
+ TimeSeries_.Clear();
+ }
+
+ private:
+ TEncoderState State_;
+ IOutputStream* Out_;
+ bool HumanReadableTs_;
+ TInstant CommonTime_ = TInstant::Zero();
+ EMetricType MetricType_ = EMetricType::UNKNOWN;
+ TLabels Labels_;
+ TMetricTimeSeries TimeSeries_;
+ };
+
+ }
+
+ IMetricEncoderPtr EncoderText(IOutputStream* out, bool humanReadableTs) {
+ return MakeHolder<TEncoderText>(out, humanReadableTs);
+ }
+
+}