Skip to content

Experiment(secret-manager): add tracing transport logic to google-cloud-secret-manager - #18188

Open
chalmerlowe wants to merge 2 commits into
feat/otel-tracing-eager-channel-wrappingfrom
feat/otel-tracing-transport-logic
Open

Experiment(secret-manager): add tracing transport logic to google-cloud-secret-manager#18188
chalmerlowe wants to merge 2 commits into
feat/otel-tracing-eager-channel-wrappingfrom
feat/otel-tracing-transport-logic

Conversation

@chalmerlowe

@chalmerlowe chalmerlowe commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Problem

Client libraries currently lack built-in support for OpenTelemetry tracing interceptors. We need a flexible, explicit mechanism to inject these interceptors into the transport pipeline without tying the core low-level helpers too tightly to specific observability features.

Note

This PR is NOT intended to be merged. It is a proof-of-concept intended to inform the design and implementation of changes that need to be made in the GAPIC Generator templates.

Solution

This PR implements explicit interceptor injection in the SecretManagerServiceClient and its gRPC transport.

  • Updated SecretManagerServiceClient to resolve OpenTelemetry interceptors using google-api-core helpers and explicitly pass them to the transport.
  • Added unit tests to verify that interceptors are correctly injected and applied.

Notes to Reviewers

  • Async Deferred: As per the design plan, Async gRPC updates are deferred to a separate PR to keep this implementation small and clean.
  • Stacked PRs: This work builds on the foundational helpers introduced in the google-api-core.
  • Explicit Injection: This demonstrates the "active orchestrator" role of the generated client, delegating resolution to core helpers but explicitly controlling the pipeline.

Fixes #18139 (partially, this is Phase 2 of the larger effort)

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

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.

Code Review

This pull request introduces OpenTelemetry (OTel) tracing support by adding a helper module _otel_helpers.py to resolve and instantiate OTel gRPC interceptors, extending ClientOptions to accept a tracer_provider, and updating the Secret Manager gRPC transport to inject these interceptors. The review feedback highlights Python compatibility issues in _otel_helpers.py due to the use of the | union operator, which is unsupported in older Python versions, and suggests using typing.Union instead. Additionally, it recommends adding a defensive None check for client_options to avoid calling getattr on a None object.

Comment thread packages/google-api-core/google/api_core/_otel_helpers.py Outdated
Comment thread packages/google-api-core/google/api_core/_otel_helpers.py
Comment thread packages/google-api-core/google/api_core/_otel_helpers.py Outdated
@chalmerlowe
chalmerlowe force-pushed the feat/otel-tracing-transport-logic branch from 916213b to d1a7a0f Compare August 21, 2026 14:16
@chalmerlowe
chalmerlowe changed the base branch from main to feat/otel-tracing-api-core-logic August 21, 2026 14:18
@chalmerlowe
chalmerlowe force-pushed the feat/otel-tracing-transport-logic branch from 37bdd10 to dab7994 Compare August 24, 2026 13:03
@chalmerlowe
chalmerlowe changed the base branch from feat/otel-tracing-api-core-logic to main August 25, 2026 14:41
@chalmerlowe
chalmerlowe changed the base branch from main to feat/otel-tracing-api-core-logic August 25, 2026 14:41
@chalmerlowe
chalmerlowe force-pushed the feat/otel-tracing-transport-logic branch 2 times, most recently from 8a121ca to 1b042a2 Compare August 25, 2026 16:54
@chalmerlowe chalmerlowe added the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Aug 26, 2026
@chalmerlowe chalmerlowe self-assigned this Aug 26, 2026
@chalmerlowe
chalmerlowe marked this pull request as ready for review August 26, 2026 13:56
@chalmerlowe
chalmerlowe requested a review from a team as a code owner August 26, 2026 13:56
@chalmerlowe

Copy link
Copy Markdown
Contributor Author

Warning

Do not merge label added because this is a prototype implementation to discover the needed edits to the GAPIC generator templates. This is not intended to be merged.

Base automatically changed from feat/otel-tracing-api-core-logic to main August 26, 2026 16:56
… application

- Use _observability.create_channel_with_otel in SecretManagerServiceClient

- Use grpc_helpers.apply_interceptors in SecretManagerServiceGrpcTransport

- Add unit tests for channel injection and interceptor wiring
@chalmerlowe
chalmerlowe force-pushed the feat/otel-tracing-transport-logic branch from e6ba4ac to e5dc180 Compare August 27, 2026 17:19
@chalmerlowe
chalmerlowe changed the base branch from main to feat/otel-tracing-eager-channel-wrapping August 27, 2026 17:48


def test_secret_manager_service_client_otel_channel_injection_enabled():
mock_wrapped_channel = mock.Mock()

@chalmerlowe chalmerlowe Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Happy to fine tune the tests with fixtures, reusable mocks and/or functions, etc, but prefer to wait on going there until we get some buy-in on the overall approach in the code to avoid premature optimization.

credentials_file=self._client_options.credentials_file,
scopes=self._client_options.scopes,
quota_project_id=self._client_options.quota_project_id,
)

@daniel-sanche daniel-sanche Aug 27, 2026

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.

Do you need to modify any of these kwargs? If not, it might be best to keep this as a callable, and let the Transport pass in the rest of the channel-init arguments:

transport_kwargs["channel"] = functools.partial(
   _observability.create_channel_with_otel,
   channel_factory=SecretManagerServiceGrpcTransport.create_channel
   client_options=self._client_options
)

But this would only work if create_channel_with_otel supported passthrough positional args, along with the kwargs

if transport_init is SecretManagerServiceGrpcTransport:
if _observability.is_otel_capabilities_enabled(self._client_options):
transport_kwargs["channel"] = (
_observability.create_channel_with_otel(

@daniel-sanche daniel-sanche Aug 27, 2026

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.

A problem with this is that if anyone needs to use a custom channel (like bigtable), they lose the otel interceptors.

I was hoping there was a way that we could decouple the interceptors, instead of baking them into the channel. But it sounds like otel makes that difficult?

@daniel-sanche daniel-sanche Aug 27, 2026

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.

Here are a couple ideas on how to get around this:

A (preferred). Maybe when creating a channel, the interceptors argument could accept functions structured as Callable[[Channel], Channel], and then it can apply both styles of interceptor separately

B. If we really need to treat this otel interceptor as a special case, we could add another argument to the transport for this. Something like enable_otel, and if set, it will add the extra interceptor to whatever channel it sends up with

I haven't looked too deeply into this though, so maybe there are flaws, or maybe when we start thinking about async, that would cause even more complication

If not set, the host value will be used as a default.
interceptors (Optional[Sequence[ClientInterceptor]]):
Additional interceptors to be injected into the gRPC channel pipeline.
These are executed in order.

@daniel-sanche daniel-sanche Aug 27, 2026

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.

I left a comment here, suggesting that we may be able to accept Callable[[Channel], Channel] here to support otel's interceptor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Indicates a pull request not ready for merge, due to either quality or timing.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants