Skip to content

Commit 34e378c

Browse files
committed
feat(storage): add resource span attributes for ACO ( App Centric Observability ) for async client
1 parent 7ee3864 commit 34e378c

4 files changed

Lines changed: 109 additions & 7 deletions

File tree

google/cloud/storage/internal/async/connection_tracing.cc

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,25 @@
1414

1515
#include "google/cloud/storage/internal/async/connection_tracing.h"
1616
#include "google/cloud/storage/async/writer_connection.h"
17+
#include "google/cloud/storage/internal/async/default_options.h"
1718
#include "google/cloud/storage/internal/async/object_descriptor_connection_tracing.h"
1819
#include "google/cloud/storage/internal/async/reader_connection_tracing.h"
1920
#include "google/cloud/storage/internal/async/rewriter_connection_tracing.h"
2021
#include "google/cloud/storage/internal/async/writer_connection_tracing.h"
22+
#include "google/cloud/storage/internal/bucket_metadata_cache.h"
23+
#include "google/cloud/storage/internal/connection_factory.h"
2124
#include "google/cloud/internal/opentelemetry.h"
2225
#include "google/cloud/version.h"
26+
#include <algorithm>
27+
#include <chrono>
28+
#include <future>
2329
#include <memory>
30+
#include <mutex>
31+
#include <vector>
2432

2533
namespace google {
2634
namespace cloud {
35+
2736
namespace storage_internal {
2837
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2938

@@ -35,6 +44,12 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
3544
std::shared_ptr<storage::AsyncConnection> impl)
3645
: impl_(std::move(impl)) {}
3746

47+
~AsyncConnectionTracing() override {
48+
for (auto& f : bg_tasks_) {
49+
if (f.valid()) f.wait();
50+
}
51+
}
52+
3853
Options options() const override { return impl_->options(); }
3954

4055
future<StatusOr<google::storage::v2::Bucket>> GetBucket(
@@ -47,6 +62,8 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
4762
future<StatusOr<google::storage::v2::Object>> InsertObject(
4863
InsertObjectParams p) override {
4964
auto span = internal::MakeSpan("storage::AsyncConnection::InsertObject");
65+
EnrichSpan(*span, p.options,
66+
p.request.write_object_spec().resource().bucket());
5067
internal::OTelScope scope(span);
5168
return internal::EndSpan(std::move(span),
5269
impl_->InsertObject(std::move(p)));
@@ -55,6 +72,7 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
5572
future<StatusOr<std::shared_ptr<storage::ObjectDescriptorConnection>>> Open(
5673
OpenParams p) override {
5774
auto span = internal::MakeSpan("storage::AsyncConnection::Open");
75+
EnrichSpan(*span, p.options, p.read_spec.bucket());
5876
internal::OTelScope scope(span);
5977
return impl_->Open(std::move(p))
6078
.then([oc = opentelemetry::context::RuntimeContext::GetCurrent(),
@@ -74,6 +92,7 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
7492
future<StatusOr<std::unique_ptr<storage::AsyncReaderConnection>>> ReadObject(
7593
ReadObjectParams p) override {
7694
auto span = internal::MakeSpan("storage::AsyncConnection::ReadObject");
95+
EnrichSpan(*span, p.options, p.request.bucket());
7796
internal::OTelScope scope(span);
7897
auto wrap = [oc = opentelemetry::context::RuntimeContext::GetCurrent(),
7998
span = std::move(span)](auto f)
@@ -89,6 +108,7 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
89108
future<StatusOr<storage::ReadPayload>> ReadObjectRange(
90109
ReadObjectParams p) override {
91110
auto span = internal::MakeSpan("storage::AsyncConnection::ReadObjectRange");
111+
EnrichSpan(*span, p.options, p.request.bucket());
92112
internal::OTelScope scope(span);
93113
return impl_->ReadObjectRange(std::move(p))
94114
.then([oc = opentelemetry::context::RuntimeContext::GetCurrent(),
@@ -103,6 +123,8 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
103123
StartAppendableObjectUpload(AppendableUploadParams p) override {
104124
auto span = internal::MakeSpan(
105125
"storage::AsyncConnection::StartAppendableObjectUpload");
126+
EnrichSpan(*span, p.options,
127+
p.request.write_object_spec().resource().bucket());
106128
internal::OTelScope scope(span);
107129
return impl_->StartAppendableObjectUpload(std::move(p))
108130
.then([oc = opentelemetry::context::RuntimeContext::GetCurrent(),
@@ -119,6 +141,8 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
119141
ResumeAppendableObjectUpload(AppendableUploadParams p) override {
120142
auto span = internal::MakeSpan(
121143
"storage::AsyncConnection::ResumeAppendableObjectUpload");
144+
EnrichSpan(*span, p.options,
145+
p.request.write_object_spec().resource().bucket());
122146
internal::OTelScope scope(span);
123147
return impl_->ResumeAppendableObjectUpload(std::move(p))
124148
.then([oc = opentelemetry::context::RuntimeContext::GetCurrent(),
@@ -135,6 +159,8 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
135159
StartUnbufferedUpload(UploadParams p) override {
136160
auto span =
137161
internal::MakeSpan("storage::AsyncConnection::StartUnbufferedUpload");
162+
EnrichSpan(*span, p.options,
163+
p.request.write_object_spec().resource().bucket());
138164
internal::OTelScope scope(span);
139165
return impl_->StartUnbufferedUpload(std::move(p))
140166
.then([oc = opentelemetry::context::RuntimeContext::GetCurrent(),
@@ -151,6 +177,8 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
151177
StartBufferedUpload(UploadParams p) override {
152178
auto span =
153179
internal::MakeSpan("storage::AsyncConnection::StartBufferedUpload");
180+
EnrichSpan(*span, p.options,
181+
p.request.write_object_spec().resource().bucket());
154182
internal::OTelScope scope(span);
155183
return impl_->StartBufferedUpload(std::move(p))
156184
.then([oc = opentelemetry::context::RuntimeContext::GetCurrent(),
@@ -198,13 +226,15 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
198226
future<StatusOr<google::storage::v2::Object>> ComposeObject(
199227
ComposeObjectParams p) override {
200228
auto span = internal::MakeSpan("storage::AsyncConnection::ComposeObject");
229+
EnrichSpan(*span, p.options, p.request.destination().bucket());
201230
internal::OTelScope scope(span);
202231
return internal::EndSpan(std::move(span),
203232
impl_->ComposeObject(std::move(p)));
204233
}
205234

206235
future<Status> DeleteObject(DeleteObjectParams p) override {
207236
auto span = internal::MakeSpan("storage::AsyncConnection::DeleteObject");
237+
EnrichSpan(*span, p.options, p.request.bucket());
208238
internal::OTelScope scope(span);
209239
return internal::EndSpan(std::move(span),
210240
impl_->DeleteObject(std::move(p)));
@@ -218,7 +248,61 @@ class AsyncConnectionTracing : public storage::AsyncConnection {
218248
}
219249

220250
private:
251+
void CleanupCompletedTasks() {
252+
std::unique_lock<std::mutex> lk(mu_);
253+
bg_tasks_.erase(
254+
std::remove_if(bg_tasks_.begin(), bg_tasks_.end(),
255+
[](std::future<void> const& f) {
256+
return f.wait_for(std::chrono::seconds(0)) ==
257+
std::future_status::ready;
258+
}),
259+
bg_tasks_.end());
260+
}
261+
262+
void MaybeTriggerBackgroundFetch(Options const& options,
263+
std::string const& bucket_name) {
264+
CleanupCompletedTasks();
265+
266+
if (!BucketMetadataCache::Singleton().StartFetch(bucket_name)) {
267+
return;
268+
}
269+
270+
auto f = std::async(std::launch::async, [bucket_name, options]() {
271+
google::cloud::internal::OptionsSpan span(options);
272+
auto conn = MakeStorageConnection(options);
273+
auto const normalized =
274+
BucketMetadataCache::NormalizeBucketName(bucket_name);
275+
storage::internal::GetBucketMetadataRequest request(normalized);
276+
auto metadata = conn->GetBucketMetadata(request);
277+
if (metadata.ok()) {
278+
BucketMetadataCache::Singleton().Put(
279+
bucket_name, BucketCacheEntry::FromMetadata(*metadata));
280+
} else if (metadata.status().code() == StatusCode::kPermissionDenied) {
281+
BucketMetadataCache::Singleton().Put(
282+
bucket_name, {"projects/_/buckets/" + normalized, "global"});
283+
}
284+
BucketMetadataCache::Singleton().EndFetch(bucket_name);
285+
});
286+
287+
std::unique_lock<std::mutex> lk(mu_);
288+
bg_tasks_.push_back(std::move(f));
289+
}
290+
291+
void EnrichSpan(opentelemetry::trace::Span& span, Options const& options,
292+
std::string const& bucket_name) {
293+
if (bucket_name.empty()) return;
294+
auto entry = BucketMetadataCache::Singleton().Get(bucket_name);
295+
if (entry.has_value()) {
296+
span.SetAttribute("gcp.resource.destination.id", entry->id);
297+
span.SetAttribute("gcp.resource.destination.location", entry->location);
298+
} else {
299+
MaybeTriggerBackgroundFetch(options, bucket_name);
300+
}
301+
}
302+
221303
std::shared_ptr<storage::AsyncConnection> impl_;
304+
std::vector<std::future<void>> bg_tasks_;
305+
std::mutex mu_;
222306
};
223307

224308
} // namespace

google/cloud/storage/internal/bucket_metadata_cache.cc

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ namespace cloud {
2222
namespace storage_internal {
2323
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2424

25+
BucketMetadataCache& BucketMetadataCache::Singleton() {
26+
static BucketMetadataCache instance(10000);
27+
return instance;
28+
}
29+
2530
BucketCacheEntry BucketCacheEntry::FromMetadata(
2631
storage::BucketMetadata const& m) {
2732
std::string loc = m.location();
@@ -39,7 +44,8 @@ void BucketMetadataCache::MoveToFront(std::list<std::string>::iterator it) {
3944
}
4045

4146
absl::optional<BucketCacheEntry> BucketMetadataCache::Get(
42-
std::string const& bucket_name) {
47+
std::string const& raw_bucket_name) {
48+
auto const bucket_name = NormalizeBucketName(raw_bucket_name);
4349
std::unique_lock<std::mutex> lk(mu_);
4450
auto it = map_.find(bucket_name);
4551
if (it == map_.end()) return absl::nullopt;
@@ -48,7 +54,7 @@ absl::optional<BucketCacheEntry> BucketMetadataCache::Get(
4854
return it->second.first;
4955
}
5056

51-
void BucketMetadataCache::Put(std::string const& bucket_name,
57+
void BucketMetadataCache::Put(std::string const& raw_bucket_name,
5258
BucketCacheEntry entry) {
5359
if (max_size_ == 0) return;
5460
std::unique_lock<std::mutex> lk(mu_);
@@ -69,7 +75,8 @@ void BucketMetadataCache::Put(std::string const& bucket_name,
6975
map_[bucket_name] = {std::move(entry), list_.begin()};
7076
}
7177

72-
void BucketMetadataCache::Invalidate(std::string const& bucket_name) {
78+
void BucketMetadataCache::Invalidate(std::string const& raw_bucket_name) {
79+
auto const bucket_name = NormalizeBucketName(raw_bucket_name);
7380
std::unique_lock<std::mutex> lk(mu_);
7481
auto it = map_.find(bucket_name);
7582
if (it != map_.end()) {
@@ -84,7 +91,8 @@ void BucketMetadataCache::Clear() {
8491
list_.clear();
8592
}
8693

87-
bool BucketMetadataCache::StartFetch(std::string const& bucket_name) {
94+
bool BucketMetadataCache::StartFetch(std::string const& raw_bucket_name) {
95+
auto const bucket_name = NormalizeBucketName(raw_bucket_name);
8896
std::unique_lock<std::mutex> lk(mu_);
8997
if (in_flight_fetch_.find(bucket_name) != in_flight_fetch_.end()) {
9098
return false;
@@ -93,7 +101,8 @@ bool BucketMetadataCache::StartFetch(std::string const& bucket_name) {
93101
return true;
94102
}
95103

96-
void BucketMetadataCache::EndFetch(std::string const& bucket_name) {
104+
void BucketMetadataCache::EndFetch(std::string const& raw_bucket_name) {
105+
auto const bucket_name = NormalizeBucketName(raw_bucket_name);
97106
std::unique_lock<std::mutex> lk(mu_);
98107
in_flight_fetch_.erase(bucket_name);
99108
}

google/cloud/storage/internal/bucket_metadata_cache.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ class BucketMetadataCache {
4848
explicit BucketMetadataCache(std::size_t max_size = 10000)
4949
: max_size_(max_size) {}
5050

51+
static BucketMetadataCache& Singleton();
52+
53+
static std::string NormalizeBucketName(std::string const& bucket) {
54+
auto const prefix = std::string("projects/_/buckets/");
55+
if (bucket.rfind(prefix, 0) == 0) {
56+
return bucket.substr(prefix.size());
57+
}
58+
return bucket;
59+
}
60+
5161
absl::optional<BucketCacheEntry> Get(std::string const& bucket_name);
5262
void Put(std::string const& bucket_name, BucketCacheEntry entry);
5363
void Invalidate(std::string const& bucket_name);

google/cloud/storage/internal/tracing_connection.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ TracingConnection::~TracingConnection() {
6060
}
6161

6262
BucketMetadataCache& TracingConnection::cache() {
63-
static BucketMetadataCache instance(10000);
64-
return instance;
63+
return BucketMetadataCache::Singleton();
6564
}
6665

6766
void TracingConnection::ResetCacheForTesting() { cache().Clear(); }

0 commit comments

Comments
 (0)