Skip to content

feat(storage): enable App-Centric Observability (ACO) support in Otel#13248

Open
nidhiii-27 wants to merge 1 commit into
mainfrom
aco
Open

feat(storage): enable App-Centric Observability (ACO) support in Otel#13248
nidhiii-27 wants to merge 1 commit into
mainfrom
aco

Conversation

@nidhiii-27
Copy link
Copy Markdown
Contributor

Adding support for App-Centric Observability (ACO) by ensuring GCS spans include the required id and location resource attributes: gcp.resource.destination.id and gcp.resource.destination.location

  • Implemented AcoSpanBuilder and AcoSpan to intercept setAttribute("gsutil.uri", ...), startSpan and endSpan calls
  • Added a package-private BucketMetadataCache using a bounded LinkedHashMap (10,000 entries) to manage bucket-to-location mappings with low memory overhead
  • Triggered asynchronous GetBucket metadata resolution on cache misses using a dedicated ThreadPoolExecutor
  • Managing cache eviction or fallback attributes in case of 404/403

Validated via OtelStorageDecoratorAcoUnitTest and integration tests (ITOpenTelemetryTest, ITOpenTelemetryMPUTest)

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a bucket metadata caching mechanism to enrich OpenTelemetry spans with destination resource IDs and locations. It adds AcoSpan and AcoSpanBuilder for span lifecycle management, a BucketMetadataCache for storage, and background fetching logic in OtelStorageDecorator. Reviewer feedback includes using constants for attribute keys, optimizing GCS API calls by selecting specific fields, and reducing the executor shutdown timeout to improve closing efficiency.

Comment on lines +41 to +42
delegate.setAttribute("gcp.resource.destination.id", md.resource);
delegate.setAttribute("gcp.resource.destination.location", md.location);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When defining attribute keys, prefer using constants to avoid typos. However, ensure that gcp.client.artifact and gcp.client.version remain as hardcoded strings, as corresponding constants are not available in ObservabilityAttributes. Also, avoid using static final for constants that may need instance-level configuration in the future.

References
  1. Avoid declaring constants as 'static final' if there is a plan to expose or configure them at the instance level in the future.
  2. The attribute key gcp.client.artifact should be defined using a hardcoded string as a corresponding constant is not available in ObservabilityAttributes.
  3. The attribute key gcp.client.version should be defined using a hardcoded string as a corresponding constant is not available in ObservabilityAttributes.

}

static Tuple<String, String> fetch(Storage delegate, String bucketName) {
Bucket bucket = delegate.get(bucketName);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve efficiency and reduce the amount of data transferred from the GCS API, consider using Storage.BucketGetOption.fields(...) to only fetch the necessary fields (LOCATION, LOCATION_TYPE, and PROJECT).

Suggested change
Bucket bucket = delegate.get(bucketName);
Bucket bucket = delegate.get(bucketName, Storage.BucketGetOption.fields(Storage.BucketField.LOCATION, Storage.BucketField.LOCATION_TYPE, Storage.BucketField.PROJECT));

synchronized (this) {
if (cacheExecutor != null) {
cacheExecutor.shutdownNow();
cacheExecutor.awaitTermination(5, TimeUnit.MINUTES);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The 5-minute timeout for awaitTermination is excessively long for background observability tasks. A shorter timeout (e.g., 5-10 seconds) would be more appropriate. Additionally, ensure that cacheExecutor is a bounded thread pool and, if it is a global static utility, avoid closing it in a way that affects other active sessions.

Suggested change
cacheExecutor.awaitTermination(5, TimeUnit.MINUTES);
cacheExecutor.awaitTermination(5, TimeUnit.SECONDS);
References
  1. In global static utilities shared across multiple concurrent sessions, avoid state changes (such as closing or removing shared handlers) triggered by a single session's configuration if those changes would negatively affect other active sessions.
  2. For safety, use a bounded thread pool (e.g., ThreadPoolExecutor with a defined maximum size) instead of an unbounded one (e.g., Executors.newCachedThreadPool()), even if the current logic seems to limit concurrent tasks.

@nidhiii-27 nidhiii-27 marked this pull request as ready for review May 21, 2026 09:09
@nidhiii-27 nidhiii-27 requested review from a team as code owners May 21, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant