Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion google/cloud/bigtable/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ add_library(
internal/bulk_mutator.h
internal/channel_usage.h
internal/client_options_defaults.h
internal/client_schema_metrics.cc
internal/client_schema_metrics.h
internal/common_client.h
internal/connection_refresh_state.cc
internal/connection_refresh_state.h
Expand Down Expand Up @@ -465,6 +467,7 @@ if (BUILD_TESTING)
internal/bigtable_stub_factory_test.cc
internal/bulk_mutator_test.cc
internal/channel_usage_test.cc
internal/client_schema_metrics_test.cc
internal/connection_refresh_state_test.cc
internal/convert_policies_test.cc
internal/crc32c_test.cc
Expand All @@ -476,7 +479,6 @@ if (BUILD_TESTING)
internal/google_bytes_traits_test.cc
internal/grpc_metrics_exporter_test.cc
internal/logging_result_set_reader_test.cc
internal/metrics_test.cc
internal/mutate_rows_limiter_test.cc
internal/operation_context_factory_test.cc
internal/operation_context_test.cc
Expand Down
2 changes: 1 addition & 1 deletion google/cloud/bigtable/bigtable_client_unit_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ bigtable_client_unit_tests = [
"internal/bigtable_stub_factory_test.cc",
"internal/bulk_mutator_test.cc",
"internal/channel_usage_test.cc",
"internal/client_schema_metrics_test.cc",
"internal/connection_refresh_state_test.cc",
"internal/convert_policies_test.cc",
"internal/crc32c_test.cc",
Expand All @@ -57,7 +58,6 @@ bigtable_client_unit_tests = [
"internal/google_bytes_traits_test.cc",
"internal/grpc_metrics_exporter_test.cc",
"internal/logging_result_set_reader_test.cc",
"internal/metrics_test.cc",
"internal/mutate_rows_limiter_test.cc",
"internal/operation_context_factory_test.cc",
"internal/operation_context_test.cc",
Expand Down
2 changes: 2 additions & 0 deletions google/cloud/bigtable/google_cloud_cpp_bigtable.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ google_cloud_cpp_bigtable_hdrs = [
"internal/bulk_mutator.h",
"internal/channel_usage.h",
"internal/client_options_defaults.h",
"internal/client_schema_metrics.h",
"internal/common_client.h",
"internal/connection_refresh_state.h",
"internal/const_buffer.h",
Expand Down Expand Up @@ -199,6 +200,7 @@ google_cloud_cpp_bigtable_srcs = [
"internal/bigtable_stub_factory.cc",
"internal/bigtable_tracing_stub.cc",
"internal/bulk_mutator.cc",
"internal/client_schema_metrics.cc",
"internal/connection_refresh_state.cc",
"internal/const_buffer.cc",
"internal/convert_policies.cc",
Expand Down
185 changes: 185 additions & 0 deletions google/cloud/bigtable/internal/client_schema_metrics.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS

#include "google/cloud/bigtable/internal/client_schema_metrics.h"
#include "google/cloud/bigtable/internal/data_connection_impl.h"
#include "google/cloud/bigtable/options.h"
#include "google/cloud/bigtable/version.h"
#include <opentelemetry/metrics/meter.h>
#include <opentelemetry/semconv/incubating/cloud_attributes.h>
#include <opentelemetry/semconv/incubating/faas_attributes.h>
#include <opentelemetry/semconv/incubating/host_attributes.h>
#include <algorithm>
#include <map>
#include <set>
#include <string_view>

namespace google {
namespace cloud {
namespace bigtable_internal {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace {
auto constexpr kMeterInstrumentationScopeVersion = "v1";

std::string_view ToString(ChannelPoolLbPolicy policy) {
switch (policy) {
case ChannelPoolLbPolicy::kRoundRobin:
return "ROUND_ROBIN";
case ChannelPoolLbPolicy::kRandomTwoLeastUsed:
return "RANDOM_TWO_LEAST_USED";
}
return "ROUND_ROBIN";
}

std::string_view ToString(TransportType type) {
switch (type) {
case TransportType::kCloudPath:
return "CloudPath";
case TransportType::kDirectPath:
return "DirectPath";
}
return "CloudPath";
}

std::string_view IsStreamingAsString(RpcType type) {
switch (type) {
case RpcType::kStreaming:
return "true";
case RpcType::kUnary:
return "false";
}
return "false";
}
} // namespace

LabelMap IntoLabelMap(ClientResourceLabels const& r,
ClientOutstandingRpcLabels const& d,
std::set<std::string> const& filtered_data_labels) {
LabelMap labels = {
{"project_id", r.project_id}, {"instance", r.instance},
{"app_profile", r.app_profile}, {"client_name", r.client_name},
{"client_uid", r.client_uid}, {"client_project", r.client_project},
{"location", r.location}, {"cloud_platform", r.cloud_platform},
{"host_id", r.host_id}, {"hostname", r.hostname}};

struct {
std::string key;
std::string value;
} data[] = {
{"transport_type", std::string(ToString(d.transport_type))},
{"channel_pool_lb_policy",
std::string(ToString(d.channel_pool_lb_policy))},
{"streaming", std::string(IsStreamingAsString(d.streaming))},
};

for (auto& item : data) {
if (filtered_data_labels.find(item.key) == filtered_data_labels.end()) {
labels.emplace(std::move(item.key), std::move(item.value));
}
}

return labels;
}

ClientResourceLabels MakeClientResourceLabels(
std::string project_id, std::string instance, std::string app_profile,
Options const& options, std::string const& client_uid,
opentelemetry::sdk::resource::Resource const& detected_resource) {
namespace sc = ::opentelemetry::semconv;
auto const& detected_attributes = detected_resource.GetAttributes();
auto by_name = [&](std::string const& name, std::string default_value = {}) {
auto const l = detected_attributes.find(name);
if (l == detected_attributes.end() ||
!opentelemetry::nostd::holds_alternative<std::string>(l->second)) {
return default_value;
}
return opentelemetry::nostd::get<std::string>(l->second);
};

if (project_id.empty() &&
options.has<bigtable_internal::InstanceChannelAffinityOption>()) {
auto const& instances =
options.get<bigtable_internal::InstanceChannelAffinityOption>();
if (!instances.empty()) {
project_id = instances[0].project_id();
}
}
if (project_id.empty()) {
project_id = by_name(sc::cloud::kCloudAccountId);
}

std::string client_project = by_name(sc::cloud::kCloudAccountId);
if (client_project.empty()) {
client_project = project_id;
}

ClientResourceLabels labels;
labels.project_id = std::move(project_id);
labels.instance = std::move(instance);
labels.app_profile = std::move(app_profile);
labels.client_name = "cpp.Bigtable/" + bigtable::version_string();
labels.client_uid = client_uid;
labels.client_project = std::move(client_project);
labels.location = by_name(sc::cloud::kCloudAvailabilityZone);
if (labels.location.empty()) {
labels.location = by_name(sc::cloud::kCloudRegion, "global");
}
labels.cloud_platform = by_name(sc::cloud::kCloudPlatform, "unknown");
labels.host_id = by_name("faas.id");
if (labels.host_id.empty()) {
labels.host_id = by_name(sc::host::kHostId, "unknown");
}
labels.hostname = by_name(sc::host::kHostName);
return labels;
}

OutstandingRpcs::OutstandingRpcs(
std::string const& instrumentation_scope,
opentelemetry::nostd::shared_ptr<
opentelemetry::metrics::MeterProvider> const& provider)
: outstanding_rpcs_(
provider
->GetMeter(instrumentation_scope,
kMeterInstrumentationScopeVersion)
->CreateDoubleHistogram(
"connection_pool/outstanding_rpcs",
"Instantaneous count of outstanding RPCs on the selected "
"channel.",
"1")) {}

void OutstandingRpcs::StubSelection(
opentelemetry::context::Context const& context,
StubSelectionParams const& p) {
ClientOutstandingRpcLabels data_labels{p.transport_type,
p.channel_pool_lb_policy, p.streaming};
outstanding_rpcs_->Record(static_cast<double>(p.outstanding_rpcs),
IntoLabelMap(resource_labels_, data_labels),
context);
}

std::unique_ptr<ClientSchemaMetric> OutstandingRpcs::clone(
ClientResourceLabels const& resource_labels) const {
auto m = std::make_unique<OutstandingRpcs>(*this);
m->resource_labels_ = resource_labels;
return m;
}

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace bigtable_internal
} // namespace cloud
} // namespace google

#endif // GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
94 changes: 94 additions & 0 deletions google/cloud/bigtable/internal/client_schema_metrics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_CLIENT_SCHEMA_METRICS_H
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_CLIENT_SCHEMA_METRICS_H

#ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS

#include "google/cloud/bigtable/internal/metrics.h"
#include "google/cloud/options.h"
#include <opentelemetry/metrics/meter_provider.h>
#include <opentelemetry/metrics/sync_instruments.h>
#include <opentelemetry/sdk/resource/resource.h>
#include <memory>
#include <set>
#include <string>
#include <unordered_map>

namespace google {
namespace cloud {
namespace bigtable_internal {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN

struct ClientResourceLabels {
std::string project_id;
std::string instance;
std::string app_profile;
std::string client_name;
std::string client_uid;
std::string client_project;
std::string location;
std::string cloud_platform;
std::string host_id;
std::string hostname;
};

struct ClientOutstandingRpcLabels {
TransportType transport_type;
ChannelPoolLbPolicy channel_pool_lb_policy;
RpcType streaming;
};

using LabelMap = std::unordered_map<std::string, std::string>;
LabelMap IntoLabelMap(ClientResourceLabels const& r,
ClientOutstandingRpcLabels const& d,
std::set<std::string> const& filtered_data_labels = {});

ClientResourceLabels MakeClientResourceLabels(
std::string project_id, std::string instance, std::string app_profile,
Options const& options, std::string const& client_uid,
opentelemetry::sdk::resource::Resource const& detected_resource);

class ClientSchemaMetric : public Metric {
public:
MetricSchema schema() const final { return MetricSchema::kClient; }
virtual std::unique_ptr<ClientSchemaMetric> clone(
ClientResourceLabels const& resource_labels) const = 0;
};

class OutstandingRpcs : public ClientSchemaMetric {
public:
OutstandingRpcs(std::string const& instrumentation_scope,
opentelemetry::nostd::shared_ptr<
opentelemetry::metrics::MeterProvider> const& provider);
void StubSelection(opentelemetry::context::Context const&,
StubSelectionParams const& p) override;
std::unique_ptr<ClientSchemaMetric> clone(
ClientResourceLabels const& resource_labels) const override;

private:
ClientResourceLabels resource_labels_;
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<double>>
outstanding_rpcs_;
};

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace bigtable_internal
} // namespace cloud
} // namespace google

#endif // GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS

#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_INTERNAL_CLIENT_SCHEMA_METRICS_H
Loading
Loading