Experiment(secret-manager): add tracing transport logic to google-cloud-secret-manager - #18188
Conversation
There was a problem hiding this comment.
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.
916213b to
d1a7a0f
Compare
37bdd10 to
dab7994
Compare
8a121ca to
1b042a2
Compare
|
Warning
|
… 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
e6ba4ac to
e5dc180
Compare
|
|
||
|
|
||
| def test_secret_manager_service_client_otel_channel_injection_enabled(): | ||
| mock_wrapped_channel = mock.Mock() |
There was a problem hiding this comment.
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, | ||
| ) |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
I left a comment here, suggesting that we may be able to accept Callable[[Channel], Channel] here to support otel's interceptor
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
SecretManagerServiceClientand its gRPC transport.SecretManagerServiceClientto resolve OpenTelemetry interceptors usinggoogle-api-corehelpers and explicitly pass them to the transport.Notes to Reviewers
google-api-core.Fixes #18139 (partially, this is Phase 2 of the larger effort)