diff --git a/google/cloud/bigtable/internal/grpc_metrics_exporter.cc b/google/cloud/bigtable/internal/grpc_metrics_exporter.cc index 214f3da6e6211..647f93e4e582d 100644 --- a/google/cloud/bigtable/internal/grpc_metrics_exporter.cc +++ b/google/cloud/bigtable/internal/grpc_metrics_exporter.cc @@ -289,15 +289,11 @@ MonitoredResourceResult MakeMonitoredResource( return MonitoredResourceResult{std::move(project_id), std::move(resource)}; } -void EnableGrpcMetrics( +GrpcMetricsPluginConfig MakeGrpcMetricsPluginConfig( + // NOLINTNEXTLINE(performance-unnecessary-value-param) + opentelemetry::sdk::resource::Resource detected_resource, std::shared_ptr const& conn, Options const& options, std::string const& client_uid) { - auto authority = options.get(); - if (!GrpcMetricsExporterRegistry::Singleton().Register(authority)) return; - - auto detector = otel::MakeResourceDetector(); - auto detected_resource = detector->Detect(); - auto dynamic_resource_fn = [options, client_uid, detected_resource = std::move(detected_resource)]( opentelemetry::sdk::metrics::PointDataAttributes const& pda) { @@ -357,7 +353,7 @@ void EnableGrpcMetrics( auto provider = MakeGrpcMeterProvider(std::move(exporter), std::move(reader_options)); - auto const metrics = std::vector{ + auto metrics = std::vector{ std::string_view{"grpc.client.attempt.duration"}, std::string_view{"grpc.lb.rls.default_target_picks"}, std::string_view{"grpc.lb.rls.target_picks"}, @@ -370,13 +366,14 @@ void EnableGrpcMetrics( std::string_view{"grpc.subchannel.open_connections"}, }; - auto const disable_metrics = std::vector{ + auto disable_metrics = std::vector{ std::string_view{ "grpc.client.attempt.sent_total_compressed_message_size"}, std::string_view{ "grpc.client.attempt.rcvd_total_compressed_message_size"}, }; + auto authority = options.get(); auto scope_filter = [authority = std::move(authority)]( grpc::OpenTelemetryPluginBuilder::ChannelScope const& scope) { @@ -386,15 +383,41 @@ void EnableGrpcMetrics( << " vs expected authority=" << authority; return scope.default_authority() == authority; }; + + auto generic_method_filter = [](std::string_view target) { + return absl::StartsWith(target, "google.bigtable.v2"); + }; + + return GrpcMetricsPluginConfig{ + std::move(provider), std::move(metrics), + std::move(disable_metrics), std::move(generic_method_filter), + std::move(scope_filter), + }; +} + +GrpcMetricsPluginConfig MakeGrpcMetricsPluginConfig( + std::shared_ptr const& conn, + Options const& options, std::string const& client_uid) { + auto detector = otel::MakeResourceDetector(); + return MakeGrpcMetricsPluginConfig(detector->Detect(), conn, options, + client_uid); +} + +void EnableGrpcMetrics( + std::shared_ptr const& conn, + Options const& options, std::string const& client_uid) { + auto const& authority = options.get(); + if (!GrpcMetricsExporterRegistry::Singleton().Register(authority)) return; + + auto config = MakeGrpcMetricsPluginConfig(conn, options, client_uid); auto status = grpc::OpenTelemetryPluginBuilder() - .SetMeterProvider(provider) - .EnableMetrics(metrics) - .DisableMetrics(disable_metrics) - .SetGenericMethodAttributeFilter([](std::string_view target) { - return absl::StartsWith(target, "google.bigtable.v2"); - }) - .SetChannelScopeFilter(std::move(scope_filter)) + .SetMeterProvider(config.meter_provider) + .EnableMetrics(config.enabled_metrics) + .DisableMetrics(config.disabled_metrics) + .SetGenericMethodAttributeFilter( + std::move(config.generic_method_filter)) + .SetChannelScopeFilter(std::move(config.channel_scope_filter)) .BuildAndRegisterGlobal(); if (!status.ok()) { GCP_LOG(ERROR) << "Cannot register provider status=" << status.ToString(); diff --git a/google/cloud/bigtable/internal/grpc_metrics_exporter.h b/google/cloud/bigtable/internal/grpc_metrics_exporter.h index 8ab268b7c2fb1..433679fb6b600 100644 --- a/google/cloud/bigtable/internal/grpc_metrics_exporter.h +++ b/google/cloud/bigtable/internal/grpc_metrics_exporter.h @@ -25,11 +25,14 @@ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_GRPC_OTEL_METRICS #include "google/cloud/monitoring/v3/metric_connection.h" #include "google/api/monitored_resource.pb.h" +#include #include #include #include #include #include +#include +#include #include #endif // GOOGLE_CLOUD_CPP_BIGTABLE_WITH_GRPC_OTEL_METRICS @@ -95,6 +98,24 @@ std::shared_ptr MakeGrpcMeterProvider( opentelemetry::sdk::metrics::PeriodicExportingMetricReaderOptions reader_options); +struct GrpcMetricsPluginConfig { + std::shared_ptr meter_provider; + std::vector enabled_metrics; + std::vector disabled_metrics; + std::function generic_method_filter; + std::function + channel_scope_filter; +}; + +GrpcMetricsPluginConfig MakeGrpcMetricsPluginConfig( + opentelemetry::sdk::resource::Resource detected_resource, + std::shared_ptr const& conn, + Options const& options, std::string const& client_uid); + +GrpcMetricsPluginConfig MakeGrpcMetricsPluginConfig( + std::shared_ptr const& conn, + Options const& options, std::string const& client_uid); + void EnableGrpcMetrics( std::shared_ptr const& conn, Options const& options, std::string const& client_uid); diff --git a/google/cloud/bigtable/internal/grpc_metrics_exporter_test.cc b/google/cloud/bigtable/internal/grpc_metrics_exporter_test.cc index b4452d66c751e..259c0da66ea72 100644 --- a/google/cloud/bigtable/internal/grpc_metrics_exporter_test.cc +++ b/google/cloud/bigtable/internal/grpc_metrics_exporter_test.cc @@ -19,6 +19,7 @@ #include "google/cloud/bigtable/version.h" #include "google/cloud/grpc_options.h" #include "google/cloud/options.h" +#include #include #include #include @@ -57,6 +58,7 @@ using ::testing::Ge; using ::testing::IsEmpty; using ::testing::Le; using ::testing::Not; +using ::testing::NotNull; using ::testing::ResultOf; using ::testing::Return; using ::testing::SizeIs; @@ -161,6 +163,19 @@ auto TestReaderOptions() { return reader_options; } +class DummyEndpointConfig + : public grpc_event_engine::experimental::EndpointConfig { + public: + ~DummyEndpointConfig() override = default; + std::optional GetInt(absl::string_view) const override { + return std::nullopt; + } + std::optional GetString(absl::string_view) const override { + return std::nullopt; + } + void* GetVoidPointer(absl::string_view) const override { return nullptr; } +}; + class DummyMetricServiceConnection : public monitoring_v3::MetricServiceConnection { public: @@ -393,6 +408,57 @@ TEST(GrpcMetricsExporterTest, ValidateGrpcClientAttemptDuration) { } } +TEST(GrpcMetricsExporterTest, ValidatePluginConfigArguments) { + Options options; + options.set("custom-bigtable-authority.googleapis.com"); + options.set("test-app-profile"); + options.set(std::chrono::seconds(60)); + auto conn = std::make_shared(); + std::string const client_uid = "test-client-uid"; + + auto config = MakeGrpcMetricsPluginConfig(conn, options, client_uid); + + EXPECT_THAT(config.meter_provider, NotNull()); + + EXPECT_THAT( + config.enabled_metrics, + ElementsAre("grpc.client.attempt.duration", + "grpc.lb.rls.default_target_picks", + "grpc.lb.rls.target_picks", "grpc.lb.rls.failed_picks", + "grpc.xds_client.server_failure", + "grpc.xds_client.resource_updates_invalid", + "grpc.subchannel.disconnections", + "grpc.subchannel.connection_attempts_succeeded", + "grpc.subchannel.connection_attempts_failed", + "grpc.subchannel.open_connections")); + + EXPECT_THAT( + config.disabled_metrics, + ElementsAre("grpc.client.attempt.sent_total_compressed_message_size", + "grpc.client.attempt.rcvd_total_compressed_message_size")); + + ASSERT_TRUE(config.generic_method_filter); + EXPECT_TRUE( + config.generic_method_filter("google.bigtable.v2.Bigtable/ReadRows")); + EXPECT_TRUE( + config.generic_method_filter("google.bigtable.v2.Bigtable/MutateRow")); + EXPECT_FALSE( + config.generic_method_filter("google.storage.v2.Storage/ReadObject")); + EXPECT_FALSE( + config.generic_method_filter("google.spanner.v1.Spanner/ExecuteSql")); + EXPECT_FALSE(config.generic_method_filter("")); + + ASSERT_TRUE(config.channel_scope_filter); + DummyEndpointConfig endpoint_config; + grpc::OpenTelemetryPluginBuilder::ChannelScope matching_scope( + "custom-target", "custom-bigtable-authority.googleapis.com", + endpoint_config); + grpc::OpenTelemetryPluginBuilder::ChannelScope non_matching_scope( + "custom-target", "other-authority.googleapis.com", endpoint_config); + EXPECT_TRUE(config.channel_scope_filter(matching_scope)); + EXPECT_FALSE(config.channel_scope_filter(non_matching_scope)); +} + } // namespace GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable_internal