diff --git a/google/cloud/storage/internal/async/open_object.cc b/google/cloud/storage/internal/async/open_object.cc index 1f3b87d805e3f..49642f4ecf554 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() { +#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(); rpc_->Start().then([w = WeakFromThis()](auto f) { if (auto self = w.lock()) self->OnStart(f.get()); @@ -63,6 +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()); @@ -70,6 +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()); @@ -78,6 +120,32 @@ 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}}); + } +#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..18e9f4c3b7d8c 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_; +#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_; + opentelemetry::nostd::shared_ptr span_; +#endif }; GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END