#include "encode.h" #include #include #include #include #include namespace NMonitoring { namespace { constexpr TInstant ZERO_TIME = TInstant::Zero(); class TConsumer final: public ICountableConsumer { using TLabel = std::pair; // 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(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 ParentLabels_; TCountableBase::EVisibility Visibility_; }; } THolder CreateEncoder(IOutputStream* out, EFormat format, TStringBuf nameLabel, TCountableBase::EVisibility vis) { switch (format) { case EFormat::JSON: return MakeHolder(NMonitoring::EncoderJson(out), vis); case EFormat::SPACK: return MakeHolder(NMonitoring::EncoderSpackV1( out, NMonitoring::ETimePrecision::SECONDS, NMonitoring::ECompression::ZSTD), vis); case EFormat::PROMETHEUS: return MakeHolder(NMonitoring::EncoderPrometheus( out, nameLabel), vis); default: ythrow yexception() << "unsupported metric encoding format: " << format; break; } } THolder AsCountableConsumer(IMetricEncoderPtr encoder, TCountableBase::EVisibility visibility) { return MakeHolder(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(); } }