From d54ed9f378bee49ec9b34029393f62e13dc666c3 Mon Sep 17 00:00:00 2001 From: Gauri Kalra Date: Tue, 4 Aug 2026 10:23:47 +0000 Subject: [PATCH 1/6] feat(storage): add stream open latency metrics and trace annotations --- .../storage/internal/async/open_object.cc | 64 +++++++++++++++++++ .../storage/internal/async/open_object.h | 7 ++ 2 files changed, 71 insertions(+) diff --git a/google/cloud/storage/internal/async/open_object.cc b/google/cloud/storage/internal/async/open_object.cc index 1f3b87d805e3f..4f5aefd6b3ba6 100644 --- a/google/cloud/storage/internal/async/open_object.cc +++ b/google/cloud/storage/internal/async/open_object.cc @@ -15,6 +15,10 @@ #include "google/cloud/storage/internal/async/open_object.h" #include "google/cloud/internal/make_status.h" #include "absl/strings/str_cat.h" +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +#include "google/cloud/internal/opentelemetry.h" +#include +#endif #include namespace google { @@ -40,7 +44,39 @@ OpenObject::OpenObject(storage_internal::StorageStub& stub, CompletionQueue& cq, stub, cq, std::move(context), std::move(options), request))), initial_request_(std::move(request)) {} +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +struct StreamOpenMetrics { + opentelemetry::nostd::shared_ptr> + stream_open_latency; + opentelemetry::nostd::shared_ptr> + network_handshake; + opentelemetry::nostd::shared_ptr> + server_metadata_latency; + + static StreamOpenMetrics const& Instance() { + static auto const metrics = [] { + auto meter = + opentelemetry::metrics::Provider::GetMeterProvider()->GetMeter( + "storage", "v1"); + return StreamOpenMetrics{ + meter->CreateDoubleHistogram("gl-cpp.latency.stream_open", + "End-to-End Stream Open", "us"), + meter->CreateDoubleHistogram("gl-cpp.latency.network_handshake", + "Network Handshake", "us"), + meter->CreateDoubleHistogram("gl-cpp.latency.server_metadata", + "Server Metadata Latency", "us"), + }; + }(); + return metrics; + } +}; +#endif + future> OpenObject::Call() { + t0_ = std::chrono::steady_clock::now(); +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + span_ = opentelemetry::trace::Tracer::GetCurrentSpan(); +#endif auto future = promise_.get_future(); rpc_->Start().then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnStart(f.get()); @@ -63,6 +99,7 @@ std::unique_ptr OpenObject::CreateRpc( } void OpenObject::OnStart(bool ok) { + t1_ = std::chrono::steady_clock::now(); if (!ok) return DoFinish(); rpc_->Write(initial_request_).then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnWrite(f.get()); @@ -70,6 +107,7 @@ void OpenObject::OnStart(bool ok) { } void OpenObject::OnWrite(bool ok) { + t2_ = std::chrono::steady_clock::now(); if (!ok) return DoFinish(); rpc_->Read().then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnRead(f.get()); @@ -78,6 +116,32 @@ void OpenObject::OnWrite(bool ok) { void OpenObject::OnRead( std::optional response) { + auto t3 = std::chrono::steady_clock::now(); +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + auto const& metrics = StreamOpenMetrics::Instance(); + + auto p1 = static_cast( + std::chrono::duration_cast(t1_ - t0_).count()); + auto p2 = static_cast( + std::chrono::duration_cast(t3 - t2_).count()); + auto p3 = static_cast( + std::chrono::duration_cast(t3 - t0_).count()); + + auto bucket = initial_request_.read_object_spec().bucket(); + metrics.network_handshake->Record(p1, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); + metrics.server_metadata_latency->Record(p2, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); + metrics.stream_open_latency->Record(p3, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); + + if (span_ && span_->GetContext().IsValid()) { + span_->AddEvent("gl-cpp.open.read", + {{"gl-cpp.latency.network_handshake", p1}, + {"gl-cpp.latency.server_metadata", p2}, + {"gl-cpp.latency.stream_open", p3}}); + } +#endif if (!response) return DoFinish(); promise_.set_value(OpenStreamResult{std::move(rpc_), std::move(*response)}); } diff --git a/google/cloud/storage/internal/async/open_object.h b/google/cloud/storage/internal/async/open_object.h index 65f01dba4024c..36bd10df1a6c2 100644 --- a/google/cloud/storage/internal/async/open_object.h +++ b/google/cloud/storage/internal/async/open_object.h @@ -25,6 +25,7 @@ #include "google/cloud/version.h" #include "google/storage/v2/storage.pb.h" #include +#include #include #include @@ -107,6 +108,12 @@ class OpenObject : public std::enable_shared_from_this { std::shared_ptr rpc_; promise> promise_; google::storage::v2::BidiReadObjectRequest initial_request_; + std::chrono::steady_clock::time_point t0_; + std::chrono::steady_clock::time_point t1_; + std::chrono::steady_clock::time_point t2_; +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + opentelemetry::nostd::shared_ptr span_; +#endif }; GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END From 73bfe502477db8e162408178cec32d2e27870c9c Mon Sep 17 00:00:00 2001 From: Gauri Kalra Date: Tue, 4 Aug 2026 11:28:56 +0000 Subject: [PATCH 2/6] Address feedback from code assistant --- google/cloud/storage/internal/async/open_object.cc | 8 ++++++-- google/cloud/storage/internal/async/open_object.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/google/cloud/storage/internal/async/open_object.cc b/google/cloud/storage/internal/async/open_object.cc index 4f5aefd6b3ba6..49642f4ecf554 100644 --- a/google/cloud/storage/internal/async/open_object.cc +++ b/google/cloud/storage/internal/async/open_object.cc @@ -73,8 +73,8 @@ struct StreamOpenMetrics { #endif future> OpenObject::Call() { - t0_ = std::chrono::steady_clock::now(); #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + t0_ = std::chrono::steady_clock::now(); span_ = opentelemetry::trace::Tracer::GetCurrentSpan(); #endif auto future = promise_.get_future(); @@ -99,7 +99,9 @@ std::unique_ptr OpenObject::CreateRpc( } void OpenObject::OnStart(bool ok) { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS t1_ = std::chrono::steady_clock::now(); +#endif if (!ok) return DoFinish(); rpc_->Write(initial_request_).then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnWrite(f.get()); @@ -107,7 +109,9 @@ void OpenObject::OnStart(bool ok) { } void OpenObject::OnWrite(bool ok) { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS t2_ = std::chrono::steady_clock::now(); +#endif if (!ok) return DoFinish(); rpc_->Read().then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnRead(f.get()); @@ -116,8 +120,8 @@ void OpenObject::OnWrite(bool ok) { void OpenObject::OnRead( std::optional response) { - auto t3 = std::chrono::steady_clock::now(); #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + auto t3 = std::chrono::steady_clock::now(); auto const& metrics = StreamOpenMetrics::Instance(); auto p1 = static_cast( diff --git a/google/cloud/storage/internal/async/open_object.h b/google/cloud/storage/internal/async/open_object.h index 36bd10df1a6c2..18e9f4c3b7d8c 100644 --- a/google/cloud/storage/internal/async/open_object.h +++ b/google/cloud/storage/internal/async/open_object.h @@ -108,10 +108,10 @@ class OpenObject : public std::enable_shared_from_this { std::shared_ptr rpc_; promise> promise_; google::storage::v2::BidiReadObjectRequest initial_request_; +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS std::chrono::steady_clock::time_point t0_; std::chrono::steady_clock::time_point t1_; std::chrono::steady_clock::time_point t2_; -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS opentelemetry::nostd::shared_ptr span_; #endif }; From 68e279208dee7addda1c3fffcc5398396dfee951 Mon Sep 17 00:00:00 2001 From: Gauri Kalra Date: Thu, 6 Aug 2026 07:23:13 +0000 Subject: [PATCH 3/6] Address reviewer feedback about using a dedicated class for metrics --- .../storage/google_cloud_cpp_storage_grpc.bzl | 2 + .../google_cloud_cpp_storage_grpc.cmake | 2 + .../storage/internal/async/open_object.cc | 70 ++------- .../storage/internal/async/open_object.h | 7 +- .../internal/async/open_object_metrics.cc | 133 ++++++++++++++++++ .../internal/async/open_object_metrics.h | 61 ++++++++ 6 files changed, 210 insertions(+), 65 deletions(-) create mode 100644 google/cloud/storage/internal/async/open_object_metrics.cc create mode 100644 google/cloud/storage/internal/async/open_object_metrics.h diff --git a/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl b/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl index ad210011ea06f..69269f44fde53 100644 --- a/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl +++ b/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl @@ -50,6 +50,7 @@ google_cloud_cpp_storage_grpc_hdrs = [ "internal/async/object_descriptor_reader.h", "internal/async/object_descriptor_reader_tracing.h", "internal/async/open_object.h", + "internal/async/open_object_metrics.h", "internal/async/open_stream.h", "internal/async/partial_upload.h", "internal/async/read_payload_fwd.h", @@ -128,6 +129,7 @@ google_cloud_cpp_storage_grpc_srcs = [ "internal/async/object_descriptor_reader.cc", "internal/async/object_descriptor_reader_tracing.cc", "internal/async/open_object.cc", + "internal/async/open_object_metrics.cc", "internal/async/open_stream.cc", "internal/async/partial_upload.cc", "internal/async/read_range.cc", diff --git a/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake b/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake index 952d6dbef46d2..8d72e82151e26 100644 --- a/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake +++ b/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake @@ -123,6 +123,8 @@ add_library( internal/async/object_descriptor_reader_tracing.h internal/async/open_object.cc internal/async/open_object.h + internal/async/open_object_metrics.cc + internal/async/open_object_metrics.h internal/async/open_stream.cc internal/async/open_stream.h internal/async/partial_upload.cc diff --git a/google/cloud/storage/internal/async/open_object.cc b/google/cloud/storage/internal/async/open_object.cc index 49642f4ecf554..da59bc6f8a628 100644 --- a/google/cloud/storage/internal/async/open_object.cc +++ b/google/cloud/storage/internal/async/open_object.cc @@ -44,37 +44,9 @@ OpenObject::OpenObject(storage_internal::StorageStub& stub, CompletionQueue& cq, stub, cq, std::move(context), std::move(options), request))), initial_request_(std::move(request)) {} -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS -struct StreamOpenMetrics { - opentelemetry::nostd::shared_ptr> - stream_open_latency; - opentelemetry::nostd::shared_ptr> - network_handshake; - opentelemetry::nostd::shared_ptr> - server_metadata_latency; - - static StreamOpenMetrics const& Instance() { - static auto const metrics = [] { - auto meter = - opentelemetry::metrics::Provider::GetMeterProvider()->GetMeter( - "storage", "v1"); - return StreamOpenMetrics{ - meter->CreateDoubleHistogram("gl-cpp.latency.stream_open", - "End-to-End Stream Open", "us"), - meter->CreateDoubleHistogram("gl-cpp.latency.network_handshake", - "Network Handshake", "us"), - meter->CreateDoubleHistogram("gl-cpp.latency.server_metadata", - "Server Metadata Latency", "us"), - }; - }(); - return metrics; - } -}; -#endif - future> OpenObject::Call() { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS - t0_ = std::chrono::steady_clock::now(); + metrics_.RecordCall(); +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY span_ = opentelemetry::trace::Tracer::GetCurrentSpan(); #endif auto future = promise_.get_future(); @@ -99,9 +71,7 @@ std::unique_ptr OpenObject::CreateRpc( } void OpenObject::OnStart(bool ok) { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS - t1_ = std::chrono::steady_clock::now(); -#endif + metrics_.RecordStart(); if (!ok) return DoFinish(); rpc_->Write(initial_request_).then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnWrite(f.get()); @@ -109,9 +79,7 @@ void OpenObject::OnStart(bool ok) { } void OpenObject::OnWrite(bool ok) { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS - t2_ = std::chrono::steady_clock::now(); -#endif + metrics_.RecordWrite(); if (!ok) return DoFinish(); rpc_->Read().then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnRead(f.get()); @@ -120,32 +88,12 @@ void OpenObject::OnWrite(bool ok) { void OpenObject::OnRead( std::optional response) { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS - auto t3 = std::chrono::steady_clock::now(); - auto const& metrics = StreamOpenMetrics::Instance(); - - auto p1 = static_cast( - std::chrono::duration_cast(t1_ - t0_).count()); - auto p2 = static_cast( - std::chrono::duration_cast(t3 - t2_).count()); - auto p3 = static_cast( - std::chrono::duration_cast(t3 - t0_).count()); - - auto bucket = initial_request_.read_object_spec().bucket(); - metrics.network_handshake->Record(p1, {{"gcp.storage.bucket", bucket}}, - opentelemetry::context::Context{}); - metrics.server_metadata_latency->Record(p2, {{"gcp.storage.bucket", bucket}}, - opentelemetry::context::Context{}); - metrics.stream_open_latency->Record(p3, {{"gcp.storage.bucket", bucket}}, - opentelemetry::context::Context{}); - - if (span_ && span_->GetContext().IsValid()) { - span_->AddEvent("gl-cpp.open.read", - {{"gl-cpp.latency.network_handshake", p1}, - {"gl-cpp.latency.server_metadata", p2}, - {"gl-cpp.latency.stream_open", p3}}); - } +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY + metrics_.RecordRead(initial_request_.read_object_spec().bucket(), span_); +#else + metrics_.RecordRead(initial_request_.read_object_spec().bucket()); #endif + if (!response) return DoFinish(); promise_.set_value(OpenStreamResult{std::move(rpc_), std::move(*response)}); } diff --git a/google/cloud/storage/internal/async/open_object.h b/google/cloud/storage/internal/async/open_object.h index 18e9f4c3b7d8c..5a980619d887b 100644 --- a/google/cloud/storage/internal/async/open_object.h +++ b/google/cloud/storage/internal/async/open_object.h @@ -15,6 +15,7 @@ #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_H #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_H +#include "google/cloud/storage/internal/async/open_object_metrics.h" #include "google/cloud/storage/internal/async/open_stream.h" #include "google/cloud/storage/internal/storage_stub.h" #include "google/cloud/completion_queue.h" @@ -108,12 +109,10 @@ class OpenObject : public std::enable_shared_from_this { std::shared_ptr rpc_; promise> promise_; google::storage::v2::BidiReadObjectRequest initial_request_; -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS - std::chrono::steady_clock::time_point t0_; - std::chrono::steady_clock::time_point t1_; - std::chrono::steady_clock::time_point t2_; +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY opentelemetry::nostd::shared_ptr span_; #endif + OpenObjectMetrics metrics_; }; GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END diff --git a/google/cloud/storage/internal/async/open_object_metrics.cc b/google/cloud/storage/internal/async/open_object_metrics.cc new file mode 100644 index 0000000000000..7a8d7f5c7eed1 --- /dev/null +++ b/google/cloud/storage/internal/async/open_object_metrics.cc @@ -0,0 +1,133 @@ +// Copyright 2024 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. + +#include "google/cloud/storage/internal/async/open_object_metrics.h" + +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +#include +#endif + +namespace google { +namespace cloud { +namespace storage_internal { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +namespace { +struct StreamOpenMetrics { + opentelemetry::nostd::shared_ptr> + network_handshake; + opentelemetry::nostd::shared_ptr> + server_metadata_latency; + opentelemetry::nostd::shared_ptr> + stream_open_latency; + + static StreamOpenMetrics const& Instance() { + static auto const metrics = [] { + auto meter = + opentelemetry::metrics::Provider::GetMeterProvider()->GetMeter( + "storage", "v1"); + return StreamOpenMetrics{ + meter->CreateDoubleHistogram("gl-cpp.latency.network_handshake", + "Network Handshake", "us"), + meter->CreateDoubleHistogram("gl-cpp.latency.server_metadata", + "Server Metadata Latency", "us"), + meter->CreateDoubleHistogram("gl-cpp.latency.stream_open", + "End-to-End Stream Open", "us")}; + }(); + return metrics; + } +}; +} // namespace +#endif + +void OpenObjectMetrics::RecordCall() { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + t0_ = std::chrono::steady_clock::now(); +#endif +} + +void OpenObjectMetrics::RecordStart() { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + t1_ = std::chrono::steady_clock::now(); +#endif +} + +void OpenObjectMetrics::RecordWrite() { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + t2_ = std::chrono::steady_clock::now(); +#endif +} + +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +void OpenObjectMetrics::RecordMetrics( + std::string const& bucket, std::chrono::steady_clock::time_point t3) { + auto const& metrics = StreamOpenMetrics::Instance(); + auto p1 = static_cast( + std::chrono::duration_cast(t1_ - t0_).count()); + auto p2 = static_cast( + std::chrono::duration_cast(t3 - t2_).count()); + auto p3 = static_cast( + std::chrono::duration_cast(t3 - t0_).count()); + + metrics.network_handshake->Record(p1, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); + metrics.server_metadata_latency->Record(p2, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); + metrics.stream_open_latency->Record(p3, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); +} +#endif + +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY +void OpenObjectMetrics::RecordRead( + std::string const& bucket, + opentelemetry::nostd::shared_ptr const& span) { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + auto t3 = std::chrono::steady_clock::now(); + RecordMetrics(bucket, t3); + if (span && span->GetContext().IsValid()) { + auto p1 = static_cast( + std::chrono::duration_cast(t1_ - t0_) + .count()); + auto p2 = static_cast( + std::chrono::duration_cast(t3 - t2_) + .count()); + auto p3 = static_cast( + std::chrono::duration_cast(t3 - t0_) + .count()); + span->AddEvent("gl-cpp.stream_open.latency", + {{"gl-cpp.latency.network_handshake", p1}, + {"gl-cpp.latency.server_metadata", p2}, + {"gl-cpp.latency.stream_open", p3}}); + } +#else + (void)bucket; + (void)span; +#endif +} +#else +void OpenObjectMetrics::RecordRead(std::string const& bucket) { +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + RecordMetrics(bucket, std::chrono::steady_clock::now()); +#else + (void)bucket; +#endif +} +#endif + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace storage_internal +} // namespace cloud +} // namespace google diff --git a/google/cloud/storage/internal/async/open_object_metrics.h b/google/cloud/storage/internal/async/open_object_metrics.h new file mode 100644 index 0000000000000..56d5bb79b0b74 --- /dev/null +++ b/google/cloud/storage/internal/async/open_object_metrics.h @@ -0,0 +1,61 @@ +// Copyright 2024 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_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_METRICS_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_METRICS_H + +#include "google/cloud/version.h" +#include +#include + +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY +#include +#endif + +namespace google { +namespace cloud { +namespace storage_internal { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +class OpenObjectMetrics { + public: + void RecordCall(); + void RecordStart(); + void RecordWrite(); + +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY + void RecordRead( + std::string const& bucket, + opentelemetry::nostd::shared_ptr const& span); +#else + void RecordRead(std::string const& bucket); +#endif + + private: +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + void RecordMetrics(std::string const& bucket, + std::chrono::steady_clock::time_point t3); + + std::chrono::steady_clock::time_point t0_; + std::chrono::steady_clock::time_point t1_; + std::chrono::steady_clock::time_point t2_; +#endif +}; + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace storage_internal +} // namespace cloud +} // namespace google + +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_METRICS_H From e3106e4466285de69bcdebfb5b52cd8ac965545c Mon Sep 17 00:00:00 2001 From: Gauri Kalra Date: Thu, 6 Aug 2026 08:40:21 +0000 Subject: [PATCH 4/6] Address feedback about decoupling tracing from metrics --- .../internal/async/open_object_metrics.cc | 19 +++++++++++-------- .../internal/async/open_object_metrics.h | 3 +++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/google/cloud/storage/internal/async/open_object_metrics.cc b/google/cloud/storage/internal/async/open_object_metrics.cc index 7a8d7f5c7eed1..3f989d9684cce 100644 --- a/google/cloud/storage/internal/async/open_object_metrics.cc +++ b/google/cloud/storage/internal/async/open_object_metrics.cc @@ -53,19 +53,22 @@ struct StreamOpenMetrics { #endif void OpenObjectMetrics::RecordCall() { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +#if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ + defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) t0_ = std::chrono::steady_clock::now(); #endif } void OpenObjectMetrics::RecordStart() { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +#if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ + defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) t1_ = std::chrono::steady_clock::now(); #endif } void OpenObjectMetrics::RecordWrite() { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +#if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ + defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) t2_ = std::chrono::steady_clock::now(); #endif } @@ -94,9 +97,13 @@ void OpenObjectMetrics::RecordMetrics( void OpenObjectMetrics::RecordRead( std::string const& bucket, opentelemetry::nostd::shared_ptr const& span) { -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS auto t3 = std::chrono::steady_clock::now(); +#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS RecordMetrics(bucket, t3); +#else + (void)bucket; +#endif + if (span && span->GetContext().IsValid()) { auto p1 = static_cast( std::chrono::duration_cast(t1_ - t0_) @@ -112,10 +119,6 @@ void OpenObjectMetrics::RecordRead( {"gl-cpp.latency.server_metadata", p2}, {"gl-cpp.latency.stream_open", p3}}); } -#else - (void)bucket; - (void)span; -#endif } #else void OpenObjectMetrics::RecordRead(std::string const& bucket) { diff --git a/google/cloud/storage/internal/async/open_object_metrics.h b/google/cloud/storage/internal/async/open_object_metrics.h index 56d5bb79b0b74..1d516e31318ed 100644 --- a/google/cloud/storage/internal/async/open_object_metrics.h +++ b/google/cloud/storage/internal/async/open_object_metrics.h @@ -46,7 +46,10 @@ class OpenObjectMetrics { #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS void RecordMetrics(std::string const& bucket, std::chrono::steady_clock::time_point t3); +#endif +#if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ + defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) std::chrono::steady_clock::time_point t0_; std::chrono::steady_clock::time_point t1_; std::chrono::steady_clock::time_point t2_; From 10aa1fb70d7a85b82dd62a0c0d298f953dca0c5d Mon Sep 17 00:00:00 2001 From: Gauri Kalra Date: Mon, 10 Aug 2026 06:26:00 +0000 Subject: [PATCH 5/6] Address reviewer feedback --- .../storage/google_cloud_cpp_storage_grpc.bzl | 4 +- .../google_cloud_cpp_storage_grpc.cmake | 15 ++- .../storage/internal/async/open_object.cc | 3 +- .../storage/internal/async/open_object.h | 4 +- ...ct_metrics.cc => open_object_telemetry.cc} | 30 ++--- ...ject_metrics.h => open_object_telemetry.h} | 10 +- .../internal/async/open_object_test.cc | 108 ++++++++++++++++++ 7 files changed, 147 insertions(+), 27 deletions(-) rename google/cloud/storage/internal/async/{open_object_metrics.cc => open_object_telemetry.cc} (82%) rename google/cloud/storage/internal/async/{open_object_metrics.h => open_object_telemetry.h} (93%) diff --git a/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl b/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl index 69269f44fde53..13841ceacfb4d 100644 --- a/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl +++ b/google/cloud/storage/google_cloud_cpp_storage_grpc.bzl @@ -50,7 +50,7 @@ google_cloud_cpp_storage_grpc_hdrs = [ "internal/async/object_descriptor_reader.h", "internal/async/object_descriptor_reader_tracing.h", "internal/async/open_object.h", - "internal/async/open_object_metrics.h", + "internal/async/open_object_telemetry.h", "internal/async/open_stream.h", "internal/async/partial_upload.h", "internal/async/read_payload_fwd.h", @@ -129,7 +129,7 @@ google_cloud_cpp_storage_grpc_srcs = [ "internal/async/object_descriptor_reader.cc", "internal/async/object_descriptor_reader_tracing.cc", "internal/async/open_object.cc", - "internal/async/open_object_metrics.cc", + "internal/async/open_object_telemetry.cc", "internal/async/open_stream.cc", "internal/async/partial_upload.cc", "internal/async/read_range.cc", diff --git a/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake b/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake index 8d72e82151e26..4e194e80a4345 100644 --- a/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake +++ b/google/cloud/storage/google_cloud_cpp_storage_grpc.cmake @@ -123,8 +123,8 @@ add_library( internal/async/object_descriptor_reader_tracing.h internal/async/open_object.cc internal/async/open_object.h - internal/async/open_object_metrics.cc - internal/async/open_object_metrics.h + internal/async/open_object_telemetry.cc + internal/async/open_object_telemetry.h internal/async/open_stream.cc internal/async/open_stream.h internal/async/partial_upload.cc @@ -245,18 +245,25 @@ target_include_directories( target_compile_options(google_cloud_cpp_storage_grpc PUBLIC ${GOOGLE_CLOUD_CPP_EXCEPTIONS_FLAG}) target_compile_definitions(google_cloud_cpp_storage_grpc - PUBLIC GOOGLE_CLOUD_CPP_STORAGE_HAVE_GRPC) + PUBLIC GOOGLE_CLOUD_CPP_STORAGE_HAVE_GRPC + GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) if (GOOGLE_CLOUD_CPP_ENABLE_CTYPE_CORD_WORKAROUND) target_compile_definitions( google_cloud_cpp_storage_grpc PRIVATE GOOGLE_CLOUD_CPP_ENABLE_CTYPE_CORD_WORKAROUND) endif () +if (GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) + target_compile_definitions( + google_cloud_cpp_storage_grpc + PRIVATE GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) +endif () if ((TARGET gRPC::grpcpp_otel_plugin) AND (TARGET google-cloud-cpp::opentelemetry) AND (TARGET opentelemetry-cpp::metrics)) target_compile_definitions( google_cloud_cpp_storage_grpc - PRIVATE GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) + PRIVATE GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS + GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) target_link_libraries( google_cloud_cpp_storage_grpc PUBLIC google-cloud-cpp::opentelemetry gRPC::grpcpp_otel_plugin diff --git a/google/cloud/storage/internal/async/open_object.cc b/google/cloud/storage/internal/async/open_object.cc index da59bc6f8a628..f1368cc41e83c 100644 --- a/google/cloud/storage/internal/async/open_object.cc +++ b/google/cloud/storage/internal/async/open_object.cc @@ -15,7 +15,8 @@ #include "google/cloud/storage/internal/async/open_object.h" #include "google/cloud/internal/make_status.h" #include "absl/strings/str_cat.h" -#ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS +#if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ + defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) #include "google/cloud/internal/opentelemetry.h" #include #endif diff --git a/google/cloud/storage/internal/async/open_object.h b/google/cloud/storage/internal/async/open_object.h index 5a980619d887b..a5002b4b11079 100644 --- a/google/cloud/storage/internal/async/open_object.h +++ b/google/cloud/storage/internal/async/open_object.h @@ -15,7 +15,7 @@ #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_H #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_H -#include "google/cloud/storage/internal/async/open_object_metrics.h" +#include "google/cloud/storage/internal/async/open_object_telemetry.h" #include "google/cloud/storage/internal/async/open_stream.h" #include "google/cloud/storage/internal/storage_stub.h" #include "google/cloud/completion_queue.h" @@ -112,7 +112,7 @@ class OpenObject : public std::enable_shared_from_this { #ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY opentelemetry::nostd::shared_ptr span_; #endif - OpenObjectMetrics metrics_; + OpenObjectTelemetry metrics_; }; GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END diff --git a/google/cloud/storage/internal/async/open_object_metrics.cc b/google/cloud/storage/internal/async/open_object_telemetry.cc similarity index 82% rename from google/cloud/storage/internal/async/open_object_metrics.cc rename to google/cloud/storage/internal/async/open_object_telemetry.cc index 3f989d9684cce..5656a328a81ab 100644 --- a/google/cloud/storage/internal/async/open_object_metrics.cc +++ b/google/cloud/storage/internal/async/open_object_telemetry.cc @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// 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. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/storage/internal/async/open_object_metrics.h" +#include "google/cloud/storage/internal/async/open_object_telemetry.h" #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS #include @@ -52,21 +52,21 @@ struct StreamOpenMetrics { } // namespace #endif -void OpenObjectMetrics::RecordCall() { +void OpenObjectTelemetry::RecordCall() { #if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) t0_ = std::chrono::steady_clock::now(); #endif } -void OpenObjectMetrics::RecordStart() { +void OpenObjectTelemetry::RecordStart() { #if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) t1_ = std::chrono::steady_clock::now(); #endif } -void OpenObjectMetrics::RecordWrite() { +void OpenObjectTelemetry::RecordWrite() { #if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) t2_ = std::chrono::steady_clock::now(); @@ -74,7 +74,7 @@ void OpenObjectMetrics::RecordWrite() { } #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS -void OpenObjectMetrics::RecordMetrics( +void OpenObjectTelemetry::RecordMetrics( std::string const& bucket, std::chrono::steady_clock::time_point t3) { auto const& metrics = StreamOpenMetrics::Instance(); auto p1 = static_cast( @@ -84,17 +84,21 @@ void OpenObjectMetrics::RecordMetrics( auto p3 = static_cast( std::chrono::duration_cast(t3 - t0_).count()); - metrics.network_handshake->Record(p1, {{"gcp.storage.bucket", bucket}}, - opentelemetry::context::Context{}); - metrics.server_metadata_latency->Record(p2, {{"gcp.storage.bucket", bucket}}, - opentelemetry::context::Context{}); - metrics.stream_open_latency->Record(p3, {{"gcp.storage.bucket", bucket}}, + if (metrics.network_handshake) + metrics.network_handshake->Record(p1, {{"gcp.storage.bucket", bucket}}, opentelemetry::context::Context{}); + if (metrics.server_metadata_latency) + metrics.server_metadata_latency->Record(p2, + {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); + if (metrics.stream_open_latency) + metrics.stream_open_latency->Record(p3, {{"gcp.storage.bucket", bucket}}, + opentelemetry::context::Context{}); } #endif #ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY -void OpenObjectMetrics::RecordRead( +void OpenObjectTelemetry::RecordRead( std::string const& bucket, opentelemetry::nostd::shared_ptr const& span) { auto t3 = std::chrono::steady_clock::now(); @@ -121,7 +125,7 @@ void OpenObjectMetrics::RecordRead( } } #else -void OpenObjectMetrics::RecordRead(std::string const& bucket) { +void OpenObjectTelemetry::RecordRead(std::string const& bucket) { #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS RecordMetrics(bucket, std::chrono::steady_clock::now()); #else diff --git a/google/cloud/storage/internal/async/open_object_metrics.h b/google/cloud/storage/internal/async/open_object_telemetry.h similarity index 93% rename from google/cloud/storage/internal/async/open_object_metrics.h rename to google/cloud/storage/internal/async/open_object_telemetry.h index 1d516e31318ed..943c1843d1bfd 100644 --- a/google/cloud/storage/internal/async/open_object_metrics.h +++ b/google/cloud/storage/internal/async/open_object_telemetry.h @@ -1,4 +1,4 @@ -// Copyright 2024 Google LLC +// 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. @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_METRICS_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_METRICS_H +#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_TELEMETRY_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_TELEMETRY_H #include "google/cloud/version.h" #include @@ -28,7 +28,7 @@ namespace cloud { namespace storage_internal { GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -class OpenObjectMetrics { +class OpenObjectTelemetry { public: void RecordCall(); void RecordStart(); @@ -61,4 +61,4 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace cloud } // namespace google -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_METRICS_H +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_OPEN_OBJECT_TELEMETRY_H diff --git a/google/cloud/storage/internal/async/open_object_test.cc b/google/cloud/storage/internal/async/open_object_test.cc index 265cfdfd5ad9e..81959a62dbe1d 100644 --- a/google/cloud/storage/internal/async/open_object_test.cc +++ b/google/cloud/storage/internal/async/open_object_test.cc @@ -24,6 +24,12 @@ #include #include +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY +#include "google/cloud/internal/opentelemetry.h" +#include "google/cloud/opentelemetry_options.h" +#include "google/cloud/testing_util/opentelemetry_matchers.h" +#endif + namespace google { namespace cloud { namespace storage_internal { @@ -43,6 +49,17 @@ using ::testing::Field; using ::testing::NotNull; using ::testing::Pair; +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY +using ::google::cloud::testing_util::EventNamed; +using ::google::cloud::testing_util::InstallSpanCatcher; +using ::google::cloud::testing_util::OTelAttribute; +using ::google::cloud::testing_util::SpanEventAttributesAre; +using ::google::cloud::testing_util::SpanHasEvents; +using ::google::cloud::testing_util::SpanNamed; +using ::testing::_; +using ::testing::ElementsAre; +#endif + using MockStream = google::cloud::mocks::MockAsyncStreamingReadWriteRpc< google::storage::v2::BidiReadObjectRequest, google::storage::v2::BidiReadObjectResponse>; @@ -155,6 +172,97 @@ TEST(OpenImpl, Basic) { ASSERT_THAT(response, IsOkAndHolds(expected_result())); } +#ifdef GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY +TEST(OpenImpl, StreamOpenLatencySpanEvent) { + auto span_catcher = InstallSpanCatcher(); + auto options = internal::MakeImmutableOptions( + Options{}.set(true)); + internal::OptionsSpan options_span(options); + + auto span = internal::MakeSpan("test-open-span"); + opentelemetry::trace::Scope scope(span); + + auto constexpr kText = R"pb( + bucket: "projects/_/buckets/test-bucket" + object: "test-object" + generation: 42 + )pb"; + auto constexpr kReadResponse = R"pb( + metadata { + bucket: "projects/_/buckets/test-bucket" + name: "test-object" + generation: 42 + } + read_handle { handle: "handle-123" } + )pb"; + + auto request = google::storage::v2::BidiReadObjectRequest{}; + ASSERT_TRUE( + TextFormat::ParseFromString(kText, request.mutable_read_object_spec())); + auto expected_response = google::storage::v2::BidiReadObjectResponse{}; + ASSERT_TRUE(TextFormat::ParseFromString(kReadResponse, &expected_response)); + + AsyncSequencer sequencer; + MockStorageStub mock; + EXPECT_CALL(mock, AsyncBidiReadObject) + .WillOnce([&](CompletionQueue const&, + std::shared_ptr const&, + google::cloud::internal::ImmutableOptions const&) { + auto stream = std::make_unique(); + EXPECT_CALL(*stream, Start).WillOnce([&sequencer]() { + return sequencer.PushBack("Start").then( + [](auto f) { return f.get(); }); + }); + EXPECT_CALL(*stream, Write) + .WillOnce( + [&sequencer](google::storage::v2::BidiReadObjectRequest const&, + grpc::WriteOptions) { + return sequencer.PushBack("Write").then( + [](auto f) { return f.get(); }); + }); + EXPECT_CALL(*stream, Read).WillOnce([&sequencer, expected_response]() { + return sequencer.PushBack("Read").then([expected_response](auto) { + return std::make_optional(expected_response); + }); + }); + return std::unique_ptr(std::move(stream)); + }); + + CompletionQueue cq; + auto coro = std::make_shared( + mock, cq, std::make_shared(), + internal::MakeImmutableOptions({}), request); + auto pending = coro->Call(); + auto next = sequencer.PopFrontWithName(); + EXPECT_EQ(next.second, "Start"); + next.first.set_value(true); + next = sequencer.PopFrontWithName(); + EXPECT_EQ(next.second, "Write"); + next.first.set_value(true); + next = sequencer.PopFrontWithName(); + EXPECT_EQ(next.second, "Read"); + next.first.set_value(true); + + auto response = pending.get(); + EXPECT_THAT(response, StatusIs(StatusCode::kOk)); + internal::EndSpan(*span, Status{}); + + auto spans = span_catcher->GetSpans(); + using EventMatcher = + testing::Matcher; + EXPECT_THAT( + spans, + ElementsAre(AllOf( + SpanNamed("test-open-span"), + SpanHasEvents(EventMatcher(AllOf( + EventNamed("gl-cpp.stream_open.latency"), + SpanEventAttributesAre( + OTelAttribute("gl-cpp.latency.network_handshake", _), + OTelAttribute("gl-cpp.latency.server_metadata", _), + OTelAttribute("gl-cpp.latency.stream_open", _)))))))); +} +#endif + TEST(OpenImpl, BasicReadHandle) { auto constexpr kText = R"pb( bucket: "projects/_/buckets/test-bucket" From bb25023af92113afc447d2a485c54dd1ec3a2e27 Mon Sep 17 00:00:00 2001 From: Gauri Kalra Date: Tue, 11 Aug 2026 05:21:58 +0000 Subject: [PATCH 6/6] Address feedback about uninitialized fields --- .../storage/internal/async/open_object_telemetry.cc | 10 +++++++++- .../storage/internal/async/open_object_telemetry.h | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/google/cloud/storage/internal/async/open_object_telemetry.cc b/google/cloud/storage/internal/async/open_object_telemetry.cc index 5656a328a81ab..d7a32478c7ec1 100644 --- a/google/cloud/storage/internal/async/open_object_telemetry.cc +++ b/google/cloud/storage/internal/async/open_object_telemetry.cc @@ -76,6 +76,11 @@ void OpenObjectTelemetry::RecordWrite() { #ifdef GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS void OpenObjectTelemetry::RecordMetrics( std::string const& bucket, std::chrono::steady_clock::time_point t3) { + if (t0_.time_since_epoch().count() == 0 || + t1_.time_since_epoch().count() == 0 || + t2_.time_since_epoch().count() == 0) { + return; + } auto const& metrics = StreamOpenMetrics::Instance(); auto p1 = static_cast( std::chrono::duration_cast(t1_ - t0_).count()); @@ -108,7 +113,10 @@ void OpenObjectTelemetry::RecordRead( (void)bucket; #endif - if (span && span->GetContext().IsValid()) { + if (span && span->GetContext().IsValid() && + t0_.time_since_epoch().count() > 0 && + t1_.time_since_epoch().count() > 0 && + t2_.time_since_epoch().count() > 0) { auto p1 = static_cast( std::chrono::duration_cast(t1_ - t0_) .count()); diff --git a/google/cloud/storage/internal/async/open_object_telemetry.h b/google/cloud/storage/internal/async/open_object_telemetry.h index 943c1843d1bfd..e4884da221b3a 100644 --- a/google/cloud/storage/internal/async/open_object_telemetry.h +++ b/google/cloud/storage/internal/async/open_object_telemetry.h @@ -50,9 +50,9 @@ class OpenObjectTelemetry { #if defined(GOOGLE_CLOUD_CPP_STORAGE_WITH_OTEL_METRICS) || \ defined(GOOGLE_CLOUD_CPP_HAVE_OPENTELEMETRY) - std::chrono::steady_clock::time_point t0_; - std::chrono::steady_clock::time_point t1_; - std::chrono::steady_clock::time_point t2_; + std::chrono::steady_clock::time_point t0_{}; + std::chrono::steady_clock::time_point t1_{}; + std::chrono::steady_clock::time_point t2_{}; #endif };