aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/monlib/dynamic_counters/encode.cpp
blob: 265a505fb6cbd866bc05a8d7ee25716addd6d0eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "encode.h"

#include <library/cpp/monlib/encode/encoder.h>
#include <library/cpp/monlib/encode/json/json.h>
#include <library/cpp/monlib/encode/spack/spack_v1.h>
#include <library/cpp/monlib/encode/prometheus/prometheus.h>

#include <util/stream/str.h>

namespace NMonitoring {
    namespace {
        constexpr TInstant ZERO_TIME = TInstant::Zero();

        class TConsumer final: public ICountableConsumer {
            using TLabel = std::pair<TString, TString>; // name, value

        public:
            explicit TConsumer(NMonitoring::IMetricEncoderPtr encoderImpl, TCountableBase::EVisibility vis)
                : EncoderImpl_(std::move(encoderImpl))
                , Visibility_{vis}
            {
            }

            void OnCounter(
                const TString& labelName, const TString& labelValue,
                const TCounterForPtr* counter) override {
                NMonitoring::EMetricType metricType = counter->ForDerivative()
                                                          ? NMonitoring::EMetricType::RATE
                                                          : NMonitoring::EMetricType::GAUGE;
                EncoderImpl_->OnMetricBegin(metricType);
                EncodeLabels(labelName, labelValue);

                if (metricType == NMonitoring::EMetricType::GAUGE) {
                    EncoderImpl_->OnDouble(ZERO_TIME, static_cast<double>(counter->Val()));
                } else {
                    EncoderImpl_->OnUint64(ZERO_TIME, counter->Val());
                }

                EncoderImpl_->OnMetricEnd();
            }

            void OnHistogram(
                const TString& labelName, const TString& labelValue,
                IHistogramSnapshotPtr snapshot, bool derivative) override {
                NMonitoring::EMetricType metricType = derivative ? EMetricType::HIST_RATE : EMetricType::HIST;

                EncoderImpl_->OnMetricBegin(metricType);
                EncodeLabels(labelName, labelValue);
                EncoderImpl_->OnHistogram(ZERO_TIME, snapshot);
                EncoderImpl_->OnMetricEnd();
            }

            void OnGroupBegin(
                const TString& labelName, const TString& labelValue,
                const TDynamicCounters*) override {
                if (labelName.empty() && labelValue.empty()) {
                    // root group has empty label name and value
                    EncoderImpl_->OnStreamBegin();
                } else {
                    ParentLabels_.emplace_back(labelName, labelValue);
                }
            }

            void OnGroupEnd(
                const TString& labelName, const TString& labelValue,
                const TDynamicCounters*) override {
                if (labelName.empty() && labelValue.empty()) {
                    // root group has empty label name and value
                    EncoderImpl_->OnStreamEnd();
                    EncoderImpl_->Close();
                } else {
                    ParentLabels_.pop_back();
                }
            }

            TCountableBase::EVisibility Visibility() const override {
                return Visibility_;
            }

        private:
            void EncodeLabels(const TString& labelName, const TString& labelValue) {
                EncoderImpl_->OnLabelsBegin();
                for (const auto& label : ParentLabels_) {
                    EncoderImpl_->OnLabel(label.first, label.second);
                }
                EncoderImpl_->OnLabel(labelName, labelValue);
                EncoderImpl_->OnLabelsEnd();
            }

        private:
            NMonitoring::IMetricEncoderPtr EncoderImpl_;
            TVector<TLabel> ParentLabels_;
            TCountableBase::EVisibility Visibility_;
        };

    }

    THolder<ICountableConsumer> CreateEncoder(IOutputStream* out, EFormat format, TCountableBase::EVisibility vis) {
        switch (format) {
            case EFormat::JSON:
                return MakeHolder<TConsumer>(NMonitoring::EncoderJson(out), vis); 
            case EFormat::SPACK:
                return MakeHolder<TConsumer>(NMonitoring::EncoderSpackV1( 
                    out,
                    NMonitoring::ETimePrecision::SECONDS,
                    NMonitoring::ECompression::ZSTD), vis);
            case EFormat::PROMETHEUS:
                return MakeHolder<TConsumer>(NMonitoring::EncoderPrometheus(
                    out), vis);
            default:
                ythrow yexception() << "unsupported metric encoding format: " << format;
                break;
        }
    }

    THolder<ICountableConsumer> AsCountableConsumer(IMetricEncoderPtr encoder, TCountableBase::EVisibility visibility) {
        return MakeHolder<TConsumer>(std::move(encoder), visibility);
    }

    void ToJson(const TDynamicCounters& counters, IOutputStream* out) {
        TConsumer consumer{EncoderJson(out), TCountableBase::EVisibility::Public};
        counters.Accept(TString{}, TString{}, consumer);
    }

    TString ToJson(const TDynamicCounters& counters) {
        TStringStream ss;
        ToJson(counters, &ss);
        return ss.Str();
    }

}