-
Notifications
You must be signed in to change notification settings - Fork 24
Add OpenTelemetry lib and metric-interfaces #588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,10 @@ find_package(base64 REQUIRED) | |
| find_package(Brotli 1.1.0 REQUIRED) | ||
| find_package(jwt-cpp REQUIRED) | ||
| find_package(double-conversion REQUIRED) | ||
| find_package(opentelemetry-cpp QUIET) | ||
| if (opentelemetry-cpp_FOUND) | ||
| set(YDB_SDK_HAS_OPEN_TELEMETRY ON) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Мне кажется это не совсем правильный подход. Мы не должны опираться на то, есть ли либа в системе или нет. Установка либ в C++ и так кошмар, а если мы еще завяжем подключение компоненты SDK на наличие либы которая фиг пойми как ищется, пользователь точно с ума сойдет. Более user-frendly подход тут, чтобы источником правды были желания пользователя. Если ему нужен otel-metrics, значит собираем не смотря ни на что. Если нет зависимости - кидаем понятную ошибку. Сделать например флажок YDB_SDK_ENABLE_OTEL_METRICS. Можешь посмотреть как это у userver выглядит, у них каждый компонент можно включать и выключать: https://github.com/userver-framework/userver/blob/59e4c01531f478a3eac245379a3b1395475ec139/CMakeLists.txt#L145-L170 |
||
| endif() | ||
|
Comment on lines
+16
to
+19
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. opentelemetry -- опциональная зависимость |
||
|
|
||
| # RapidJSON | ||
| if (YDB_SDK_USE_RAPID_JSON) | ||
|
|
||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. может быть, на файлы разбить?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Как-то намешано все тут. И про метрики, и про спаны |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| #pragma once | ||
|
|
||
| #include <ydb-cpp-sdk/client/extension_common/extension.h> | ||
|
|
||
| #include <map> | ||
| #include <memory> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| namespace NYdb::inline V3::NMetrics { | ||
|
|
||
| using TLabels = std::map<std::string, std::string>; | ||
|
|
||
| class ICounter { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Маловато мне кажется. Не помню точно, но вроде SDK сейчас использует более широкий список видов метрик. Я уже делал подход по поддержке otel для метрик: https://github.com/ydb-platform/ydb-cpp-sdk/pull/552/changes#diff-f1460d2c3384a36a259dbc2d72809cb435960a695af99471b058811239323a60 Можешь посмотреть, что там было. И посмотри, какие сейчас метрики SDK уже собирает. Нам все равно их переводить придется. |
||
| public: | ||
| virtual ~ICounter() = default; | ||
| virtual void Inc() = 0; | ||
| }; | ||
|
|
||
| class IGauge { | ||
| public: | ||
| virtual ~IGauge() = default; | ||
| virtual void Add(double delta) = 0; | ||
| virtual void Set(double value) = 0; | ||
| }; | ||
|
|
||
| class IHistogram { | ||
| public: | ||
| virtual ~IHistogram() = default; | ||
| virtual void Record(double value) = 0; | ||
| }; | ||
|
|
||
| class IMetricRegistry { | ||
| public: | ||
| virtual ~IMetricRegistry() = default; | ||
|
|
||
| virtual std::shared_ptr<ICounter> Counter(const std::string& name, const TLabels& labels = {}) = 0; | ||
| virtual std::shared_ptr<IGauge> Gauge(const std::string& name, const TLabels& labels = {}) = 0; | ||
| virtual std::shared_ptr<IHistogram> Histogram(const std::string& name, const std::vector<double>& buckets, const TLabels& labels = {}) = 0; | ||
| }; | ||
|
|
||
| enum class ESpanKind { | ||
| INTERNAL, | ||
| SERVER, | ||
| CLIENT, | ||
| PRODUCER, | ||
| CONSUMER | ||
| }; | ||
|
|
||
| class ISpan { | ||
| public: | ||
| virtual ~ISpan() = default; | ||
| virtual void End() = 0; | ||
| virtual void SetAttribute(const std::string& key, const std::string& value) = 0; | ||
| virtual void SetAttribute(const std::string& key, int64_t value) = 0; | ||
| }; | ||
|
|
||
| class ITracer { | ||
| public: | ||
| virtual ~ITracer() = default; | ||
| virtual std::shared_ptr<ISpan> StartSpan(const std::string& name, ESpanKind kind = ESpanKind::INTERNAL) = 0; | ||
| }; | ||
|
|
||
| class ITraceProvider { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А зачем нам и ITracer и ITraceProvider? Нельзя сделать, чтобы ITraceProvider напрямую спаны создавал?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Про трейсы кстати тоже есть PR, от другого студента, который не доделал. Можно доже посмотреть: https://github.com/ydb-platform/ydb-cpp-sdk/pull/517/changes Но за код не ручаюсь, там все может быть и неправильно спроектировано, так что смотреть с большим скепсисом. |
||
| public: | ||
| virtual ~ITraceProvider() = default; | ||
| virtual std::shared_ptr<ITracer> GetTracer(const std::string& name) = 0; | ||
| }; | ||
|
|
||
| class IMetricsApi : public IExtensionApi { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IExtensionApi - большое зло. Не очень удачное решение, которое плотно так засело в SDK. Давайте закопаем его. Мне кажется, пользователю будет гораздо удобнее, если экспортер метрик и трейсов будут прям в TDriverConfig задаваться. Типа NYdb::TDriver driver(TDriverConfig("grpc://localhost:2136/local")
.SetMetricExporter(CreateOtelMetricExporter(...))
.SetTraceExporter(CreateOtelTraceExporter(...))
);
...Лаконично и понятно пользователю. |
||
| public: | ||
| static IMetricsApi* Create(TDriver driver); | ||
| public: | ||
| virtual ~IMetricsApi() = default; | ||
| virtual void SetMetricRegistry(std::shared_ptr<IMetricRegistry> registry) = 0; | ||
| virtual void SetTraceProvider(std::shared_ptr<ITraceProvider> provider) = 0; | ||
| virtual std::shared_ptr<IMetricRegistry> GetMetricRegistry() const = 0; | ||
| virtual std::shared_ptr<ITraceProvider> GetTraceProvider() const = 0; | ||
| }; | ||
|
|
||
| } // namespace NYdb::NMetrics | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А может разделим? Тащить и метрики и трейсы сразу как-то странно, все же разные сущности. Вдруг трейсы пользователю не нужны? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| _ydb_sdk_add_library(open_telemetry) | ||
|
|
||
| target_sources(open_telemetry PRIVATE | ||
| src/otel.cpp | ||
| ) | ||
|
|
||
| target_include_directories(open_telemetry PUBLIC | ||
| $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> | ||
| $<INSTALL_INTERFACE:include> | ||
| ) | ||
|
|
||
| target_link_libraries(open_telemetry PUBLIC | ||
| client-metrics | ||
| opentelemetry-cpp::api | ||
| opentelemetry-cpp::metrics | ||
| opentelemetry-cpp::trace | ||
| ) | ||
|
|
||
| _ydb_sdk_make_client_component(OpenTelemetry open_telemetry) | ||
| _ydb_sdk_install_headers(${CMAKE_INSTALL_INCLUDEDIR} DIRECTORY include/) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #pragma once | ||
|
|
||
| #include <ydb-cpp-sdk/open_telemetry/otel.h> | ||
| #include <ydb-cpp-sdk/client/extension_common/extension.h> | ||
|
|
||
| namespace NYdb::inline V3::NMetrics { | ||
|
|
||
| class TOtelExtension : public IExtension { | ||
| public: | ||
| using IApi = IMetricsApi; | ||
|
|
||
| struct TParams { | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::metrics::MeterProvider> MeterProvider; | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> TracerProvider; | ||
| }; | ||
|
|
||
| TOtelExtension(const TParams& params, IApi* api) { | ||
| if (params.MeterProvider) { | ||
| api->SetMetricRegistry(std::make_shared<TOtelMetricRegistry>(params.MeterProvider)); | ||
| } | ||
| if (params.TracerProvider) { | ||
| api->SetTraceProvider(std::make_shared<TOtelTraceProvider>(params.TracerProvider)); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| inline void AddOpenTelemetry(TDriver& driver | ||
| , opentelemetry::nostd::shared_ptr<opentelemetry::metrics::MeterProvider> meterProvider | ||
| , opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> tracerProvider | ||
| ) { | ||
| driver.AddExtension<TOtelExtension>({meterProvider, tracerProvider}); | ||
| } | ||
|
|
||
| } // namespace NYdb::NMetrics |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #pragma once | ||
|
|
||
| #include <ydb-cpp-sdk/client/metrics/metrics.h> | ||
|
|
||
| #include <opentelemetry/metrics/meter_provider.h> | ||
| #include <opentelemetry/trace/tracer_provider.h> | ||
|
|
||
| namespace NYdb::inline V3::NMetrics { | ||
|
|
||
| class TOtelMetricRegistry : public IMetricRegistry { | ||
| public: | ||
| TOtelMetricRegistry(opentelemetry::nostd::shared_ptr<opentelemetry::metrics::MeterProvider> meterProvider); | ||
|
|
||
| std::shared_ptr<ICounter> Counter(const std::string& name, const TLabels& labels = {}) override; | ||
| std::shared_ptr<IGauge> Gauge(const std::string& name, const TLabels& labels = {}) override; | ||
| std::shared_ptr<IHistogram> Histogram(const std::string& name, const std::vector<double>& buckets, const TLabels& labels = {}) override; | ||
|
|
||
| private: | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::metrics::MeterProvider> MeterProvider_; | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Meter> Meter_; | ||
| }; | ||
|
|
||
| class TOtelTraceProvider : public ITraceProvider { | ||
| public: | ||
| TOtelTraceProvider(opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> tracerProvider); | ||
|
|
||
| std::shared_ptr<ITracer> GetTracer(const std::string& name) override; | ||
|
|
||
| private: | ||
| opentelemetry::nostd::shared_ptr<opentelemetry::trace::TracerProvider> TracerProvider_; | ||
| }; | ||
|
|
||
| } // namespace NYdb::NMetrics |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| #include <ydb-cpp-sdk/open_telemetry/otel.h> | ||
|
|
||
| #include <opentelemetry/metrics/meter.h> | ||
| #include <opentelemetry/metrics/sync_instruments.h> | ||
| #include <opentelemetry/common/key_value_iterable_view.h> | ||
| #include <opentelemetry/trace/tracer.h> | ||
| #include <opentelemetry/context/runtime_context.h> | ||
|
|
||
| namespace NYdb::inline V3::NMetrics { | ||
|
|
||
| namespace { | ||
|
|
||
| using namespace opentelemetry; | ||
|
|
||
| common::KeyValueIterableView<TLabels> MakeAttributes(const TLabels& labels) { | ||
| return common::KeyValueIterableView<TLabels>(labels); | ||
| } | ||
|
|
||
| class TOtelCounter : public ICounter { | ||
| public: | ||
| TOtelCounter(nostd::shared_ptr<metrics::Counter<uint64_t>> counter, const TLabels& labels) | ||
| : Counter_(std::move(counter)) | ||
| , Labels_(labels) | ||
| {} | ||
|
|
||
| void Inc() override { | ||
| Counter_->Add(1, MakeAttributes(Labels_), context::RuntimeContext::GetCurrent()); | ||
| } | ||
|
|
||
| private: | ||
| nostd::shared_ptr<metrics::Counter<uint64_t>> Counter_; | ||
| TLabels Labels_; | ||
| }; | ||
|
|
||
| class TOtelUpDownCounterGauge : public IGauge { | ||
| public: | ||
| TOtelUpDownCounterGauge(nostd::shared_ptr<metrics::UpDownCounter<double>> counter, const TLabels& labels) | ||
| : Counter_(std::move(counter)) | ||
| , Labels_(labels) | ||
| {} | ||
|
|
||
| void Add(double delta) override { | ||
| Counter_->Add(delta, MakeAttributes(Labels_), context::RuntimeContext::GetCurrent()); | ||
| Value_ += delta; | ||
| } | ||
|
|
||
| void Set(double value) override { | ||
| Counter_->Add(value - Value_, MakeAttributes(Labels_), context::RuntimeContext::GetCurrent()); | ||
| Value_ = value; | ||
| } | ||
|
|
||
| private: | ||
| nostd::shared_ptr<metrics::UpDownCounter<double>> Counter_; | ||
| TLabels Labels_; | ||
| double Value_ = 0; | ||
| }; | ||
|
|
||
| class TOtelHistogram : public IHistogram { | ||
| public: | ||
| TOtelHistogram(nostd::shared_ptr<metrics::Histogram<double>> histogram, const TLabels& labels) | ||
| : Histogram_(std::move(histogram)) | ||
| , Labels_(labels) | ||
| {} | ||
|
|
||
| void Record(double value) override { | ||
| Histogram_->Record(value, MakeAttributes(Labels_), context::RuntimeContext::GetCurrent()); | ||
| } | ||
|
|
||
| private: | ||
| nostd::shared_ptr<metrics::Histogram<double>> Histogram_; | ||
| TLabels Labels_; | ||
| }; | ||
|
|
||
| trace::SpanKind MapSpanKind(ESpanKind kind) { | ||
| switch (kind) { | ||
| case ESpanKind::INTERNAL: return trace::SpanKind::kInternal; | ||
| case ESpanKind::SERVER: return trace::SpanKind::kServer; | ||
| case ESpanKind::CLIENT: return trace::SpanKind::kClient; | ||
| case ESpanKind::PRODUCER: return trace::SpanKind::kProducer; | ||
| case ESpanKind::CONSUMER: return trace::SpanKind::kConsumer; | ||
| } | ||
| return trace::SpanKind::kInternal; | ||
| } | ||
|
|
||
| class TOtelSpan : public ISpan { | ||
| public: | ||
| TOtelSpan(nostd::shared_ptr<trace::Span> span) | ||
| : Span_(std::move(span)) | ||
| {} | ||
|
|
||
| void End() override { | ||
| Span_->End(); | ||
| } | ||
|
|
||
| void SetAttribute(const std::string& key, const std::string& value) override { | ||
| Span_->SetAttribute(key, value); | ||
| } | ||
|
|
||
| void SetAttribute(const std::string& key, int64_t value) override { | ||
| Span_->SetAttribute(key, value); | ||
| } | ||
|
|
||
| private: | ||
| nostd::shared_ptr<trace::Span> Span_; | ||
| }; | ||
|
|
||
| class TOtelTracer : public ITracer { | ||
| public: | ||
| TOtelTracer(nostd::shared_ptr<trace::Tracer> tracer) | ||
| : Tracer_(std::move(tracer)) | ||
| {} | ||
|
|
||
| std::shared_ptr<ISpan> StartSpan(const std::string& name, ESpanKind kind) override { | ||
| trace::StartSpanOptions options; | ||
| options.kind = MapSpanKind(kind); | ||
| return std::make_shared<TOtelSpan>(Tracer_->StartSpan(name, options)); | ||
| } | ||
|
|
||
| private: | ||
| nostd::shared_ptr<trace::Tracer> Tracer_; | ||
| }; | ||
|
|
||
| } // namespace | ||
|
|
||
| TOtelMetricRegistry::TOtelMetricRegistry(nostd::shared_ptr<metrics::MeterProvider> meterProvider) | ||
| : MeterProvider_(std::move(meterProvider)) | ||
| , Meter_(MeterProvider_->GetMeter("ydb-cpp-sdk", "1.0.0")) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Почему 1.0.0? У ydb-cpp-sdk есть версия, в SLO тестах даже проставляем на meter: https://github.com/ydb-platform/ydb-cpp-sdk/blob/main/tests/slo_workloads/utils/metrics.cpp#L53 |
||
| {} | ||
|
|
||
| std::shared_ptr<ICounter> TOtelMetricRegistry::Counter(const std::string& name, const TLabels& labels) { | ||
| auto counter = Meter_->CreateUInt64Counter(name); | ||
| return std::make_shared<TOtelCounter>(std::move(counter), labels); | ||
| } | ||
|
|
||
| std::shared_ptr<IGauge> TOtelMetricRegistry::Gauge(const std::string& name, const TLabels& labels) { | ||
| auto counter = Meter_->CreateDoubleUpDownCounter(name); | ||
| return std::make_shared<TOtelUpDownCounterGauge>(std::move(counter), labels); | ||
| } | ||
|
|
||
| std::shared_ptr<IHistogram> TOtelMetricRegistry::Histogram(const std::string& name, const std::vector<double>& buckets, const TLabels& labels) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. buckets потеряли |
||
| auto histogram = Meter_->CreateDoubleHistogram(name); | ||
| return std::make_shared<TOtelHistogram>(std::move(histogram), labels); | ||
| } | ||
|
|
||
| TOtelTraceProvider::TOtelTraceProvider(nostd::shared_ptr<trace::TracerProvider> tracerProvider) | ||
| : TracerProvider_(std::move(tracerProvider)) | ||
| {} | ||
|
|
||
| std::shared_ptr<ITracer> TOtelTraceProvider::GetTracer(const std::string& name) { | ||
| return std::make_shared<TOtelTracer>(TracerProvider_->GetTracer(name)); | ||
| } | ||
|
|
||
| } // namespace NYdb::NMetrics | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| add_subdirectory(api) | ||
| add_subdirectory(client) | ||
| add_subdirectory(library) | ||
| add_subdirectory(library) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| _ydb_sdk_add_library(client-metrics) | ||
|
|
||
| target_sources(client-metrics PRIVATE | ||
| metrics.cpp | ||
| ) | ||
|
|
||
| target_include_directories(client-metrics PUBLIC | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А это не нужно, в _ydb_sdk_add_library уже должен проставляться target_include_directories |
||
| $<BUILD_INTERFACE:${YDB_SDK_SOURCE_DIR}/include> | ||
| $<INSTALL_INTERFACE:include> | ||
| ) | ||
|
|
||
| target_link_libraries(client-metrics PUBLIC | ||
| client-extension_common | ||
| ) | ||
|
|
||
| _ydb_sdk_make_client_component(Metrics client-metrics) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
не будет собираться если на него не сошлются